Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2004.04.11;
Скачать: [xml.tar.bz2];

Вниз

OwnerDraw PopupMenu и его рамка   Найти похожие ветки 

 
DVM ©   (2004-03-10 18:48) [0]

Увидел ниже вопрос про меню и решил задать в чем то похожий другой.
Возможно ли как-то перекрасить рамку Popup Menu в пределах одного приложения. Дело в том что сами Item-ы меню у меня отрисовываются через OwnerDraw, а вокруг них остается серый прямоугольник. Во время отрисовки Item - а, добраться до рамки не получается, т.к. вероятно область отсечения для окна меню установлена так, что рамка меню туда не попадает.


 
DVM ©   (2004-03-10 18:48) [0]

Увидел ниже вопрос про меню и решил задать в чем то похожий другой.
Возможно ли как-то перекрасить рамку Popup Menu в пределах одного приложения. Дело в том что сами Item-ы меню у меня отрисовываются через OwnerDraw, а вокруг них остается серый прямоугольник. Во время отрисовки Item - а, добраться до рамки не получается, т.к. вероятно область отсечения для окна меню установлена так, что рамка меню туда не попадает.


 
Игорь Шевченко ©   (2004-03-10 23:16) [1]

DVM ©   (10.03.04 18:48)

Рамка представляет из себя Window Frame для окна Popup-меню, и относится к неклиентской части того самого окна с классом #32768,
которое отображается для каждого Popup-меню.

Сдается мне, что лучше имитировать Popup-меню, например, ListBox"ом и уже его рисовать, как угодно.
Это, кстати, не так трудно. Впрочем, если вдруг увидишь нарисованное без рамки Popup- или MainMenu, определи класс окна, которое отображается в момент Popup"а - самому интересно, можно ли стандартными средствами отрисовать неклиентскую часть окна меню.


 
Игорь Шевченко ©   (2004-03-10 23:16) [1]

DVM ©   (10.03.04 18:48)

Рамка представляет из себя Window Frame для окна Popup-меню, и относится к неклиентской части того самого окна с классом #32768,
которое отображается для каждого Popup-меню.

Сдается мне, что лучше имитировать Popup-меню, например, ListBox"ом и уже его рисовать, как угодно.
Это, кстати, не так трудно. Впрочем, если вдруг увидишь нарисованное без рамки Popup- или MainMenu, определи класс окна, которое отображается в момент Popup"а - самому интересно, можно ли стандартными средствами отрисовать неклиентскую часть окна меню.


 
Serge ©   (2004-03-11 09:23) [2]

> Игорь Шевченко © "...можно ли стандартными средствами отрисовать неклиентскую часть окна меню"
Вроде как можно - реализованно в компоненте XPMenu при свойстве FlatMenu = true. Если он вам Нужен (в случае если Вы его не видели) могу его переслать, скажите только куда - на почту либо в "Кладовку" (хотя по моему его я оттуда и скачивал года три назад)


 
Serge ©   (2004-03-11 09:23) [2]

> Игорь Шевченко © "...можно ли стандартными средствами отрисовать неклиентскую часть окна меню"
Вроде как можно - реализованно в компоненте XPMenu при свойстве FlatMenu = true. Если он вам Нужен (в случае если Вы его не видели) могу его переслать, скажите только куда - на почту либо в "Кладовку" (хотя по моему его я оттуда и скачивал года три назад)


 
Игорь Шевченко ©   (2004-03-11 09:57) [3]

Serge ©   (11.03.04 09:23)

Кладовка за это время не один раз реорганизовывалась (иногда спонтанно), поэтому я не надеюсь там найти.
Если не затруднит, то на whitefranz@hotmail.com


 
Игорь Шевченко ©   (2004-03-11 09:57) [3]

Serge ©   (11.03.04 09:23)

Кладовка за это время не один раз реорганизовывалась (иногда спонтанно), поэтому я не надеюсь там найти.
Если не затруднит, то на whitefranz@hotmail.com


 
serge ©   (2004-03-11 10:05) [4]

Почему-же, не затруднит, уже скинул!
Надеюсь поможет.

P.S. А кладовка по моему и сейчас спонтанно реорганизовывается :)


 
serge ©   (2004-03-11 10:05) [4]

Почему-же, не затруднит, уже скинул!
Надеюсь поможет.

P.S. А кладовка по моему и сейчас спонтанно реорганизовывается :)


 
Игорь Шевченко ©   (2004-03-11 10:34) [5]

Как получить доступ к окну OwnerDraw меню:

В событии DrawItem надо использовать вызов функции
WindowFromDC, в качестве DC выступает ACanvas.Handle, передаваемый в обработчик события OnDrawItem.
А потом с окном можно делать все необходимые действия.

