Ir ao conteúdo

[C/C++11 - win32] - fazer a class menu


Cambalinho

Posts recomendados

Postado

eu estou a criar 1 class menu mas com algum problemas com o ciclo de mensagens :(

class Menu{private:    static int intID;    int ID=0;    bool primeiromenu=false;    HMENU MenuHandle=NULL;    HMENU hMenu=NULL;    int menuposition=0;    string strCaption="";    static LRESULT CALLBACK MenuSubclassProc( HWND hwnd, UINT uMsg, WPARAM wParam,  LPARAM lParam)    {       Menu *wnd = 0;        // retrieve associated Window instance        wnd = reinterpret_cast<Menu *>(GetWindowLong(hwnd, GWL_USERDATA));        if(uMsg==WM_MENUCOMMAND)            wnd->MenuClick();        return DefWindowProc(hwnd, uMsg, wParam, lParam);    }    public:    event(MenuClick) = []() {;};    Menu(string caption="&Menu",HMENU subtmenu=NULL, HWND MainHWND=WindowMain)    {        intID=intID+1;        ID=intID;        if(caption!="-")            caption=(string)caption + " " + to_string(ID);        strCaption=caption;        if(GetMenu(MainHWND)==NULL)            hMenu = CreateMenu();        else            hMenu =GetMenu(MainHWND);        if (subtmenu==NULL)        {            HMENU hSubMenu=CreatePopupMenu() ;            AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, caption.c_str());            MenuHandle=hSubMenu;//my error was here            SetMenu(MainHWND, hMenu);            menuposition=GetMenuItemCount(hMenu)-1;            primeiromenu=true;        }        else        {            if(caption=="-")                AppendMenu(subtmenu, MF_SEPARATOR, ID, caption.c_str());            else                AppendMenu(subtmenu, MF_STRING, ID, caption.c_str());            MenuHandle=subtmenu;            menuposition=GetMenuItemCount(subtmenu)-1;            SetMenu(MainHWND, hMenu);        }            MENUINFO  mi;            mi.cbSize=sizeof(MENUINFO );            if(primeiromenu==true)                SetMenuInfo(GetMenu(WindowMain),&mi);            else                GetMenuInfo(MenuHandle,&mi);            mi.fMask=MIM_STYLE;            mi.dwStyle =MNS_NOTIFYBYPOS;            if(primeiromenu==true)                SetMenuInfo(GetMenu(WindowMain),&mi);            else                SetMenuInfo(MenuHandle,&mi);        SetWindowLong(MainHWND,GWL_WNDPROC,(LONG)MenuSubclassProc);        SetWindowLong(MainHWND,GWL_USERDATA,(LONG)this);    }    void Show(HWND mainshowed)    {        LPPOINT x;        GetCursorPos(x);        SetForegroundWindow(mainshowed);        TrackPopupMenu(MenuHandle,NULL,x->x,x->y,0,mainshowed,NULL);        PostMessage(mainshowed, WM_NULL, 0, 0);    }    int getmenuposition()    {        return menuposition;    }    property<string> Caption    {        Get(string)        {            return strCaption;        },        Set(string text)        {            MENUITEMINFO mi;            mi.cbSize=sizeof(MENUITEMINFO);            if(primeiromenu==true)                GetMenuItemInfo(GetMenu(WindowMain),menuposition,true,&mi);            else                GetMenuItemInfo(MenuHandle,menuposition,true,&mi);            mi.fMask=MIIM_STRING;            mi.dwTypeData =(LPTSTR)text.c_str();            if(primeiromenu==true)                SetMenuItemInfo(GetMenu(WindowMain),menuposition,true,&mi);            else                SetMenuItemInfo(MenuHandle,menuposition,true,&mi);        }    };    operator int()    {        return ID;    }    operator HMENU()    {        return MenuHandle;    }    void Destroy()    {        DestroyMenu(MenuHandle);    }};int Menu::intID=0;//no procedimento das mensagens do form tenho:case WM_MENUCOMMAND:                {                    SendMessage((HWND)lParam , WM_COMMAND, wParam, lParam);                }                break;                case WM_COMMAND:                {                    SendMessage((HWND)lParam , WM_COMMAND, wParam, lParam);                }                break;

o problema é que o  procedimento do menu nao retorna ao do form :( alguem me pode explicar o que estou fazendo mal?

Postado

Você está criando a janela do zero?

Com WinMain, atribuindo WNDCLASS, RegisterClass, etc..?

sim. tenho tudo numa class form. e mais 1 procedimento para o loop das mensagens.

o erro que tenho é mesmo com SetWindowLong(), porque chama o MenuSubclassProc() mas nao volta ao procedimento de mensagens do form. outra coisa: MainHWND é o HWND do form, penso que isto esta errado tambem. mas aceito ideias

Postado

No case você está tentando processar a mensagem WM_MENUCOMMAND. Tente processar WM_COMMAND que é a mensagem para eventos do menu.

Uma ideia que talvez deixe o projeto mais simples na criação de menus, é o uso de recursos. Já tentou usar recursos?

Mas eu acho que, já que você está usando as APIs diretamente, você devia programar C.

C++ deixa o projeto complexo, além de não ter grande vantagem. Se for para programar em C++, acho melhor usar alguma biblioteca POO como o MFC que encapsula as APIs.

Postado

No case você está tentando processar a mensagem WM_MENUCOMMAND. Tente processar WM_COMMAND que é a mensagem para eventos do menu.

Uma ideia que talvez deixe o projeto mais simples na criação de menus, é o uso de recursos. Já tentou usar recursos?

Mas eu acho que, já que você está usando as APIs diretamente, você devia programar C.

C++ deixa o projeto complexo, além de não ter grande vantagem. Se for para programar em C++, acho melhor usar alguma biblioteca POO como o MFC que encapsula as APIs.

esquece o MFC lol

sim eu posso alterar isso. mas estou a usar essa mensagem porque modifiquei os menus para isso ;)

eu quero meter o processamento das mensagens na class ;)

Postado

Ok, não tenho mais nenhuma sugestão.

Vamos aguardar, talvez alguém ajude.

eu entendi a tua sugestao do MFC e eu ja dei conta dessa linguagem complicada.. eu prefiro simplificar as minhas cenas ;)

mas tenho de ver como vou corrigir aquele erro :(

o problema é os menus usarem HMENU em vez de HWND. senao estava resolvido de outra forma

Postado

Eu acho que se você quisesse simplificar, considerando esse código, poderia evitar POO. Mas se você domina C++, ok. Só sugeri uma lib tipo MFC considerando um projeto POO.

 

A forma mais simplificada de criar menu é com recurso (rc file). Não há necessidade de handle HMENU, basta criar o script e passar o nome do menu para lpszMenuName. Aí basta tratar a mensagem WM_COMMAND de WindowProc.

 

Mas da forma que está aí, fica difícil ajudar.

Postado

Eu acho que se você quisesse simplificar, considerando esse código, poderia evitar POO. Mas se você domina C++, ok. Só sugeri uma lib tipo MFC considerando um projeto POO.

 

A forma mais simplificada de criar menu é com recurso (rc file). Não há necessidade de handle HMENU, basta criar o script e passar o nome do menu para lpszMenuName. Aí basta tratar a mensagem WM_COMMAND de WindowProc.

 

Mas da forma que está aí, fica difícil ajudar.

imagina isto:

1 - crias 1 objecto do menu;

2 - esse objecto pode alterar a opções do menu(texto, atalhos, cor de texto e muito mais);

3 - esse objecto, com lambdas, podes fazer os 'eventos'.

quero inserir tudo nessa class. mas a parte dos 'eventos' esta complicada :(

('eventos' -  falo das mensagens)

PS: para fazer 1 form e mostrar, só preciso de criar 1 variavel do tipo form. nao é simplificado? ;)

PS: posso ocultar a cor de fundo do form, permitindo as formas do form. nao é simplificado? ;)

Postado

Prefiro usar resource e simplesmente passar o nome do menu para lpszMenuName.

Fica mais fácil gerenciar o objeto e até traduzir se o programador quiser.

Você usaria/usa essa sua classe em um projeto profissional com milhares de linhas de código?

Postado

Prefiro usar resource e simplesmente passar o nome do menu para lpszMenuName.

Fica mais fácil gerenciar o objeto e até traduzir se o programador quiser.

Você usaria/usa essa sua classe em um projeto profissional com milhares de linhas de código?

sim ;)

