Neste tópico aqui, falei das dicas de layout (layout hints). Essas dicas são passadas para quem vai ficar dentro do gerenciador de layout. Por exemplo, quando eu pus um botão na janela (veja aqui), eu passei LAYOUT_FILL em suas opções, para que ocupasse a janela inteira.
Existem ainda outras opções que definem o layout, mas que devem ser passadas para o próprio gerenciador de layout. Essas opções determinam a forma de empacotamento dos filhos, e também são definidas em FXWindow.h. São elas:
Opção padrão: cada widget com seu tamanho. Nem precisa passar se for o caso (novamente, a não ser que você quiser maior clareza no código...).
PACK_UNIFORM_HEIGHT
Primeiramente, o gerenciador calcula o filho com maior altura. Depois, utiliza esse valor para todos os outros filhos, deixando todo mundo com a mesma altura.
PACK_UNIFORM_WIDTH
Da mesma forma, deixa todos os filhos com a mesma largura.
Essas duas últimas opções sobrepõem opções individuais dos filhos, como LAYOUT_FIX_WIDTH.
À medida que avançarmos em nossos tutoriais sobre gerenciadores de layout, mostrarei essas opções funcionando.
Neste caso, o alvo do meu evento é o próprio aplicativo, que pode ser recuperado chamando getApp(), presente em todas as classes derivadas de FXId (na prática, quase todas as classes FOX são; veja aqui a hierarquia de FXId).
A bem da verdade, nem seria necessário chamar esse método, já que estamos no construtor da janela, cujo primeiro parâmetro é a aplicação; bastava eu passar o ponteiro. Utilizei essa chamada aqui apenas para ilustrar.
O próximo parâmetro é o identificador da mensagem. Por convenção, sempre começa com ID_. Aqui eu passei ID_QUIT, que pertence à classe FXApp.
É só isso. Assim, eu conectei o botão à aplicação. Quando o botão envia um evento, a aplicação responde. Basicamente, é assim que os objetos se comunicam no FOX Toolkit.
Mas o que acontece lá dentro?
Bom, existem alguns detalhes a respeito disso. Com este exemplo, só posso dizer que o botão envia para a aplicação uma mensagem do tipo ID_QUIT, e a aplicação responde com a ação correspondente, ou seja, terminar a aplicação.
Futuramente, entrarei em detalhes e explicarei como funciona o mecanismo de comunicação entre os objetos FOX.
Só um detalhe, para o qual eu apanhei no começo e levei um certo tempo para descobrir o que era: eu criei um botão para fechar o aplicativo, mas em vez de passar o aplicativo, eu passei a janela. Resultado: a janela fechava, mas o aplicativo continuava executando... aí eu tinha que matar o processo.
As Layout Hints são opções passadas pelos widgets para os gerenciadores de layout que os contêm para informar algo a respeito de sua posição e tamanho. Assim como as opções de decoração (aqui), essas são apenas dicas; entretanto, os gerenciadores de layout farão o possível para atender aos pedidos.
A falta de algumas dicas quer dizer que o comportamento padrão deve ser utilizado, portanto muitas vezes não é preciso informá-las: as dicas do FOX Toolkit foram projetadas para que as situações mais comuns requeiram menos dicas. Por exemplo, normalmente os gerenciadores organizam seus filhos da esquerda para a direita, de cima para baixo, ou seja, não é preciso informar essas opções se esse for o caso.
Utilizados somente quando o gerenciador de layout for do tipo FXPacker, FXGroupBox ou FXTopWindow. Posiciona o widget junto à borda superior, inferior, esquerda ou direita, respectivamente.
LAYOUT_SIDE_TOP e LAYOUT_SIDE_BOTTOM reduzem a altura do espaço disponível, enquanto LAYOUT_SIDE_LEFT e LAYOUT_SIDE_RIGHT reduzem a largura.
Essas opções não têm efeito nenhum se utilizadas em outros gerenciadores de layout.
LAYOUT_FILL_COLUMN LAYOUT_FILL_ROW
Utilizados somente dentro de um FXMatrix.
Se todos os widgets de uma mesma coluna especificarem LAYOUT_FILL_COLUMN, então a coluna inteira é redimensionada se a matriz for redimensionada horizontalmente.
Da mesma forma, se todos o widgets de uma mesma linha especificarem LAYOUT_FILL_ROW, então a linha inteira é redimensionada se a matriz for redimensionada verticalmente.
LAYOUT_LEFT(default) LAYOUT_RIGHT
Posiciona o widget no lado esquerdo ou direito do seu contêiner, respectivamente. Quando utilizado em um FXPacker, FXGroupBox ou FXTopWindow, só fazem sentido se em conjunto com LAYOUT_SIDE_TOP ou LAYOUT_SIDE_BOTTOM.
LAYOUT_TOP(default) LAYOUT_BOTTOM
Posiciona o widget na parte de cima ou de baixo do seu contêiner, respectivamente. Quanto utilizado em um FXPacker, FXGroupBox ou FXTopWindow, só fazem sentido se em conjunto com LAYOUT_SIDE_RIGHT ou LAYOUT_SIDE_BOTTOM.
LAYOUT_FIX_X LAYOUT_FIX_Y
Podem ser usados nenhum, um deles ou ambos. Instruem o gerenciador a posicionar o widget exatamente na posição informada pelo construtor do objeto. (Veja este tópico)
LAYOUT_FIX_WIDTH LAYOUT_FIX_HEIGHT
Instruem o gerenciador a exibir o widget no tamanho especificado no construtor. (Veja este tópico)
Estes não precisam ser especificados nunca (a não ser para enfatizar o fato durante a leitura do código), pois este é o comportamento padrão. Faz com que o gerenciador exiba o widget com seu tamanho mínimo.
LAYOUT_CENTER_X LAYOUT_CENTER_Y
Centraliza o widget no gerenciador na direção especificada, adicionando espaço extra ao redor dele. O tamanho do widget será o padrão (o tamanho mínimo), a menos que seja informado explicitamente.
LAYOUT_FILL_X LAYOUT_FILL_Y
Faz com que o widget ocupe todo o espaço disponível no contêiner na direção especificada. Se um ou mais widgets forem posicionados no mesmo gerenciador com essas opções, o espaço é dividido proporcionalmente aos seus tamanhos mínimos.
Obs.: Essa regrinha acima não funciona para dois gerenciadores de layout lado-a-lado.
Confesso que não sei para que servem, e a documentação não fala nada a respeito.
LAYOUT_FILL
Apenas uma combinação deLAYOUT_FILL_X e LAYOUT_FILL_Y para conveniência.
LAYOUT_EXPLICIT
Outra opção de conveniência: combinação de LAYOUT_FIX_X, LAYOUT_FIX_Y, LAYOUT_FIX_WIDTH e LAYOUT_FIX_HEIGHT, ou seja, te dá controle total sobre a posição e o tamanho do widget.
Este tópico discute um pequeno detalhe a respeito do construtor dos widgets FOX. Serve para mostrar um dos pontos fortes do FOX Toolkit, a consistência, e também alguns aspectos que serão mostrados aqui servirão para tópicos futuros.
Alguns dele já foram explicados em tópicos anteriores, mas vou falar de todos aqui.
FXComposite *p
O componente que será o pai do widget criado. Serve para montar a hierarquia dos objetos FOX sem a necessidade guardar em um ponteiro e chamar algo do tipo p->add() (sem querer falar mal de outras linguagens...).
Normalmente é um gerenciador de layout.
Parâmetros específicos
Depois do dono do widget, vêm alguns parâmetros específicos. Por exemplo, para um botão (FXButton) esses parâmetros são o texto do botão e o ícone.
Naturalmente, nem todos os widgets terão parâmetros específicos, e a quantidade varia de widget para widget. Mas eles sempre vêm depois do dono e antes do alvo dos eventos (exceto para gerenciadores de layout).
FXObject *tgt
FXObject é o topo da hierarquia de classes do FOX Toolkit. Esse parâmetro indica que objeto irá receber os eventos disparados.
Se esse parâmetro é um FXObject, então qualquer objeto FOX pode receber eventos?
Sim. Não só receber como também enviar.
E só aproveitando o ensejo, aqui outra grande característica do FOX se revela: a capacidade de conectar os objetos entre si. Aqui essa conexão é estabelecida.
FXSelector sel
Além do alvo do evento, é preciso dizer qual é a mensagem que este widget envia. FXSelector nada mais é que um inteiro sem sinal.
Quando falarmos de tratamento de evento, esses dois parâmetros serão discutidos em mais detalhes.
Obs.: não estão presentes em gerenciadores de layout. Simplesmente porque eles não enviam eventos que o usuário queira tratar por conta própria.
FXuint opts
As opções do widget.
Alguns widgets possuem opções específicas. Por exemplo, um botão tem a opção BUTTON_TOOLBAR (entre outras, naturalmente) que faz com que ele tenha aparência achatada, levantando as bordas ao se passar com o mouse por cima (como o próprio nome diz, um botão da barra de ferramentas).
Aqui são passadas também opções de borda e de layout. No tutorial sobre criar um botão (aqui), eu criei um botão normal (ou seja, com borda levantada, grossa, com o texto centralizado e o ícone antes do texto) e que se expande pela janela inteira (uma opção de layout).
Todas essas opções são definidas por meio de enumerações e podem ser combinadas com o operador OU sobre bits ( | ).
FXint x, FXint y
Posição. O único detalhe é que essas coordenadas são em relação à janela pai (mãe?). Mas como os gerenciadores de layout se encarregam de posicionar seus filhos, raramente é necessário especificá-los manualmente.
FXint w, FXint h
Largura e altura do widget. Novamente, isso é controlado pelos gerenciadores de layout. Mas é mais comum precisar controlar o tamanho que a posição.
Normalmente não é necessário porque a maioria dos widgets sabe seu tamanho mínimo: um botão, por padrão, sempre vai ter um tamanho suficiente para exibir seu texto e ícone. Entretanto, alguns widgets não têm um tamanho mínimo: um FXCanvas, por exemplo, não tem nada dentro dele para calcular seu tamanho mínimo, então tem que dizer o tamanho dele (ou deixar que o gerenciador de layout o diga).
FXint pl, FXint pr, FXint pt, FXint pb
Bem, esses parâmetros servem para informar a quantidade de espaço entre sua borda e outros widgets. Se for um gerenciador de layout, define o espaço entre sua borda interna e os widgets (conforme já explicado aqui). Se for um widget folha (ou seja, não recebe nenhum filho na hierarquia), indica o espaço entre sua borda externa e outros widgets, conforme a figura a seguir:
Esses aqui é que são raros de especificar. Os valores padrões que eles apresentam dão praticamente sempre bons resultados.
FXint hs, FXint vs
Estes só estão disponíveis para gerenciadores de layout. Informam o espaço entre os seus filhos; também foi explicado aqui. E seus valores padrões também dão um resultado agradável.
No tutorial sobre ícones, eu falei que o ícone deve saber quem é seu aplicativo. Isto é correto.
Entretanto, logo em seguida eu disse que isso era para que o ícone fosse criado junto com o aplicativo. Não é bem assim.
Um aplicativo FOX (FXApp) não tem conhecimento dos ícones ou imagens. Então quem tem a responsabilidade de criá-los é exatamente quem vai utilizá-los, seja uma janela, um botão ou qualquer outro objeto que exiba um ícone/imagem.
Ou seja, se a minha janela tem um ícone, o create() da janela vai chamar o create() de seu ícone. E como ícones e imagens podem ser compartilhados, a eles é permitido chamar create() mais de uma vez.
Observe que os objetos FOX são organizados em uma hierarquia em árvore, em que os pais criam os filhos. Isso quer dizer que se eu instancio uma imagem e dou um dono para ela antes que esse dono tenha sido criado, essa imagem será criada junto com seu dono.
Se eu instanciar uma imagem depois que seu dono foi criado, é preciso chamar create() na imagem manualmente.
Bom, o objetivo desse tópico era apenas apresentar essa correção. No fundo, no fundo, as imagens são criadas junto com o aplicativo, que é a raiz da hierarquia. Só que as imagens não são filhas do aplicativo, como eu imaginei, sendo criadas automaticamente se, e somente se, tiverem algum widget que seja dono delas.
Retornando aos tutoriais básicos, falarei agora rapidamente sobre criar um botão na interface. Também os detalhes são diversos aqui, portanto este também é o primeiro tópico de uma série sobre os botões que o FOX Toolkit disponibiliza.
Neste primeiro tópico, criarei apenas um botão que se expande pela janela inteira e não está associado a nenhum evento (falarei mais tarde sobre tratamento de eventos).
FXButton é a classe FOX para um botão simples, que você pressiona, solta, e ele executa uma ação. Aqui eu instancio um novo objeto dessa classe. Novamente, sem a necessidade de atribuir a um ponteiro, pois a própria janela se encarregará de liberá-lo.
Os parâmetros que foram passados:
this: significa que o botão será colocado dentro da própria janela principal.
"Hello, &FOX!": texto que aparecerá no botão. O & significa a letra que servirá de mnemônico, no caso F. Assim, Alt+F é o atalho para pressionar o botão. Existem outros detalhes dentro do texto do botão, que serão discutidos mais adiante.
NULL: o ícone do botão. Aqui é criado um botão somente com texto, então fica nulo mesmo.
NULL: o alvo da mensagem. Como ele não lança nenhum evento, nulo.
0: a mensagem que o botão envia. Novamente, ele não lança nenhum evento: zero.
BUTTON_NORMAL|LAYOUT_FILL: opções do botão. BUTTON_NORMAL significa um botão com borda grossa e elevada, com o texto centralizado e o ícone à esquerda. LAYOUT_FILL significa que ele será expandido para ocupar a janela inteira. Esses detalhes serão explicados em seu devido tempo.
As demais opções referem-se à posição, tamanho e espaçamentos do botão, e normalmente não é necessário informá-los, pois têm valores padrões.
Resultado
Lembrando que FXMainWindow é um gerenciador de layout, redimensionar a janela fará com que o botão seja automaticamente redimensionado.
Todos os gerenciadores de layout do FOX Toolkit têm um preenchimento (padding) interior, que afasta seus widgets filhos das suas bordas de cima, baixo, esquerda e direita por uma certa distância em pixels.
Além do preenchimento, há também um espaçamento (spacing), que é a distância (em pixels) entre dois widgets dentro do mesmo gerenciador de layout.
Bom, acho que com um desenho fica mais fácil de entender:
PL - espaço entre os widgets e a borda esquerda do gerenciador
PR - espaço entre os widgets e a borda direita
PT - espaço entre os widgets e a borda superior
PB - espaço entre os widgets e a borda inferior
HS - espaço horizontal entre um widget e outro
VS - espaço vertical entre um widget e outro
Esses parâmetros (nessa ordem) são tipicamente os seis últimos parâmetros do construtor de um gerenciador de layout. Porém, são fornecidos valores padrões para esses parâmetros, ou seja, na maioria dos casos não será necessário informá-los.
DEFAULT_SPACING é uma enumeração definida em FXPacker.h (FXHorizontalFrame deriva diretamente de FXPacker):
enum{DEFAULT_SPACING=4};
Ou seja, ao se colocar widgets dentro de um FXHorizontalFrame, estes estarão distantes das bordas por quatro pixels, e distantes entre si também por quatro pixels (isto, claro, se os valores não forem informados, aceitando os padrões).
Em uma interface gráfica de usuário, é muito importante que layout seja bem atrativo. Informar manualmente as posições e dimensões de cada objeto dá ao programador total controle sobre a interface. Entretanto, essa abordagem tem duas desvantagens seriíssimas:
é uma tarefa tediosa e que consome muito tempo
se o tamanho da tela mudar, os objetos devem se adaptar a essas mudanças; se suas posições e dimensões forem absolutas, eles não se modificarão junto com a tela
Devido a isso, a maneira mais recomendada de se posicionarem objetos é utilizando os chamados Gerenciadores de Layout (Layout Managers). A tarefa principal de um gerenciador de layout é arrumar os objetos que estão dentro dele de alguma maneira específica. Existem diferentes gerenciadores, que organizam seus objetos de cima para baixo, da esquerda para direita, em forma de grade e até um por cima do outro. A maioria deles permite, também, que as posições e dimensões sejam informadas explicitamente.
As vantagens de se utilizarem os gerenciadores de layout incluem:
Evita a tarefa chata de posicionar os controles
Os controles são rearrumados automaticamente quando há mudanças no layout (por exemplo, o usuário aumenta o tamanho da fonte)
O layout é recalculado automática e inteligentemente quando o usuário redimensiona a janela
Fica mais fácil adicionar controles que são criados automaticamente dependendo do controle do programa, como por exemplo interfaces criadas com base em bancos de dados
Todos os gerenciadores de layout do FOX Toolkit são derivados de FXComposite. Isso significa que é possível aninhá-los arbitrariamente. Esse aninhamento dos gerenciadores adequados, junto com as opções de layout passadas tanto para os próprios gerenciadores quanto para os objetos que ficarão dentro deles é que definirá o arranjo da interface.
Gerenciadores de layout básicos
O FOX Toolkit vem com alguns gerenciadores de layout de propósito geral. Os principais são:
FXPacker: posiciona os objetos dentro de seu retângulo, grudandos-os a um dos lados (esquerdo, direito, superior ou inferior) e reduzindo o tamanho disponível de acordo. Por exemplo, se um objeto é posicionado à esquerda ou direita, a largura é reduzida; se for posicionado em cima ou embaixo, a altura é reduzida.
FXTopWindow: opera da mesma forma que o FXPacker; entretanto, não é utilizado diretamente, pois não tem um construtor público. É utilizado indiretamente através de FXMainWindow e FXDialogBox (duas subclasses diretas). Resumindo, toda janela que for criada (seja a principal ou uma caixa de diálogo) vai ter esse comportamento.
FXHorizontalFrame: organiza os filhos horizontalmente da esquera para direita (padrão) ou da direita para esquerda.
FXVerticalFrame: organiza os filhos verticalmente de cima para baixo (padrão) ou de baixo para cima.
FXMatrix: organiza os filhos em forma de grade, com linhas e colunas.
FXSwitcher: posiciona os filhos exatamente um em cima do outro, deixando apenas um deles visível
FXGroupBox: provê a mesma funcionalidade do FXPacker, além de adicionar bordas ao redor do conteúdo e um rótulo (label) opcional.
FXSplitter: divide a tela horizontal ou verticalmente em duas áreas; a divisão pode ser movida pelo usuário.
FX4Splitter: divide a tela em quatro partes; da mesma forma, o usuário pode modificar as divisões.
FXSpring: tipicamente colocada dentro de um FXHorizontalFrame ou FXVerticalFrame. A grande diferença do FXSpring para outros gerenciadores é que ele permite uma divisão da tela em proporções fixas, por exemplo, dividir uma janela em três partes nas proporções 1:2:1 (a janela do meio sempre será o dobro das outras duas).
Continua...
Esta é apenas a primeira parte de uma séries de tópicos relacionados aos gerenciadores de layout. Este é um assunto muito extenso, que ainda tem muito a ser discutido. Existem vários detalhes a respeito deles, e haverá tópicos específicos para cada gerenciador mostrado acima.
Além do FOX Toolkit, eu utilizo a biblioteca OpenCV (Open Source Computer Vision Library), pois trabalho com Processamento de Imagens. Então surgiu a necessidade de juntar os dois.
O OpenCV até fornece alguns recursos de interface gráfica, mas são muito limitados: apenas janelas, trackbars e tratamento de eventos de mouse e teclado. A próxima figura mostra uma janela com uma trackbar.
Quebrando, então, a seqüência de tutoriais básicos, vou ensinar como exibir uma imagem do OpenCV (IplImage) em um aplicativo FOX.
Para isso, criarei um aplicativo que abre uma imagem pelo OpenCV, exibe e aplica o filtro da média. Não vou falar da criação da interface e do tratamento de eventos, apenas mostrar como se faz a "conversão" de IplImage para FXImage.
Na declaração da classe, eu apenas declaro os ponteiros para as imagens:
Aqui, eu crio uma imagem temporária só para carregar a imagem do arquivo. Neste caso, ele abre uma imagem colorida com três canais de 8 bits.
A representação interna do IplImage é um vetor de caracteres e os pixels são armazenados em BGR.
A representação interna do FXImage é um vetor de FXColor (equivalente a um inteiro sem sinal). Em cada inteiro são armazenados quatro canais (um byte para cada): RGBA.
Bom, aí já temos uma semelhança: ambos armazenam em um vetor. Isso que dizer que eu posso aproveitar o vetor de pixels do IplImage e jogar dentro do FXImage. Basta converter a representação interna.
Então, cria-se uma IplImage com quatro canais e profundidade de 8 bits sem sinal. Esta é a que foi declarada em nossa classe.
Assim, já temos uma IplImage com representação interna parecida com a de FXImage. É preciso ainda converter de char* para FXColor*. Essa não é uma conversão padrão, portanto é preciso usar um operador especial para isso.
Eu acho até dolorido usá-lo, mas não vi outra alternativa.
Como a imagem foi criada depois do aplicativo, é preciso chamar create() manualmente.
Manipulando a imagem
Agora, temos um FXImage com o vetor de pixels compartilhado com o IplImage. Isso significa que qualquer operação executada sobre a imagem Ipl refletirá na imagem FX.
Isso é demonstrado aqui, onde eu aplico o filtro da média para suavizar a imagem:
Os únicos detalhes é que é preciso chamar render() de FXImage e atualizar o imageView.
O render() é necessário porque há duas representações do FXImage: uma do lado do cliente, que neste caso é o vetor compartilhado entre as duas imagens, e o lado do servidor gráfico. render() atualiza o lado do servidor gráfico, de forma que seja exibida a imagem modificada.
E é preciso atualizar o imageView porque ele não detecta automaticamente alterações na imagem, então é preciso informar manualmente que ele deve se redesenhar.
Trabalhando com vídeos
O OpenCV, além de imagens estáticas, também trabalha com vídeos, que podem ser capturados de câmeras ou lidos de arquivos.
Cada quadro do vídeo é recuperado em um IplImage. Isso significa que dá para usar a técnica descrita acima. O problema é que a imagem que representa cada quadro não pode ser deletada nem modificada. Isso significa que para cada quadro do vídeo, é preciso fazer a conversão para uma outra imagem.
Seria mais simples se desse para modificar a imagem retornada, assim dava para compartilhar os pixels sem a necessidade de uma imagem extra.
Infelizmente, não tenho nenhum exemplo a mostrar com vídeos.
Quando falei sobre criar a janela principal (aqui), citei alguns aspectos relativos às decorações da janela e seu posicionamento, informando que isto era definido em FXTopWindow.h, onde está definida a superclasse direta de FXMainWindow.
Falarei agora especificamente desses dois assuntos.
Decorações
As decorações são itens "extras" que o seu decorador de janelas acrescenta. São as bordas da janela, barra de título, botões de minimizar, maximizar, fechar, menu da janela etc. FXTopWindow.h define a seguinte enumeração:
Apesar de serem bem intuitivos os nomes, vou explicá-los:
DECOR_NONE: Janela sem bordas, sem nada, só com o conteúdo. Se parecer inútil, pense em uma janela em modo tela cheia.
DECOR_TITLE: Título da janela.
DECOR_MINIMIZE: Adiciona a capacidade de minimizar a janela.
DECOR_MAXIMIZE: Adiciona a capacidade de maximizar a janela.
DECOR_CLOSE: Adiciona a capacidade de fechar a janela.
DECOR_BORDER: Adiciona bordas à janela.
DECOR_SHRINKABLE: Possibilita diminuir o tamanho da janela.
DECOR_STRETCHABLE: Possibilita aumentar o tamanho da janela.
DECOR_RESIZE: Permite aumentar ou diminuir a janela. Perceba que é apenas uma combinação das duas anteriores para facilitar.
DECOR_MENU: Habilita o menu da janela.
DECOR_ALL: Já conhecido, habilita todo mundo.
Agora a pergunta: se é tão intuitivo, porque explicar cada um? Simples. Essas são apenas sugestões para o decorador de janelas. Não são regras.
Isso quer dizer que, se o decorador achar melhor desenhar um item que você não especificou, ele desenha. Por isso eu não falei "Desenha isso", "Desenha aquilo", mas sim "Adiciona a capacidade", "Habilita". Por exemplo, para exibir o botão de fechar, tem que ter a barra de título (e com certeza as bordas vêm de brinde). Acontece também de se especificarem somente os botões de minimizar e fechar, mas o de maximizar aparece junto, desabilitado.
O que eu quero dizer é que cada decorador tem suas regras próprias, e que essas são apenas sugestões. Mas tenha certeza que o que você especificar ele faz. E se não especificar, também não faz; ou seja, se você não quer que a janela aumente de tamanho nem maximize, ela não irá, embora o botão de maximizar esteja lá (desabilitado, claro).
Não quero dizer, por outro lado, que você deva confiar sempre nos itens que vêm de "brinde". Especifique sempre os que você quer ter certeza que estejam disponíveis.
Posicionamento
Para mostrar a janela, chamei o método show(), passando PLACEMENT_SCREEN como parâmetro, exibindo no meio da tela. As opções de posicionamento são:
PLACEMENT_DEFAULT: No tamanho e posição que foram especificados no construtor.
PLACEMENT_VISIBLE: Posiciona a janela para ficar totalmente visível. Confesso que nunca usei...
PLACEMENT_CURSOR: Posiciona onde está o cursor do mouse.
PLACEMENT_OWNER: Posiciona no centro da janela dona desta. Quando adicionarmos mais janelas, esta opção será utilizada.
PLACEMENT_SCREEN: Já conhecido, posiciona no centro da tela.
PLACEMENT_MAXIMIZED: Deixa a janela do tamanho da tela. Mas tem uma ressalva.
O PLACEMENT_MAXIMIZED realmente deixa a janela do tamanho da tela. Porém, dependendo do decorador (sempre ele...) as bordas vão todas embora. Dos que eu já usei (foram só três, mas tudo bem), só o Emerald (sempre ele...) preservou as bordas, deixando a janela do jeito que se imagina que uma janela maximizada deva ser. O decorador do Windows (não sei o nome) e o gtk-window-decorator (decorador padrão do GNOME) sumiram com as bordas.
E se eu quiser que a janela já inicie maximizada, com borda e tudo?
O que seria uma interface gráfica sem eles? Neste tutorial ensinarei a colocar ícones na janela (tanto o pequeno quanto o grande). Claro que ícones no FOX não servem apenas para isso, mas como eu só falei da janela principal, é lá que vamos colocá-los.
Um breve histórico
Acrescentar um ícone na interface FOX era bem trabalhoso. Primeiro, era preciso converter a imagem em um vetor (sim, um vetor estilo C) de pixels utilizando um programa chamado reswrap, distribuído junto com o FOX Toolkit. Sua sintaxe era:
Assim, criavam-se dois arquivos, um icons.h com a declaração dos vetores, e um icons.cpp com o conteúdo deles. Era uma coisa monstruosa.
Todo este trabalho foi aliviado com a chegada de uma classe mágica: FXIconSource. Mas vamos ao código. Vou exibir aqui apenas as modificações relativas ao tutorial anterior.
39: Cria um objeto da classe FXIconSource. Apesar do nome, serve também para carregar imagens. Mas vamos com calma. Cada ícone deve saber quem é sua aplicação, portanto o IconSource já deve vir com essa informação. Serve para que eles sejam criados junto com a aplicação.
41: Carrega um ícone do arquivo, retornando um ponteiro para o ícone. 42: Idem, mas além de carregar, escala o ícone para que nenhuma de suas dimensões exceda o valor estabelecido (no caso, 16 pixels).
45-48: Nosso destrutor. Conforme dito acima, precisamos destruir manualmente nossos ícones. delete é o suficiente para isso.
Resultado
Considerações finais
Por que GIF?
Apenas dois motivos: é suportado nativamente pelo FOX Toolkit e suporta transparência. Mas nada impede de usar outros formatos.
Créditos
Destaque de sintaxe provido por Code2HTML, v. 0.9.1
Já que nosso último tutorial foi sobre criar uma janela vazia, usando FXMainWindow, falarei agora especificamente sobre essa classe.
Descrição
A MainWindow é normalmente a janela central de uma aplicação. Aplicações podem ter qualquer número de janelas principais.
Quando uma MainWindow é fechada, ela envia uma mensagem SEL_CLOSE para o seu alvo; o alvo deve retornar 0 se não houver nenhuma objeção contra o fechamento, e 1 caso contrário.
Depois que a mensagem SEL_CLOSE for enviada e nenhuma objeção for levantada, a janela principal deletará a si mesma.
1: A classe FXMainWindow é derivada de FXTopWindow. Por isso ela é pequena desse jeito, toda a funcionalidade dela é herdada das superclasses. E a hierarquia não é pequena:
Obs.: Em tópicos deste tipo, tratarei de apenas uma classe, ou seja, vou me limitar ao que a declaração da classe apresenta.
Ícone grande, que aparece quando se troca de janela com Alt+Tab
Ícone pequeno, que aparece no canto superior esquerdo da janela
FXuint opts - Opções da janela. Essas opções referem-se às decorações da janela, e são definidas em FXTopWindow.h. Chegaremos lá.
FXint x, FXint y - Posição inicial da janela.
FXint w, FXint h - Largura e altura da janela.
FXint pl, FXint pr, FXint pt, FXint pb - Espaçamento entre os componentes e a borda da janela. Uma MainWindow é um gerenciador de layout (layout manager), portanto aceita esses parâmetros. Quando falarmos de gerenciadores de layout, explicarei melhor.
FXint hs, FXint vs - Espaçamento entre um componente e outro. Idem.
Percebam que apenas a aplicação e o título da janela são obrigatórios. Todos os outros parâmetros têm valores default, ou seja, podem ser omitidos. Outra vantagem do FOX Toolkit: os parâmetros default asseguram um layout agradável aos olhos.
Observações
A descrição da classe foi retirada da própria documentação de referência.
O gráfico de herança foi desenhado com o programa Dia.
Blog criado por um entusiasta do FOX Toolkit. Aqui você encontrará dicas, tutoriais e várias informações sobre essa biblioteca de classes escrita em C++ para construção de interface gráfica do usuário.