Как сделано в XPMenu:
 if not (csDesigning in ComponentState) then
 begin
   if (FFlatMenu) and (not FTopMenu) then
   begin
     hDcM := ACanvas.Handle;
     hWndM := WindowFromDC(hDcM);
     if hWndM <> FForm.Handle then
     begin
       DrawWindowBorder(hWndM, FMenu.IsRightToLeft);
     end;
   end;
 end;
...
procedure TXPMenu.DrawWindowBorder(hWnd: HWND; IsRightToLeft: boolean);
var
 WRect, CRect: TRect;
 dCanvas: TCanvas;
begin

 if hWnd <= 0 then
 begin
  exit;
 end;
 dCanvas := nil;
 try
 dCanvas := TCanvas.Create;
 dCanvas.Handle := GetDc(0);

 GetClientRect(hWnd, CRect);
 GetWindowRect(hWnd, WRect);

 ExcludeClipRect(dCanvas.Handle, CRect.Left, CRect.Top, CRect.Right,
                 CRect.Bottom);

 dCanvas.Brush.Style := bsClear;

 Dec(WRect.Right, 2);
 Dec(WRect.Bottom, 2);

 dCanvas.Pen.Color := FMenuBorderColor;
 dCanvas.Rectangle(WRect.Left, WRect.Top, WRect.Right, WRect.Bottom);

 if IsRightToLeft then
 begin
   dCanvas.Pen.Color := FFColor;
   dCanvas.Rectangle(WRect.Left + 1, WRect.Top + 1, WRect.Right - 2,
                     WRect.Top + 3);

   dCanvas.MoveTo(WRect.Left + 2, WRect.Top + 2);
   dCanvas.LineTo(WRect.Left + 2, WRect.Bottom - 2);

   dCanvas.Pen.Color := FFIconBackColor;
   dCanvas.MoveTo(WRect.Right - 2, WRect.Top + 2);
   dCanvas.LineTo(WRect.Right - 2, WRect.Bottom - 2);

   dCanvas.MoveTo(WRect.Right - 2, WRect.Top + 2);
   dCanvas.LineTo(WRect.Right - 1 - FIconWidth, WRect.Top + 2);
 end
 else
 begin
   if not FGradient then
   begin
     dCanvas.Pen.Color := FFColor;
     dCanvas.Rectangle(WRect.Left + 1, WRect.Top + 1, WRect.Right - 2,
                       WRect.Top + 3);

     dCanvas.Pen.Color := FFIconBackColor;
     dCanvas.MoveTo(WRect.Left + 1, WRect.Top + 2);
     dCanvas.LineTo(WRect.Left + 2 + FIconWidth, WRect.Top + 2);
   end;

   dCanvas.Pen.Color := FFIconBackColor;
   dCanvas.MoveTo(WRect.Left + 1, WRect.Top + 1);
   dCanvas.LineTo(WRect.Left + 1, WRect.Bottom - 2);

 end;

 Inc(WRect.Right, 2);
 Inc(WRect.Bottom, 2);

 dCanvas.Pen.Color := FMenuShadowColor;
 dCanvas.Rectangle(WRect.Left +2, WRect.Bottom, WRect.Right, WRect.Bottom - 2);
 dCanvas.Rectangle(WRect.Right - 2, WRect.Bottom, WRect.Right, WRect.Top + 2);

 dCanvas.Pen.Color := FFIconBackColor;
 dCanvas.Rectangle(WRect.Left, WRect.Bottom - 2, WRect.Left + 2, WRect.Bottom);
 dCanvas.Rectangle(WRect.Right - 2, WRect.Top, WRect.Right, WRect.Top + 2);
 finally
 IntersectClipRect(dCanvas.Handle, WRect.Left, WRect.Top, WRect.Right, WRect.Bottom);
 dCanvas.Free;
 end;

end;



 
Игорь Шевченко ©   (2004-03-11 10:34) [5]

Как получить доступ к окну OwnerDraw меню:

В событии DrawItem надо использовать вызов функции
WindowFromDC, в качестве DC выступает ACanvas.Handle, передаваемый в обработчик события OnDrawItem.
А потом с окном можно делать все необходимые действия.

Как сделано в XPMenu:
 if not (csDesigning in ComponentState) then
 begin
   if (FFlatMenu) and (not FTopMenu) then
   begin
     hDcM := ACanvas.Handle;
     hWndM := WindowFromDC(hDcM);
     if hWndM <> FForm.Handle then
     begin
       DrawWindowBorder(hWndM, FMenu.IsRightToLeft);
     end;
   end;
 end;
...
procedure TXPMenu.DrawWindowBorder(hWnd: HWND; IsRightToLeft: boolean);
var
 WRect, CRect: TRect;
 dCanvas: TCanvas;
