Menus
Autor: Edgar Diniz | Publicado: 2009-12-14T13:54:00-03:00

Neste tópico, ensinarei como adicionar uma barra de menus (com menus, obviamente) ao programa. Neste momento, colocarei menus simples, apenas com comandos simples. Há outros componentes que podem ser adicionados aos menus, mas serão tratados em tópicos futuros.

Vamos lá.


Barra de menus

Tudo começa com a barra de menus. Naturalmente, é lá que ficam os menus. E, naturalmente, fica no topo da janela:



FXMenuBar *menuBar = new FXMenuBar(this, LAYOUT_FILL_X|FRAME_RAISED);

Percebam que ela pode ser criada localmente, o próprio FOX se encarrega de liberá-la depois. Além disso, lembrem-se que a localização padrão é no topo da janela, portanto não precisei passar LAYOUT_SIDE_TOP.

Isso cria o espaço ideal para os menus. Aqui, criarei apenas dois, "Arquivo" e "Editar", apenas para exemplificar. Não é um processo complicado. Pelo contrário, é bem simples.


Adicionando menus

Os menus precisam ser declarados com escopo de classe. Então, na declaração da classe, temos:



protected:
  FXMenuPane *_fileMenu;
  FXMenuPane *_editMenu;

Agora, vamos criar e preencher os menus. Neste primeiro exemplo, do menu "Arquivo", vou colocar e explicar linha por linha. No segundo, o menu "Editar", vou colocar tudo de uma vez só para explicar a forma como eu gosto de criar os menus.

Menu Arquivo




_fileMenu = new FXMenuPane(this);

Cria o painel onde ficarão os itens do menu. Os dois parâmetros do construtor são a janela pai e as opções, que não é necessário informar.




new FXMenuCommand(_fileMenu, "&amp;Carregar imagem...", 0, 0, 0);

Cria um comando de menu. Os principais parâmetros são:

Menu onde vai aparecer. Na verdade, pode ficar em um FXComposite qualquer (e, de fato, eu coloquei um sem querer na própria janela, ficou algo bizarro). Como estamos criando menus, é bom que fique em um FXMenuPanel. Neste caso, no menu "Arquivo".

Texto do comando. O caractere &amp; indica que a próxima letra ficará sublinhada, para acesso através de Alt+. Neste caso, Alt+C acionará esse comando. É meio Uíndous, mas muito melhor que em Java (um setMnemonic() horroroso).

Ícone. FXMenuCommands podem ter um ícone associado, indique aqui. Já falei sobre ícones aqui.

Alvo do evento.

ID da mensagem. A série sobre Tratamento de Eventos explica essa parte referente a esses dois últimos parâmetros.

O último parâmetro são as opções, novamente desnecessário informar.

E caso não tenha ficado claro pelo nome da classe: FXMenuCommands lançam eventos do tipo SEL_COMMAND. Isso significa que no mapa de mensagens do tratador (seja a própria janela ou seja lá quem for) vai aparecer algo como:



FXMAPFUNC(SEL_COMMAND,
  FoxTutorialMainWindow::ID_LOAD_IMAGE,
  FoxTutorialMainWindow::onCmdLoadImage),


Continuando:



new FXMenuSeparator(_fileMenu);

Apenas um separador. Desenha uma linha para separar os comandos em seções.




new FXMenuCommand(_fileMenu, "&amp;Sair\tCtrl+Q\tEncerrar o aplicativo",
        0, getApp(), FXApp::ID_QUIT);

Mais um comando, para fechar o aplicativo. Desta vez fiz com que esse comando lançasse um evento para exemplificar. Já falei sobre como fechar o aplicativo através de um comando aqui.

A única observação adicional é quanto ao texto do comando. Assim como o texto dos botões, este também é dividido em três seções, separadas pelo caractere de tabulação:

A primeira é o texto que será exibido. Natural e praticamente obrigatório.

A segunda são as teclas de atalho (aceleradores). Neste caso, coloquei Ctrl+Q para fechar o aplicativo. Opcional.

A terceira é o texto que aparecerá na barra de status. Falaremos dela no futuro. Opcional.

Bom, isso preenche o nosso menu "Arquivo". Vamos, agora, adicioná-lo à barra de menus (ou vocês achavam que isso já tinha sido feito?):



new FXMenuTitle(menuBar, "&amp;Arquivo", 0, _fileMenu);

Aqui informamos:

A barra de menus onde vai ficar. Novamente, pode ficar em um FXComposite qualquer. Mas não há a menor necessidade de uma bizarrice dessas.

O título que vai aparecer. Não preciso mais dizer para que serve o &amp;, preciso?

Ícone. Eu, particularmente, nunca vi em nenhum programa (escrito em FOX ou não) um menu com ícone. Mas o FOX Toolkit te dá essa liberdade.

O painel que será exibido ao acionar o menu.

Nosso menu Arquivo está pronto. Observemos, agora, o menu Editar.


Menu Editar




_editMenu = new FXMenuPane(this);
  new FXMenuCommand(_editMenu, "&amp;Preferências...", 0, 0, 0);
new FXMenuTitle(menuBar, "&amp;Editar", 0, _editMenu);

Bom, esse aqui é só para mostrar a maneira como eu normalmente crio menus (e, de fato, qualquer objeto composto por uma hierarquia).

Na primeira linha eu sigo o recuo normal do código. Esta é, digamos, a linha de criação (cunhei esse termo agora...).

Em seguida, vêm as linhas de preenchimento (de novo...). Nelas, coloco os objetos que vão "dentro" do objeto principal, com um recuo a mais exatamente para deixar claro essa hierarquia.

No final, volto ao recuo da linha de criação. É a linha de realização ( &gt;D ), pois nela dou um sentido ao meu objeto (afinal, não faz sentido criar um painel sem acesso a ele).

Desenvolvi esse estilo quando comecei a trabalhar com o OpenSceneGraph (não confundam com OpenSG) e precisava definir as características de um modelo, ficava mais ou menos assim:
osg::ref_ptr geode = new osg::Geode();
&nbsp;&nbsp;osg::Geometry *geometry = new osg::Geometry();
&nbsp;&nbsp; &nbsp;osg::Vec3Array *vertexArray = new osg::Vec3Array();
&nbsp;&nbsp; &nbsp; &nbsp;/* Preenche a lista de vértices */
&nbsp;&nbsp; &nbsp;geometry-&gt;setVertexArray(vertexArray);

&nbsp;&nbsp; &nbsp;osg::DrawElementsUInt *primitiveSet = new osg::DrawElementsUInt(GL_POINTS);
&nbsp;&nbsp; &nbsp; &nbsp;/* Adiciona as primitivas */
&nbsp;&nbsp; &nbsp;geometry-&gt;addPrimitiveSet(primitiveSet);
&nbsp;&nbsp;geode-&gt;addDrawable(geometry);


Recuar os objetos mais internos me ajudou a entender melhor a hierarquia dos objetos do OpenSceneGraph e acabei aplicando essa técnica ao programar com o FOX Toolkit. Não vou explicar porque está fora do escopo do tópico (e do blog como um todo...).

Bom, é apenas uma sugestão.


Liberando os menus

FXMenuPanels são objetos compartilháveis, assim como ícones. Isso serve, por exemplo, para exibir o mesmo painel pelo menu ou clicando com o botão direito sobre algum objeto.

Sendo assim, devem ser liberados "na mãozona":



delete _fileMenu;
delete _editMenu;


Resultado

Depois disso tudo, o menu Arquivo fica conforme a imagem a seguir. Em destaque, a barra de status mostrando o texto do comando de sair.





Considerações finais

Notem o texto dos comandos de "Carregar imagem..." (menu Arquivo) e "Preferências..." (menu Editar). Eles terminam em reticências.

Terminar um texto de exibição (tanto de comandos de menu como também de botões) com reticências informa imediatamente ao usuário que uma nova janela se abrirá, onde ele terá que executar mais ações.


Outra observação importante é onde posicionar o código para criação dos menus. No início, eu colocava tudo no construtor. As coisas foram aumentando de tamanho, e resolvi apenas criar a barra no construtor e chamar uma função, populateMenu(), para fazer essa tarefa.

Agora, as coisas no meu projeto estão ficando grandes demais, e estou pensando seriamente em criar uma nova classe só para isso. Acontece que, na pressa de obter resultados, a gente acaba tocando tudo no mesmo lugar. Nessa brincadeira até o padrão MVC vai para o espaço. Por favor, não façam isso.


Bom, esse é o que tem de mais básico em termos de menus. Ainda vou discutir sobre submenus e outros elementos que podem aparecer em um FXMenuPanel. Um abraço e até lá.