quinta-feira, 14 de maio de 2009

Layout Managers: Aninhamento

Todos os gerenciadores de layout do FOX podem ser aninhados, ou seja, podem ser filhos de outros gerenciadores de layout. Essa, na verdade, é uma característica obrigatória em qualquer biblioteca de interface gráfica, pois é isso que permite compor a aparência dos programas. Sem essa capacidade, ficaria quase impossível criar uma interface sofisticada (pense em posicionar cada elemento manualmente, ajustar as bordas de cada seção e outras tarefas tediosas).

Neste tópico, apresentarei um exemplo bem simples (e didático...) desse aninhamento. Farei uma janela semelhante a uma que eu criei para a minha monografia. À esquerda da janela principal, quatro imagens; à direita, uma janela para a exibição 3D. Assim:


Vou logo avisando que vai ficar bem diferente dessa de cima. No final eu explico por que. O objetivo desse tópico é basicamente mostrar o aninhamento dos gerenciadores de layout, utilizando a bagagem que foi adquirida até aqui.

Comecemos, então.


Codificação

O primeiro elemento da janela é uma barra de menu. Aqui tudo será simulado, então utilizarei um HorizontalFrame para a barra:
23   FXHorizontalFrame *menuBar = new FXHorizontalFrame(this,
24 LAYOUT_SIDE_TOP|LAYOUT_FILL_X|PACK_UNIFORM_WIDTH);

Os "menus" são simplesmente labels:
26   /* Menu Arquivo */
27 new FXLabel(menuBar, "&Arquivo");
28
29 /* Menu Imagens */
30 new FXLabel(menuBar, "&Imagens");

Agora vêm os aninhamentos. Na verdade, desde a primeira vez que colocamos um gerenciador de layout, fizemos um aninhamento, já que a própria janela já é um gerenciador de layout, mas aqui isso fica mais explícito.

Primeiramente, um frame horizontal representando o conteúdo da janela:
32   FXHorizontalFrame *contents = new FXHorizontalFrame(this,
LAYOUT_SIDE_TOP|LAYOUT_FILL|FRAME_NORMAL);

Eu gosto de definir os filhos imediatamente, formando realmente uma árvore no código (inclusive com indentação); acho que fica mais fácil saber quem é filho de quem, em vez de definir todos os filhos e depois os filhos dos filhos.

Sendo assim, o primeiro filho de contents é um frame vertical:
33     FXVerticalFrame *frameExam = new FXVerticalFrame(contents,
LAYOUT_FILL|FRAME_NORMAL);

Dentro dele, tem dois frames horizontais (que ficarão um sobre o outro); dentro de cada um deles, tem dois objetos do tipo FXFrame (que pode ser considerado um espaço vazio), que ficarão um do lado do outro:
34       FXHorizontalFrame *ccFrame = new FXHorizontalFrame(frameExam,
LAYOUT_FILL|FRAME_NORMAL);
35 new FXFrame(ccFrame, LAYOUT_FILL|FRAME_NORMAL);
36 new FXFrame(ccFrame, LAYOUT_FILL|FRAME_NORMAL);
37
38 FXHorizontalFrame *mloFrame = new FXHorizontalFrame(frameExam,
LAYOUT_FILL|FRAME_NORMAL);
39 new FXFrame(mloFrame, LAYOUT_FILL|FRAME_NORMAL);
40 new FXFrame(mloFrame, LAYOUT_FILL|FRAME_NORMAL);

O segundo filho de contents também é um FXFrame, apenas para ocupar o espaço:
42       new FXFrame(contents, LAYOUT_FILL|FRAME_NORMAL);


Resultado

Repetindo, o resultado é totalmente diferente do que foi mostrado acima. Com essa codificação, o que se obtém é isso:


Eu mandei a borda ser desenhada "afundada" justamente para que o aninhamento seja mais visível.


Discussão

O resultado ficou bem diferente do modelo por alguns motivos básicos.

Primeiramente, no modelo eu não utilizei somente FX(Horizontal|Vertical)Frame (não resisti à regex). Existem gerenciadores de layout bem mais propícios para uma interface como aquela.

Segundo, não alterei valores de espaçamento; por isso, dá para ver que as bordas ficam bem distantes umas das outras.

Terceiro, de contents para baixo, todos estão com a opção LAYOUT_FILL. Isso faz que o tamanho final de cada filho seja proporcional ao seu tamanho padrão em relação a seus irmãos. Como do lado esquerdo tem mais filhos, este ficou bem maior que o direito.

E quarto, para o modelo, eu defino explicitamente a largura dos contêineres das imagens (as áreas escuras) de acordo com as imagens carregadas. Tanto que, ao iniciar o programa, eles estão com a largura padrão, que é 1. Vejam:



Conclusão

Este tópico mostrou como é feito o aninhamento de gerenciadores de layout no FOX Toolkit. Espero ter ficado bem claro, pois é algo extremamente útil.

Utilizei nele poucos recursos porque achei melhor me limitar ao que já foi tratado até aqui. Entretanto, tudo o que foi dito aqui vale para qualquer outro gerenciador de layout. O FOX vem inclusive com um exemplo que diz "É claro que eles podem ser aninhados arbitrariamente." Creio que essa frase mostra bem o espírito da coisa.

Só uma observação final: FXFrame, ao contrário do que possa parecer, NÃO é um gerenciador de layout. Muito menos superclasse de FX(Horizontal|Vertical)Frame (como sugere o sufixo). É ele que desenha as bordas dos controles (grossa, fina, levantada, abaixada etc.).

FXFrame pode ser utilizado apenas como um "guarda-lugar" (placeholder), como foi feito aqui. Entretanto, é mais utilizado como classe-base para controles simples; por exemplo, FXLabel é derivado direto de FXFrame (e FXButton é derivado direto de FXLabel).


Um abraço e até a próxima.


---
Código-fonte para este tutorial.

2 comentários:

Edgar Diniz disse...

O código-fonte pode não estar disponível: devido a problemas de conexão, não consegui colocá-los no servidor.

Deixei o link apenas para não precisar editar o tópico; assim que possível, disponibilizarei o fonte.

Edgar Diniz disse...

Código-fonte já disponível