begin

 if hWnd <= 0 then
 begin
  exit;
 end;
 dCanvas := nil;
 try
 dCanvas := TCanvas.Create;
 dCanvas.Handle := GetDc(0);

 GetClientRect(hWnd, CRect);
 GetWindowRect(hWnd, WRect);

 ExcludeClipRect(dCanvas.Handle, CRect.Left, CRect.Top, CRect.Right,
                 CRect.Bottom);

 dCanvas.Brush.Style := bsClear;

 Dec(WRect.Right, 2);
 Dec(WRect.Bottom, 2);

 dCanvas.Pen.Color := FMenuBorderColor;
 dCanvas.Rectangle(WRect.Left, WRect.Top, WRect.Right, WRect.Bottom);

 if IsRightToLeft then
 begin
   dCanvas.Pen.Color := FFColor;
   dCanvas.Rectangle(WRect.Left + 1, WRect.Top + 1, WRect.Right - 2,
                     WRect.Top + 3);

   dCanvas.MoveTo(WRect.Left + 2, WRect.Top + 2);
   dCanvas.LineTo(WRect.Left + 2, WRect.Bottom - 2);

   dCanvas.Pen.Color := FFIconBackColor;
   dCanvas.MoveTo(WRect.Right - 2, WRect.Top + 2);
   dCanvas.LineTo(WRect.Right - 2, WRect.Bottom - 2);

   dCanvas.MoveTo(WRect.Right - 2, WRect.Top + 2);
   dCanvas.LineTo(WRect.Right - 1 - FIconWidth, WRect.Top + 2);
 end
 else
 begin
   if not FGradient then
   begin
     dCanvas.Pen.Color := FFColor;
     dCanvas.Rectangle(WRect.Left + 1, WRect.Top + 1, WRect.Right - 2,
                       WRect.Top + 3);

     dCanvas.Pen.Color := FFIconBackColor;
     dCanvas.MoveTo(WRect.Left + 1, WRect.Top + 2);
     dCanvas.LineTo(WRect.Left + 2 + FIconWidth, WRect.Top + 2);
   end;

   dCanvas.Pen.Color := FFIconBackColor;
   dCanvas.MoveTo(WRect.Left + 1, WRect.Top + 1);
   dCanvas.LineTo(WRect.Left + 1, WRect.Bottom - 2);

 end;

 Inc(WRect.Right, 2);
 Inc(WRect.Bottom, 2);

 dCanvas.Pen.Color := FMenuShadowColor;
 dCanvas.Rectangle(WRect.Left +2, WRect.Bottom, WRect.Right, WRect.Bottom - 2);
 dCanvas.Rectangle(WRect.Right - 2, WRect.Bottom, WRect.Right, WRect.Top + 2);

 dCanvas.Pen.Color := FFIconBackColor;
 dCanvas.Rectangle(WRect.Left, WRect.Bottom - 2, WRect.Left + 2, WRect.Bottom);
 dCanvas.Rectangle(WRect.Right - 2, WRect.Top, WRect.Right, WRect.Top + 2);
 finally
 IntersectClipRect(dCanvas.Handle, WRect.Left, WRect.Top, WRect.Right, WRect.Bottom);
 dCanvas.Free;
 end;

end;



 
serge ©   (2004-03-11 10:43) [6]