sabes porque?

olha isto:

Menu menu1, menu2, menu3("oi",menu2), menu4("hello",menu2);

o resto é só propriedades amigo. então nao usavas?

nao sei de destes conta: mas objecto do Menu cria o menu e mostra-o. o menu3 e menu4 indico(2º parametro) o sitio onde vão ficar amigo ;)

Postado

Já deu uma olhada no gerenciador de eventos da biblioteca Boost C++?

http://en.highscore.de/cpp/boost/eventhandling.html

 

Talvez você encontre tudo o que necessita. 

lamento mas nao :(

 

tenho outra idea para isso, ao criar os menus, ja os preparo  para serem trabalhados na mensagem WM_MENUCOMMAND:

//put the this on dwItemData            MENUITEMINFO  s;            GetMenuItemInfo (hMenu,intID, true, &s);            s.cbSize=sizeof(MENUITEMINFO );            s.fMask=MIIM_DATA;            s.dwItemData=(ULONG_PTR)this;            SetMenuItemInfo (hMenu,intID, true, &s);            //change the menu for use the WM_MENUCOMMAND            MENUINFO mnInfo;            GetMenuInfo(hMenu,&mnInfo);            mnInfo.cbSize=sizeof(MENUINFO);            mnInfo.fMask=MIM_STYLE;            mnInfo.dwStyle=MNS_NOTIFYBYPOS;            SetMenuInfo(hMenu,&mnInfo);

mas nao estou a captar o 'this' correctamente.. alguem me pode dizer o que fiz de errado?

case WM_MENUCOMMAND:                {                    BOOL fResult = FALSE;                    MENUITEMINFO menuInfo = { 0 };                    menuInfo.cbSize = sizeof(MENUITEMINFO);                    menuInfo.fMask = MIIM_ID | MIIM_DATA;                    fResult = GetMenuItemInfo((HMENU)lParam,(UINT) wParam, TRUE, &menuInfo );                    if (fResult!=0)                    {                        UINT myId = menuInfo.wID; // this is item ID                        ULONG_PTR myData = menuInfo.dwItemData; // item data (like 'this' pointer')                        CREATESTRUCT *p = (CREATESTRUCT *)menuInfo.dwItemData;                        Menu *menu = (Menu *)p->lpCreateParams;                        //if(mMenu->MenuClick==NULL) break;                        //mMenu->MenuClick();//it's a lambda function variable                    }                }                break;
  • mês depois...
Postado

eu resolvi esse erro:

Menu(string caption, Menu *submenu=NULL, HWND MainHWND=WindowMain, bool systmenu=false) //WindowMain is then 1st form handle(WHND window) that is created    {        //calculate the ID        intID=intID+1;        ID=intID;        Mainwindow=MainHWND;        //calculate the caption //i'm changing these too        strCaption=caption;        if (strCaption=="")            strCaption=(string)caption + " " + to_string(ID);        //getting the menu bar handle if the submenu is null        mnuBar = GetMenu(Mainwindow);        if(mnuBar==NULL)            mnuBar = CreateMenu();        if(systmenu==true)            mnuBar=GetSystemMenu(Mainwindow,false);        //creates the popup menu for add the new items        if (submenu==NULL && systmenu==true )        {            AppendMenu(mnuBar, MF_STRING, ID, strCaption.c_str());            MenuHandle=mnuBar;//is where the submenu is created            SetMenu(MainHWND, mnuBar);            menuposition=GetMenuItemCount(mnuBar)-1;            ispopup=false;            MenuPopup=mnuBar;            primeiromenu=false;        }        else if (submenu==NULL)        {            HMENU hSubMenu=CreatePopupMenu() ;            AppendMenu(mnuBar, MF_STRING | MF_POPUP, (UINT)hSubMenu, strCaption.c_str());            MenuHandle=hSubMenu;//is where the submenu is created            SetMenu(MainHWND, mnuBar);            menuposition=GetMenuItemCount(mnuBar)-1;            ispopup=true;            MenuPopup=GetMenu(MainHWND);            primeiromenu=true;        }        else        {            //creates a separator            if(strCaption=="-")            {                AppendMenu((HMENU)submenu, MF_SEPARATOR, ID, strCaption.c_str());                MenuHandle=(HMENU)submenu;                SetMenu(MainHWND, GetMenu(MainHWND));//update the menu                ispopup=false;            }            //change the subitem to be a popup menu            else if(submenu->ispopup==false)            {                HMENU hSubMenu=CreatePopupMenu();                ModifyMenu(submenu->MenuHandle,submenu->menuposition,MF_BYPOSITION| MF_POPUP|MF_STRING,(UINT_PTR)hSubMenu, submenu->strCaption.c_str());                submenu->MenuHandle=hSubMenu;//is where the submenu is created                AppendMenu(submenu->MenuHandle, MF_STRING, ID, strCaption.c_str());                SetMenu(MainHWND, GetMenu(MainHWND));                menuposition=GetMenuItemCount(submenu->MenuHandle)-1;                MenuHandle=hSubMenu;                SetMenu(MainHWND, GetMenu(MainHWND));                MenuPopup=submenu->MenuPopup;                submenu->ispopup=true;            }            //add a new item on subtmenu popup menu            else if(submenu!=NULL)            {                AppendMenu((HMENU)submenu->MenuHandle, MF_STRING, ID, strCaption.c_str());                MenuHandle=(HMENU)submenu->MenuHandle;//the menu handle is the popup menu handle... instead the item menu handle                 menuposition=GetMenuItemCount((HMENU)submenu->MenuHandle)-1;//calculate the menu position                SetMenu(MainHWND, GetMenu(MainHWND));//update the menu                ispopup=false;            }        }        MENUINFO mnInfo;        mnInfo.cbSize=sizeof(MENUINFO);        mnInfo.fMask=MIM_STYLE;        if(systmenu==false)            GetMenuInfo(GetMenu(MainHWND),&mnInfo);        else            GetMenuInfo(GetSystemMenu(MainHWND,false),&mnInfo);        mnInfo.cbSize=sizeof(MENUINFO);        mnInfo.fMask=MIM_STYLE;        mnInfo.dwStyle=MNS_NOTIFYBYPOS;        if(systmenu==false)            SetMenuInfo(GetMenu(MainHWND),&mnInfo);        //put the this on dwItemData        HMENU hMenu = NULL;        if(primeiromenu)            hMenu = GetMenu(MainHWND);        else if(ispopup)            hMenu = (HMENU)submenu->MenuHandle;        else if(systmenu==true)            hMenu=GetSystemMenu(MainHWND,false);        else            hMenu = MenuHandle;        MENUITEMINFO  s;        s.cbSize=sizeof(MENUITEMINFO );        s.fMask=MIIM_DATA;        GetMenuItemInfo (hMenu,menuposition, true, &s);        s.cbSize=sizeof(MENUITEMINFO );        s.fMask=MIIM_DATA;        s.dwItemData=(ULONG_PTR)this;        SetMenuItemInfo (hMenu,menuposition, true, &s);    }//no window procedure do form:case WM_MENUCOMMAND:                {                    MENUITEMINFO menuInfo;                    menuInfo.cbSize = sizeof(MENUITEMINFO);                    menuInfo.fMask=MIIM_DATA;                    GetMenuItemInfo((HMENU)lParam,(UINT) wParam, true, &menuInfo );//true means by position                    Menu *mMenu = (Menu *) menuInfo.dwItemData;                    mMenu->MenuClick();                }                break;

agora estou a fazer para o menu do system(o icon da janela):

case WM_INITMENUPOPUP:                {                    menuhandle=(HMENU)wParam;                    return 0;                }                break;                case WM_SYSCOMMAND:                {                    if (menuhandle!=NULL)                    {                        int menuitemcount=GetMenuItemCount(menuhandle)-1;                        int i=0;                        for(i=0; i<menuitemcount; i++)                        {                            if(GetMenuState(menuhandle,i,MF_BYPOSITION) == MF_HILITE)                            {                                menuposition=(UINT)i;                                break;                            }                        }                        SetWindowText(HandleWindow, to_string(i).c_str());                        MENUITEMINFO menuInfo;                        menuInfo.cbSize = sizeof(MENUITEMINFO);                        menuInfo.fMask=MIIM_DATA;                        GetMenuItemInfo(menuhandle,(UINT) menuposition, true, &menuInfo );//true means by position                        Menu *mMenu = (Menu *) menuInfo.dwItemData;                        if (mMenu!=NULL)                        {                            mMenu->MenuClick();                            menuhandle=NULL;                            menuposition=0;                        }                    }                    return DefWindowProc(HandleWindow, msg, wParam, lParam);                }                break;

algo se passa com o ciclo for, eu recebo sempre o mesmo resultado. o GetMenuState() nao é para me indicar se o rato esta por cima do item do menu?

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!