해당 버그 현상은 일단 다음과 같습니다. ( JVCL347CompleteJCL241-Build4571 )
메뉴를 띄우게 되면 ( 알려진 프로그램이라서 캡션은 따로 삭제하였습니다. ) 처음에 다음과 같이 나오고,
메뉴를 마우스에 가까이 가져가면..
다음과 같이 나옵니다.
각각 확대해보면 다음과 같습니다.
다른 점을 찾으셧나요?
테두리 색상이 마우스를 갔다되면 바뀌는게 이게 의도한 것인지 버그인지는 모르겠으나 일단 저의 입장에서는 버그로 보입니다.
하이라이트 개념으로 만들었다면 다시 마우스를 메뉴바깥으로 가져갈 때 원래대로 되돌아와야 하는데 그렇지는 않구요.
처음 메뉴를 띄웠을 때 기본 테두리를 그대로 가져가면 좋겠는데 그렇지가 않아서 그렇게 수정할려고 하니까 아예 jvcl 코드자체를 수정해야 되더군요.
삽질을 방지하기 위해서 수정한 부분을 적어보면 다음과 같습니다.
아래 함수가 수정되었는데 마우스를 가져갔을 때 테두리가 그려지는 함수자체를 호출하지 않도록 하면 메뉴를 선택했을 때 하이라이트 되는 테두리가 제대로 그려지지 않아서 수정합니다.
procedure TJvXPMenuItemPainter.DrawSelectedFrame(ARect: TRect);
begin
with Canvas do
begin
Font.Color := clMenuText;
if IsPopup(FItem) then
begin
Brush.Assign(SelectionFrameBrush);
Pen.Style := psClear;
Rectangle(1, ARect.Top, ARect.Right + 4, ARect.Bottom - 1);
Pen.Assign(SelectionFramePen);
Brush.Style := bsClear;
MoveTo(1, ARect.Top);
LineTo(ARect.Right + 4, ARect.Top);
MoveTo(1, ARect.Bottom - 2);
LineTo(ARect.Right + 4, ARect.Bottom - 2);
MoveTo(1, ARect.Top);
LineTo(1, ARect.Bottom - 2);
MoveTo(ARect.Right - 1, ARect.Top);
LineTo(ARect.Right - 1, ARect.Bottom - 2);
end
else
begin
Brush.Color := clSilver;
Brush.Style := bsSolid;
Pen.Color := clGray;
Pen.Style := psSolid;
Rectangle(ARect);
end;
end;
end;
그리고 아래 부분은 마우스를 가져갔을 때 테두리가 안 그려지도록 하는 부분입니다.
procedure TJvXPMenuItemPainter.Paint(Item: TMenuItem; ItemRect: TRect;
State: TMenuOwnerDrawState);
var
CanvasWindow: HWND;
WRect: TRect;
DefProc: Pointer;
TmpDC: hDC;
begin
FItem := Item;
// draw the contour of the window
if IsPopup(Item) and not(csDesigning in ComponentState) then
begin
CanvasWindow := WindowFromDC(Canvas.Handle);
if not(Assigned(FMainMenu) and (FMainMenu.GetOwner <> nil) and
(FMainMenu.GetOwner is TForm) and
(TForm(FMainMenu.GetOwner).Handle = CanvasWindow)) then
begin
// If we have a window, that has a WndProc, which is different from our
// replacement WndProc and we are not at design time, then install
// our replacement WndProc.
// Once this is done, we can draw the border in the appropriate rect.
// Note that if the menu has sub-menus we can have multiple hooks; so we
// use TWindowList
if CanvasWindow <> 0 then
begin
GetWindowRect(CanvasWindow, WRect);
DefProc := Pointer(GetWindowLongPtr(CanvasWindow, GWL_WNDPROC));
if (DefProc <> nil) and (DefProc <> @XPMenuItemPainterWndProc) and
not(csDesigning in Menu.ComponentState) then
begin
currentXPPainter := Self;
// 현재 메뉴에 전체 보더를 그리지 않도록 수정해놨는데
// 이 부분에서 서브 메뉴에 의해서 탑 메뉴가 가려진 후 다시 나타날 때
// XPMenuItemPainterWndProc 호출되는데 간혹 이 부분에서 보더가 그려지는
// 문제가 있어서 주석처리합니다.
// WindowList.AddHook(CanvasWindow, DefProc, @XPMenuItemPainterWndProc);
end;
(* // Note: we draw the border here. But using the "Canvas" property is
// not good enough as it does not take into account the borders of the
// menu. So for version prior to Vista, be draw directly on the desktop
// window canvas. However, with desktop composition under Vista, this
// is awfully slow so we try to use the DISPLAY device context. Note
// that the behaviour on Vista has not been tested as no JVCL developper
// has access to a Vista system with the Aero them turned on.
if JclSysInfo.GetWindowsVersion = wvWinVista then
begin
TmpDC := CreateDC('DISPLAY', nil, nil, nil);
try
if not Assigned(FBorderCanvas) then
FBorderCanvas := TCanvas.Create;
FBorderCanvas.Handle := TmpDC;
DrawBorder(FBorderCanvas, WRect);
finally
DeleteDC(TmpDC);
end;
end
else *)
begin
if not Assigned(FBorderCanvas) then
FBorderCanvas := TCanvas.Create;
TmpDC := GetWindowDC(CanvasWindow);
try
FBorderCanvas.Handle := TmpDC;
// DrawBorder(FBorderCanvas, WRect);
finally
FBorderCanvas.Handle := 0;
ReleaseDC(CanvasWindow, TmpDC);
end;
end;
end;
end;
end;
// then draw the items
inherited Paint(Item, ItemRect, State);
end;
소스를 수정하고 저장한다고 해서 바로 적용되는 것은 아닙니다.
왜냐면 기본적으로 pas를 참조하는게 아니라 dcu를 참조하기 때문에 jvMenus.duc를 따로 찾아서 삭제하고 수정된 jvMenus.Pas를 참조하도록 변경해야 합니다.
전체코드는 다음과 같습니다.
'인터넷/IT > 프로그래밍' 카테고리의 다른 글
InnoSetup에서 프로그램 실행 시 창이 뒤로 가는 경우 (0) | 2014.03.09 |
---|---|
InnoSetup 사용 시 설치전 모든 페이지를 스킵 시 wpReady가 보이는 문제점 (0) | 2014.03.08 |
Overbytes ics 의 THttpCli 컴포넌트 사용 시 주의점 (0) | 2014.03.05 |
class EIcsLibeayException with message Unable to load LIBEAY32.DLL (0) | 2014.02.21 |
OpenSSL 빌드하기 ( Visual Studio 2010 ) 또는 libeay32.dll, ssleay32.dll 다운로드 (1) | 2014.02.21 |
IE9 이상으로 브라우저를 업그레이드하거나, 크롬, 파이어폭스 등 최신 브라우저를 이용해주세요.