Да, кстати - забыл сказать.
По исходникам - этого-же компонента делал то-же самое (рамку), так вот что у меня получалось - в Windows 2000 все тип-топ (рамочка и все такое), в XP, 2003 - даже при отключенных темах - ничего, меню отрисовывалось стандартным :(


 
serge ©   (2004-03-11 10:43) [6]

Да, кстати - забыл сказать.
По исходникам - этого-же компонента делал то-же самое (рамку), так вот что у меня получалось - в Windows 2000 все тип-топ (рамочка и все такое), в XP, 2003 - даже при отключенных темах - ничего, меню отрисовывалось стандартным :(


 
DVM ©   (2004-03-11 18:31) [7]


> Игорь Шевченко ©   (11.03.04 10:34) [5]

Да, я уже и сам стал подумывать о примерно том же, попробую так сделать обязательно! О результатах сообщу.


 
DVM ©   (2004-03-11 18:31) [7]


> Игорь Шевченко ©   (11.03.04 10:34) [5]

Да, я уже и сам стал подумывать о примерно том же, попробую так сделать обязательно! О результатах сообщу.


 
DVM ©   (2004-03-11 22:57) [8]

Попробовал, не то чтобы не получилось. Получилось, но не очень. Рамка меню рисуется только если по нему провести мышкой. Если меню просто показать TrackPopupMenu, то оно без рамки все равно. Тестировалось в WinXP. Вот тестовый код. Есть у кого какие соображения КАК ВСЕ ТАКИ ОТРИСОВАТЬ РАМКУ У МЕНЮ???
XP меню пробовал, вроде там тоже самое, но там работает.

program Test;

uses
 Windows, Messages;

const
 IDB_START = 10;
 szMainWndClass: PChar = "MenuWndClass";
 szMainWndName:  PChar = "MenuDemo";
 szButtonName: PChar = "Click";
 
var
 wc: TWndClassEx;
 hMainWnd: HWND;
 Mesg: TMsg;
 hBtn: HWND;
 hMainMenu: HMENU;

type

PMenuItemData = ^TMenuItemData;
TMenuItemData = packed record
  text: string;
end;

//------------------------------------------------------------------------------

function OnMeasureItem(wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
begin
 PMEASUREITEMSTRUCT (lParam).itemWidth := 200;
 PMEASUREITEMSTRUCT (lParam).itemHeight:=18;
 result:=1;
end;

//------------------------------------------------------------------------------

procedure DrawWindowBorder(Wnd: HWND; IsRightToLeft: boolean);
var
WRect, CRect: TRect;
dc: HDC;
br: HBRUSH;
begin
GetClientRect(Wnd, CRect);
GetWindowRect(Wnd, WRect);
DC := GetDc(0);
BR := CreateSolidBrush(rgb(255,0,0));
ExcludeClipRect(DC, wRect.Left+3, wRect.Top+3, wRect.Right-3, wRect.Bottom-3);
fillrect(dc, wRect, br);
IntersectClipRect(dc, WRect.Left, WRect.Top, WRect.Right, WRect.Bottom);
ReleaseDc(0, dc);
DeleteObject(br);
end;

//------------------------------------------------------------------------------

function OnDrawItem(wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
var
 DC: HDC;
 rc: TRect;
 prevtx,prevbk:colorref;
 lf:logfont;
 buffnt:hfont;
 prevfn:hfont;
 br: HBRUSH;
 txt:string;
 hWndM: HWND;
begin
if (PDRAWITEMSTRUCT (LParam).CtlType = ODT_MENU) then
  begin
     DC := PDRAWITEMSTRUCT(LParam).hDC;
     rc := PDRAWITEMSTRUCT (LParam).rcItem;
     if (PDRAWITEMSTRUCT (LParam).itemState and ODS_SELECTED) = ODS_SELECTED then
       begin
         prevtx:=settextcolor (dc,GetSysColor(COLOR_HIGHLIGHTTEXT));
         prevbk:=setbkcolor (dc,GetSysColor(COLOR_HIGHLIGHT));
         Br:=CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
       end
     else
       begin
         prevtx:=settextcolor (dc,GetSysColor(COLOR_MENUTEXT));
         prevbk:=setbkcolor (dc,(rgb(110,255,60)));
         Br:=CreateSolidBrush((rgb(110,255,60)));
       end;
     FillRect(DC, rc, br);
     DeleteObject(br);

     zeromemory (@lf,sizeof (lf));
     lf.lfHeight:=12;
     lf.lfFaceName:="MS Sans Serif"+#0;
     lf.lfCharSet:=DEFAULT_CHARSET;
     lf.lfWeight:=FW_NORMAL;

     buffnt:=createfontindirect (lf);
     prevfn:=selectobject (dc,buffnt);

     txt:=PMenuItemData(PDRAWITEMSTRUCT (LParam).itemData).text;
     drawtextex(dc,pchar (txt),length (txt),rc,DT_END_ELLIPSIS or DT_LEFT or DT_MODIFYSTRING or DT_NOPREFIX or DT_VCENTER,NIL);

     settextcolor (dc,prevtx);
     selectobject (dc,prevfn);
     setbkcolor (dc,prevbk);
     deleteobject (buffnt);

     hWndM := WindowFromDC(PDRAWITEMSTRUCT (LParam).hDC);
     DrawWindowBorder(hWndM, true);
  end;
 Result:=1;
end;

//------------------------------------------------------------------------------

function OnCommand(wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
var
 ctrlID: Word;
 rc: TRect;
begin
 ctrlID := loWord(wParam);
 case ctrlID of
   IDB_START:
     begin
       GetWindowRect(wnd, rc);
       TrackPopupMenu(hMainMenu, TPM_VERNEGANIMATION, rc.Right, rc.Top, 0, Wnd, nil);
     end
 end;
 result := 0;
end;

//------------------------------------------------------------------------------

procedure ClearMenuItemsData;
var
 i: integer;
 mii: TMenuItemInfo;
begin
 for i := 0 to 10 do
   begin
     MII.cbSize := SizeOf(TMenuItemInfo);
     MII.fMask := MIIM_DATA;
     if (GetMenuItemInfo(hMainMenu, i, false, mii)<>false) then
       begin
         Dispose(PMenuItemData(mii.dwItemData));
       end;
   end;
end;

//------------------------------------------------------------------------------

function WindowProc(wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;

begin
 case msg of
   WM_MEASUREITEM: Result := OnMeasureItem(wnd, Msg, wParam, lParam);
   WM_DRAWITEM: Result := OnDrawItem(wnd, Msg, wParam, lParam);
   WM_COMMAND: Result := OnCommand(wnd, Msg, wParam, lParam);
   WM_DESTROY:
     begin
       ClearMenuItemsData;
       DestroyMenu(hMainMenu);
       PostQuitMessage(0);
       Result := 0;
       exit;
     end;
 else
   Result := DefWindowProc(Wnd, Msg, wParam, lParam);
end;
end;

//------------------------------------------------------------------------------

var
 xPos, yPos, nWidth, nHeight: integer;
 mii: TMenuItemInfo;
 i: integer;


 
DVM ©   (2004-03-11 22:57) [8]

Попробовал, не то чтобы не получилось. Получилось, но не очень. Рамка меню рисуется только если по нему провести мышкой. Если меню просто показать TrackPopupMenu, то оно без рамки все равно. Тестировалось в WinXP. Вот тестовый код. Есть у кого какие соображения КАК ВСЕ ТАКИ ОТРИСОВАТЬ РАМКУ У МЕНЮ???
XP меню пробовал, вроде там тоже самое, но там работает.

program Test;

uses
 Windows, Messages;

const
 IDB_START = 10;
 szMainWndClass: PChar = "MenuWndClass";
 szMainWndName:  PChar = "MenuDemo";
 szButtonName: PChar = "Click";
 
var
 wc: TWndClassEx;
 hMainWnd: HWND;
 Mesg: TMsg;
 hBtn: HWND;
 hMainMenu: HMENU;

type

PMenuItemData = ^TMenuItemData;
TMenuItemData = packed record
  text: string;
end;

//------------------------------------------------------------------------------

function OnMeasureItem(wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
begin
 PMEASUREITEMSTRUCT (lParam).itemWidth := 200;
 PMEASUREITEMSTRUCT (lParam).itemHeight:=18;
 result:=1;
end;

//------------------------------------------------------------------------------

procedure DrawWindowBorder(Wnd: HWND; IsRightToLeft: boolean);
var
WRect, CRect: TRect;
dc: HDC;
br: HBRUSH;
begin
GetClientRect(Wnd, CRect);
GetWindowRect(Wnd, WRect);
DC := GetDc(0);
BR := CreateSolidBrush(rgb(255,0,0));
ExcludeClipRect(DC, wRect.Left+3, wRect.Top+3, wRect.Right-3, wRect.Bottom-3);
fillrect(dc, wRect, br);
IntersectClipRect(dc, WRect.Left, WRect.Top, WRect.Right, WRect.Bottom);
ReleaseDc(0, dc);
DeleteObject(br);
end;

//------------------------------------------------------------------------------

function OnDrawItem(wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
var
 DC: HDC;
 rc: TRect;
 prevtx,prevbk:colorref;
 lf:logfont;
 buffnt:hfont;
 prevfn:hfont;
 br: HBRUSH;
 txt:string;
 hWndM: HWND;
begin
if (PDRAWITEMSTRUCT (LParam).CtlType = ODT_MENU) then
  begin
     DC := PDRAWITEMSTRUCT(LParam).hDC;
     rc := PDRAWITEMSTRUCT (LParam).rcItem;
     if (PDRAWITEMSTRUCT (LParam).itemState and ODS_SELECTED) = ODS_SELECTED then
       begin
         prevtx:=settextcolor (dc,GetSysColor(COLOR_HIGHLIGHTTEXT));
         prevbk:=setbkcolor (dc,GetSysColor(COLOR_HIGHLIGHT));
         Br:=CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT));
       end
     else
       begin
         prevtx:=settextcolor (dc,GetSysColor(COLOR_MENUTEXT));
         prevbk:=setbkcolor (dc,(rgb(110,255,60)));
         Br:=CreateSolidBrush((rgb(110,255,60)));
       end;
     FillRect(DC, rc, br);
     DeleteObject(br);

     zeromemory (@lf,sizeof (lf));
     lf.lfHeight:=12;
     lf.lfFaceName:="MS Sans Serif"+#0;
     lf.lfCharSet:=DEFAULT_CHARSET;
     lf.lfWeight:=FW_NORMAL;

     buffnt:=createfontindirect (lf);
     prevfn:=selectobject (dc,buffnt);

     txt:=PMenuItemData(PDRAWITEMSTRUCT (LParam).itemData).text;
     drawtextex(dc,pchar (txt),length (txt),rc,DT_END_ELLIPSIS or DT_LEFT or DT_MODIFYSTRING or DT_NOPREFIX or DT_VCENTER,NIL);

     settextcolor (dc,prevtx);
     selectobject (dc,prevfn);
     setbkcolor (dc,prevbk);
     deleteobject (buffnt);

     hWndM := WindowFromDC(PDRAWITEMSTRUCT (LParam).hDC);
     DrawWindowBorder(hWndM, true);
  end;
 Result:=1;
end;

//------------------------------------------------------------------------------

function OnCommand(wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
var
 ctrlID: Word;
 rc: TRect;
begin
 ctrlID := loWord(wParam);
 case ctrlID of
   IDB_START:
     begin
       GetWindowRect(wnd, rc);
       TrackPopupMenu(hMainMenu, TPM_VERNEGANIMATION, rc.Right, rc.Top, 0, Wnd, nil);
     end
 end;
 result := 0;
end;

//------------------------------------------------------------------------------

procedure ClearMenuItemsData;
var
 i: integer;
 mii: TMenuItemInfo;
begin
 for i := 0 to 10 do
   begin
     MII.cbSize := SizeOf(TMenuItemInfo);
     MII.fMask := MIIM_DATA;
     if (GetMenuItemInfo(hMainMenu, i, false, mii)<>false) then
       begin
         Dispose(PMenuItemData(mii.dwItemData));
       end;
   end;
end;

//------------------------------------------------------------------------------

function WindowProc(wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;

begin
 case msg of
   WM_MEASUREITEM: Result := OnMeasureItem(wnd, Msg, wParam, lParam);
   WM_DRAWITEM: Result := OnDrawItem(wnd, Msg, wParam, lParam);
   WM_COMMAND: Result := OnCommand(wnd, Msg, wParam, lParam);
   WM_DESTROY:
     begin
       ClearMenuItemsData;
       DestroyMenu(hMainMenu);
       PostQuitMessage(0);
       Result := 0;
       exit;
     end;
 else
   Result := DefWindowProc(Wnd, Msg, wParam, lParam);
end;
end;

//------------------------------------------------------------------------------

var
 xPos, yPos, nWidth, nHeight: integer;
 mii: TMenuItemInfo;
 i: integer;


 
DVM ©   (2004-03-11 22:57) [9]

begin

 wc.cbSize := SizeOf(wc);
 wc.style := CS_HREDRAW or CS_VREDRAW;
 wc.lpfnWndProc := @WindowProc;
 wc.cbClsExtra := 0;
 wc.cbWndExtra := 0;
 wc.hInstance := hInstance;
 wc.hIcon := 0;
 wc.hCursor := 0;
 wc.hbrBackground := COLOR_BTNFACE+1;
 wc.lpszMenuName := nil;
 wc.lpszClassName := szMainWndClass;

 if RegisterClassEx(wc) = 0 then
   begin
     MessageBox(0, "Error Register Window Class!", "Error!", 0);
     exit;
   end;

 xPos:=0; yPos:=0; nWidth:=200; nHeight:=100;

 hMainWnd:=CreateWindowEx(0,
                         szMainWndClass,
                         szMainWndName,
                         WS_OVERLAPPEDWINDOW,
                         xPos,
                         yPos,
                         nWidth,
                         nHeight,
                         0,
                         0,
                         hInstance,
                         nil);

 if hMainWnd = 0 then
   begin
     MessageBox(0, "Error Create Window!", "Error!", 0);
     UnregisterClass(szMainWndClass, hInstance);
     exit;
   end;

 hBtn := CreateWindowEx(0,
                       "button",
                       szButtonName,
                       BS_PUSHBUTTON or
                       WS_CHILD or
                       WS_VISIBLE,
                       10,
                       10,
                       75,
                       25,
                       hMainWnd,
                       IDB_START,
                       hInstance,
                       nil);

               
 if hBtn = 0 then
   begin
     MessageBox(0, "Button not Created!", "Error!", 0);
     DestroyWindow(hMainWnd);
     UnregisterClass(szMainWndClass, hInstance);
     exit;
   end;

 ShowWindow(hMainWnd, SW_SHOW);

 hMainMenu:=CreatePopupMenu;
 if hMainMenu<>0 then
   begin
     for i:=0 to 10 do
       begin
         ZeroMemory(@mii, SizeOf(mii));
         New(PMenuItemData(mii.dwItemData));
         mii.cbSize:=SizeOf(TMenuItemInfo);
         mii.fType:=MFT_OWNERDRAW;
         mii.fMask:=MIIM_TYPE or MIIM_DATA  or MIIM_ID;
         mii.wID:=i;
         PMenuItemData(mii.dwItemData).text:="Item";
         InsertMenuItem (hMainMenu, 0, true, mii);
       end;
   end;

 while GetMessage(Mesg, 0, 0, 0) do
  begin
    TranslateMessage(Mesg);
    DispatchMessage(Mesg);
  end;
end.


 
DVM ©   (2004-03-11 22:57) [9]

begin

 wc.cbSize := SizeOf(wc);
 wc.style := CS_HREDRAW or CS_VREDRAW;
 wc.lpfnWndProc := @WindowProc;
 wc.cbClsExtra := 0;
 wc.cbWndExtra := 0;
 wc.hInstance := hInstance;
 wc.hIcon := 0;
 wc.hCursor := 0;
 wc.hbrBackground := COLOR_BTNFACE+1;
 wc.lpszMenuName := nil;
 wc.lpszClassName := szMainWndClass;

 if RegisterClassEx(wc) = 0 then
   begin
     MessageBox(0, "Error Register Window Class!", "Error!", 0);
     exit;
   end;

 xPos:=0; yPos:=0; nWidth:=200; nHeight:=100;

 hMainWnd:=CreateWindowEx(0,
                         szMainWndClass,
                         szMainWndName,
                         WS_OVERLAPPEDWINDOW,
                         xPos,
                         yPos,
                         nWidth,
                         nHeight,
                         0,
                         0,
                         hInstance,
                         nil);

 if hMainWnd = 0 then
   begin
     MessageBox(0, "Error Create Window!", "Error!", 0);
     UnregisterClass(szMainWndClass, hInstance);
     exit;
   end;

 hBtn := CreateWindowEx(0,
                       "button",
                       szButtonName,
                       BS_PUSHBUTTON or
                       WS_CHILD or
                       WS_VISIBLE,
                       10,
                       10,
                       75,
                       25,
                       hMainWnd,
                       IDB_START,
                       hInstance,
                       nil);

               
 if hBtn = 0 then
   begin
     MessageBox(0, "Button not Created!", "Error!", 0);
     DestroyWindow(hMainWnd);
     UnregisterClass(szMainWndClass, hInstance);
     exit;
   end;

 ShowWindow(hMainWnd, SW_SHOW);

 hMainMenu:=CreatePopupMenu;
 if hMainMenu<>0 then
   begin
     for i:=0 to 10 do
       begin
         ZeroMemory(@mii, SizeOf(mii));
         New(PMenuItemData(mii.dwItemData));
         mii.cbSize:=SizeOf(TMenuItemInfo);
         mii.fType:=MFT_OWNERDRAW;
         mii.fMask:=MIIM_TYPE or MIIM_DATA  or MIIM_ID;
         mii.wID:=i;
         PMenuItemData(mii.dwItemData).text:="Item";
         InsertMenuItem (hMainMenu, 0, true, mii);
       end;
   end;

 while GetMessage(Mesg, 0, 0, 0) do
  begin
    TranslateMessage(Mesg);
    DispatchMessage(Mesg);
  end;
end.


 
Игорь Шевченко ©   (2004-03-11 23:27) [10]

Я дико извиняюсь, а то же самое на VCL не проще будет отлаживать ? Уж больно код длинный :)


 
Игорь Шевченко ©   (2004-03-11 23:27) [10]

Я дико извиняюсь, а то же самое на VCL не проще будет отлаживать ? Уж больно код длинный :)


 
Gero ©   (2004-03-12 07:42) [11]

> Сдается мне, что лучше имитировать Popup-меню, например,
> ListBox"ом и уже его рисовать, как угодно.
> Это, кстати, не так трудно

Интересная идея.
Только как насчет исчезновения меню?
Оно ведь должно исчезать когда:
- Вызывается другое или это же меню
- Меню теряет фокус
- Приложение теряет фокус
И еще в нескольких случаях. Как это все можно отслеживать?
Чтобы это меню работало четко, как и стандартное.


 
Gero ©   (2004-03-12 07:42) [11]

> Сдается мне, что лучше имитировать Popup-меню, например,
> ListBox"ом и уже его рисовать, как угодно.
> Это, кстати, не так трудно

Интересная идея.
Только как насчет исчезновения меню?
Оно ведь должно исчезать когда:
- Вызывается другое или это же меню
- Меню теряет фокус
- Приложение теряет фокус
И еще в нескольких случаях. Как это все можно отслеживать?
Чтобы это меню работало четко, как и стандартное.


 
Игорь Шевченко ©   (2004-03-12 10:12) [12]

Gero ©   (12.03.04 07:42)


> Оно ведь должно исчезать когда:
> - Вызывается другое или это же меню
> - Меню теряет фокус
> - Приложение теряет фокус


На каждое из этих событий окну-владельцу меню посылается сообщение. Я встречал в свое время в сети имитаторы меню, возни много, но способ имеет право на существование. Кстати, имитаторы меню реализованы в DevExpress (TDxBarSubMenuControl), в MSDN и в MSOffice (MSOCommandBarPopup)


 
Игорь Шевченко ©   (2004-03-12 10:12) [12]

Gero ©   (12.03.04 07:42)


> Оно ведь должно исчезать когда:
> - Вызывается другое или это же меню
> - Меню теряет фокус
> - Приложение теряет фокус


На каждое из этих событий окну-владельцу меню посылается сообщение. Я встречал в свое время в сети имитаторы меню, возни много, но способ имеет право на существование. Кстати, имитаторы меню реализованы в DevExpress (TDxBarSubMenuControl), в MSDN и в MSOffice (MSOCommandBarPopup)


 
Gero ©   (2004-03-12 17:30) [13]

> На каждое из этих событий окну-владельцу меню посылается сообщение

А какое именно сообщение, Вы не в курсе?


 
Gero ©   (2004-03-12 17:30) [13]

> На каждое из этих событий окну-владельцу меню посылается сообщение

А какое именно сообщение, Вы не в курсе?


 
Игорь Шевченко ©   (2004-03-12 23:55) [14]

Gero ©   (12.03.04 17:30)

в первую очередь WM_KILLFOCUS

Также можно посмотреть реализацию класса TPopupListBox в VCL (в DBCtrls.pas, если не ошибаюсь, он себя ведет примерно так же, как меню)


 
Игорь Шевченко ©   (2004-03-12 23:55) [14]

Gero ©   (12.03.04 17:30)

в первую очередь WM_KILLFOCUS

Также можно посмотреть реализацию класса TPopupListBox в VCL (в DBCtrls.pas, если не ошибаюсь, он себя ведет примерно так же, как меню)


 
Gero ©   (2004-03-13 08:56) [15]

> Игорь Шевченко ©   (12.03.04 23:55) [14]

Спасибо за инфу.


 
Gero ©   (2004-03-13 08:56) [15]

> Игорь Шевченко ©   (12.03.04 23:55) [14]

Спасибо за инфу.


 
Nick Denry ©   (2004-03-13 15:10) [16]

2 > Игорь Шевченко ©  
Наверно, я плохо молился. Или вопрос стал слишком популярен? :))))

Вопрос в тему : можно - ли перерисовывать сепаратор (MENUITEM SEPARATOR) своими силами (т.е. получить линию, которой рисуются все разделители). Это нужно, чтобы нарисовать битмап с надписью с левой стороны меню, как в Пуске....

С уважением, NickD.


 
Nick Denry ©   (2004-03-13 15:10) [16]

2 > Игорь Шевченко ©  
Наверно, я плохо молился. Или вопрос стал слишком популярен? :))))

Вопрос в тему : можно - ли перерисовывать сепаратор (MENUITEM SEPARATOR) своими силами (т.е. получить линию, которой рисуются все разделители). Это нужно, чтобы нарисовать битмап с надписью с левой стороны меню, как в Пуске....

С уважением, NickD.


 
Gero ©   (2004-03-13 19:04) [17]

Nick Denry ©   (13.03.04 15:10) [16]
> можно - ли перерисовывать сепаратор (MENUITEM SEPARATOR) своими силами

Конечно можно, через OnDrawItem.


 
Gero ©   (2004-03-13 19:04) [17]

Nick Denry ©   (13.03.04 15:10) [16]
> можно - ли перерисовывать сепаратор (MENUITEM SEPARATOR) своими силами

Конечно можно, через OnDrawItem.


 
Nick Denry ©   (2004-03-14 12:52) [18]

2> Gero (c)

Конечно можно, через OnDrawItem.

Вопервых без VCL - это WM_DRAWITEM насколько я понимаю, во - вторых  у сепаратора не может быть стиля MF_OWNERDRAW (MFT_OWNERDRAW). Я думаю, что можно как-то нарисовать (получить, если это битмап) линию, которая рисуется в сепараторе , или нет? А сам сепаратор перерисовывать вроде бесполезно...

С уважением, NIckD.


 
Nick Denry ©   (2004-03-14 12:52) [18]

2> Gero (c)

Конечно можно, через OnDrawItem.

Вопервых без VCL - это WM_DRAWITEM насколько я понимаю, во - вторых  у сепаратора не может быть стиля MF_OWNERDRAW (MFT_OWNERDRAW). Я думаю, что можно как-то нарисовать (получить, если это битмап) линию, которая рисуется в сепараторе , или нет? А сам сепаратор перерисовывать вроде бесполезно...

С уважением, NIckD.



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2004.04.11;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.61 MB
Время: 0.046 c
7-1080148513
beard
2004-03-24 20:15
2004.05.09
Мультизагрузка в Windows XP


3-1081879329
3APA3A
2004-04-13 22:02
2004.05.09
Создание DATABASE в FireBird...


3-1081483877
Mery
2004-04-09 08:11
2004.05.09
Сумма в запросе


1-1082959287
Alexander
2004-04-26 10:01
2004.05.09
Динамическое создание меню: возникла необходимость создания меню


8-1069869678
Михайлов Антон
2003-11-26 21:01
2004.05.09
TV Capture Card





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский