Documentação do Tdk
|
Tutorial
/ Módulo de Interface com o Usuário
|
Este tutorial tem como objetivo apresentar o
módulo interface com o usuário, mostrando exemplos práticos de suas
funcionalidades e observando suas particularidades.
|
|
Em construção a seção 4 !!!
|
|
Introdução
|
Este capítulo do tutorial apresentará os controles
de interface gráfica de usuário. Ou seja, apresentará os widgets
(ou controles). Um widget é um elemento da interface que o usuário
interage como um canvas, uma janela, uma caixa de texto, um botão, um menu,
etc.
A aplicação de exemplo que vamos utilizar neste tutorial é o VIPE (Visualização,
Impressão, Processamento e Edição). Ele foi feito para testar
as funcionalidades implementadas no Tdk.
Esta etapa do tutorial está dividida em 5 seções:
|
Seção 1
|
Na primeira seção, você conhecerá as funcionalidades implementadas no VIPE.
Seguiremos os seguintes passos:
-
Instalação do VIPE
-
Visualização de um projeto exemplo no VIPE
-
Apresentação dos modos da aplicação: mapa, layout e impressão
-
Utilização da legenda
-
Ligar e desligar tema
-
Selecionar tema
-
Criar tema
-
Enquadrar tema
-
Mudar estilo dos objetos do tema
-
Mudar as propriedades do tema
-
Excluir um tema
-
Mover (para cima e para baixo) um tema
-
Apresentação das principais funcionalidades do modo de mapa:
-
Zoom, pan, fit, seleção de objeto
-
Inserir um objeto. Mostraremos como exemplos de objetos: ponto, linha, polígono
e texto.
-
Apresentação das principais funcionalidades do modo de layout:
-
Zoom de papel, zoom no objeto mapa, pan, fit
-
Inserir um objeto. Mostraremos como exemplos de objetos: ponto, linha,
polígono, texto, imagem.
-
Arrastar, redimensionar e rotacionar um objeto
-
Como imprimir utilizando o modo de impressão
|
Seção 2
|
Na segunda seção, você aprenderá os conceitos básicos para interação com o
canvas
-
Árvore VIX
-
Árvore de eventos TDK
-
Definição
-
Tratamento de eventos (mouse click, mouse move e teclado) na árvore
-
Estado de Aplicação
-
O que é um estado de aplicação
-
Como criar um novo estado de aplicação
-
Como registrar um estado de aplicação
-
Como criar um novo interador e uma nova tarefa
|
Seção 3
|
Na terceira seção, mostraremos como utilizar o TDK no modo de layout e
de impressão.
-
Introdução
-
Exemplo de Criação de Novo Tipo de Objeto de Layout
-
Criação do Novo Tipo de Objeto de Layout
-
Utilização do Novo Tipo de Objeto de Layout - Criação e Registro de Estado de
Interação, Criação de Tarefa e Criação de Interador
|
Seção 4
|
Na quarta seção, mostraremos como utilizar o TDK no modo de mapa
|
|
Seção 1 - VIPE
|
Nesta seção do tutorial veremos algumas
funcionalidades do VIPE, através da descrição de etapas que vão desde a
instalação da aplicação até a manipulação de objetos de um projeto.
|
1.1) Instalando e Executando o VIPE
|
Considerando que SVN_ROOT é o diretório onde foi feito o checkout do
tdk pelo svn, o arquivo de solução que deve ser compilado é o SVN_ROOT\iupvipe\mak.vc71\iupvipe.sln.
Temos então que compilar o arquivo da solução utilizando o Visual Studio
.NET 2003. Para isso, acesse o menu Build -> Build Solution e
aguarde a compilação das bibliotecas.
Para executar o VIPE pelo Visual Studio, após a compilação, aperte a tecla "F5"
ou acesse pelo menu: Debug -> Start.
Para executar fora do Visual Studio, clique duas vezes no nome do arquivo
SVN_ROOT\bin\mtdebug\vc71\iupvipe\iupvipe.exe (conforme a figura abaixo). Este
arquivo foi gerado na compilação do projeto usando o Visual Studio.
|
|
1.2) Visualização de um projeto
exemplo no VIPE
|
Agora com o VIPE executando precisamos nos conectar a banco de
dados de exemplo. Utilizaremos neste tutorial o banco de dados ALPHA_Sergipe_2006_V1_04.mdb
localizado no link disponibilizado.
|
|
Para se conectar com o banco clique em Arquivo -> Conectar
-> Access. Veja na figura abaixo.
|
|
Selecione então o banco no diretorio especificado.
|
|
Após a escolha do banco de dados, precisamos especificar o
projeto que será utilizado. O projeto será o TerraEditProject.
|
|
O projeto será aberto e uma tela como a
imagem a seguir será apresentada:
|
|
1.3) Os modos da aplicação: Mapa,
Layout e Impressão
|
O VIPE possui três modos de visualização do projeto, cada um com suas
respectivas funcionalidades, são eles: modo de visualização (ou modo mapa),
modo de layout, e modo de impressão.
O modo mapa é utilizado para visualização
e edição de objetos geográficos, ou seja, é possível manipular tanto a
geometria dos objetos quanto seus atributos.
O modo de layout é utilizado
para preparar a impressão ou geração de uma carta cartográfica. Neste
modo é possível mexer em um "papel" que tem o mapa fazendo operações
de zoom e de rotacionar. Uma carta cartográfica é composta
basicamente do mapa e de informações relacionadas a este mapa como
legenda, norte (rosa dos ventos), escala gráfica, etc.
O modo de impressão permite a impressão do
que foi definido através do layout. Ele funciona como um print
preview, retratando exatamente o que do modo de layout será impresso.
Ao abrir um projeto no VIPE, ele
o apresentará no modo de mapa. Para alternar entre os modos basta
selecionar os botões referentes a cada um deles localizados no canto inferior
direito da tela, conforme indicado na figura abaixo. Observe que para cada modo
de visualização teremos funcionalidades ativadas ou desativadas.
|
|
Estaremos apresentando as principais funcionalidades dos três modos.
|
1.4) Utilizando a Legenda
|
A legenda é a visualização dos metadados de
um projeto. Ela é apresentada no canto esquerdo da tela da
aplicação, representando os objetos que compõe o projeto.
Um projeto é composto por visões (View). NO VIPE é
possível ver apenas um projeto com uma visão.
Uma visão por sua vez é composta por temas
ou grupos de temas.
O VIPE permite agrupar os objetos de um tema para
visualizá-los em um mapa temático. O agrupamento é feito por atributos. Se
for um atributo numérico por exemplo, o agrupamento pode ser feito por valor ou
por intervalos.
Na figura ao lado, o projeto possui a visão "Mapa1".
A visão por sua vez possui, o tema "Setas" e o grupo de temas "Recursos
Socioeconômicos", e o tema "Toponímia" dividido em temáticos.
(A definição de projeto, de Visão e de temas, pode
ser encontrada no capítulo Modelo de
Dados do Tdk)
|
|
|
|
Principais Funcionalidades:
Para ligar e desligar um tema basta clicar duas vezes sobre um
tema específico com o botão esquerdo do mouse. Outra forma é clicar com o botão
direito sobre o tema e selecionar Exibir/Esconder Tema(s). É
interessante observar as alterações no mapa da visão após ligar ou desligar um
tema. Os grupos de temas também podem ser ligados e desligados apenas com o
duplo click. Já os temáticos não podem ser ligados ou desligados.
Para selecionar um tema, clique com o botão direito sobre
o tema e selecione a opção Selecionar Tema. Note que os
temáticos e os grupos de temas não podem ser selecionados.
Para criar um tema, clique com o
botão direito do mouse sobre a view e selecione e opção Novo tema. A
tela seguinte aparecerá.
Na tela de criação de tema, devemos especificar o nome do novo tema, selecionar
a sua view correspondente e o seu Layer.
Podemos Também criar uma restrição sobre os campos de tabelas do Layer
selecionado. Para isso utilizamos o campo Restricao SQL. Ao clicar-mos
no botão Editar Restricao uma nova janela surgirá com ferramentas para
auxiliar a composição da restrição.
|

Criando
tema
Editando Restrição SQL
|
Para enquadrar um tema da view, basta clicar com o botão
direito do mouse sobre o tema e selecionar a opção Enquadrar Tema .
O VIPE também nos permite alterar
o estilo dos objetos de um tema (ponto, linha, polígono
e texto). Para isso clique com o botão direito do mouse sobre um tema e
selecione a opção Estilo de Objetos. Também é possível editar apenas
aos estilos de objetos selecionados. Para isso na visão mapa clique sobre um
objeto para selecioná-lo e agora sobre o tema clique com o botão direito e
selecione a opção Estilo de Objetos Selecionados.
|
|
Para excluir um tema da view, basta clicar com o botão direito
sobre a view desejada e selecionar a opção Excluir. Uma mensagem de
Alerta aparecerá pedindo a confirmação da operação.
Para mover um tema para cima ou para baixo na estrutura da
visão, basta clicar com o botão direito sobre o tema e selecionar uma das
opções Mover para Cima ou Mover para baixo. Os grupos de
temas também podem ser movidos dentro da estrutura da view do projeto e
os temáticos pode ser movidos "para cima" ou "para baixo" na estrutura do
tema.
|
1.5) Principais funcionalidades do
modo mapa:
|
Zoom
|

|

|
A primeira ferramenta realiza o zoom da imagem, considerando um
ponto ou uma área especificada pelo usuário (posição da lupa).
Para determinar uma área para zoom, com a ferramenta selecionada clique,
arraste o mouse e solte-o.
|

|
Realiza a redução do zoom, considerando o ponto especificado pelo
usuário (posição da lupa) como o centro da operação.
|

|
A terceira ferramenta, que também possui o nome de "mais zoom",
realiza a mesma operação que a lupa de "mais zoom", mas considerando como ponto
para a operação o centro da tela e não uma posição ou área especificada pelo
usuário.
|

|
Realiza a operação de "menos zoom" considerando como ponto para a
operação o centro da tela e não uma posição especificada pelo usuário.
|
Pan
|

|

|
Move o mapa da visão para a esquerda.
|

|
Move o mapa da visão para a Cima.
|

|
Move o mapa da visão para a Baixo.
|

|
Move o mapa da visão para a direita.
|

|
Move o mapa para uma posição determinada
pelo usuário.
Com a ferramenta selecionada clique sobre o mapa da visão e arraste o mouse até
a posição desejada.
|
Fit
|

|

|
Serve para se obter uma visão geral de todo o mapa (todo o mapa é
enquadrado na tela).
|

|
Altera a visão do mapa realizando zoom nos objetos selecionados e
enquadrando-os na tela.
Veremos adiante como selecionar um objeto no modo mapa.
|
Seleção de objeto
|

|

|
Com a ferramenta "Selecção de Objetos"(seta) selecionada clique
com o botão direito sobre um objeto no mapa da visão e selecione a opção Seleciona
o Objeto.
|
|
Selecionando área para
zoom
Selecionando Objeto
|
|
Para os exemplos de inserção de objetos criaremos
um tema de exemplo (nome "Exemplo") na visão "Mapa1" seguindo as etapas de
criação de tema já esplicados (item 1.4 Utilizando a Legenda), não sendo
necessária a definição de restrições sql.
Para a inserção de novos objetos, é necessário que um tema esteja selecionado,
por tanto antes de prossegir selecione o tema de exemplo criado
Ao clicar no Menu Inserir serão apresentados os tipos de objetos que
podem ser inseridos (ponto, linha, polígono e texto).
|
|
Para inserir um ponto selecione Inserir -> ponto
e clique em uma posição do Mapa para desenhar o objeto.
Para inserir uma linha selecione Inserir -> Linha.
Cada Clique com o botão esquerdo do mouse irá inserir um ponto da linha no
mapa. Para terminar o desenho clique com o botão direito do mouse.
Para inserir um polígono selecione Inserir ->
Polígono. Assim como no caso da linha, cada clique com o botão
esquerdo do mouse irá inserir um novo ponto do polígono. Para terminar o
desenho clique com o botão direito do mouse.
Para inserir um texto selecione Inserir -> Texto. Clique
na área do mapa onde o texto será inserido. Aparecerá então um tela para a
entrada da mensagem texto.
|
1.6) Principais funcionalidades do
modo de layout:
|
É interessante observar que o modo de layout possui duas representações do mapa.
A maior representa a visão do mapa no modo mapa. A menor apresenta uma visão de
todo o mapa, apresentando uma área hachurada em vermelho que é correspondente
ao mapa da representação maior.
Zoom de papel
|
Os botões de zoom de papel possuem funções análogas as do zoom de
mapa, só que estas se aplicam ao papel representado no modo de layout, ou seja
a toda a área de visão do modo de layout e não apenas ao mapa.
|

|
A primeira ferramenta realiza o zoom da imagem, considerando um
ponto especificado pelo usuário (posição da lupa). Note que, como ja explicado,
é realizado um zoom sobre o ambiente de layout e não sobre o mapa da visão (o
mesmo vale para todas as operações de zoom de papel).
|

|
Operação inversa da anterior, realiza a redução do zoom,
considerando o ponto especificado pelo usuário (posição da lupa) como o centro
da operação.
|

|
A terceira ferramenta, que também possui o nome de "mais zoom",
realiza a mesma operação que a lupa de "mais zoom", mas com ela o ponto de zoom
é o centro da tela e não um ponto determinado pelo usuário.
|

|
Realiza a operação de "menos zoom" considerando o centro da tela
e não um ponto especificado pelo usuário.
|
Zoom no mapa
|

|
|
Possuem as mesmas funcionalidades das apresentadas no módulo
mapa, só que no modo layout, para utiliza-las é preciso primeiro selecionar o
mapa, ou seja a representação maior do mapa da visão. Para selecionar o mapa
utilize a ferramenta "seta" . Mais
uma vez é interessante observar o mapeamento da visão selecionada sobre a visão
total do mapa, apresentada pelo mapa menor do modo de layout.
|
Pan:
|
|

|
Assim com no caso do zoom, a funcionalidade do botão pan do modo
layout é análoga a funcionalidade do botão mover mapa, mas voltada para
realizar modifições no ambiente da visão do layout e não no mapa.
Move a visão do modo de layout para uma posição determinada pelo usuário. Com a
ferramenta selecionada clique sobre a visão do layout e arraste o mouse até a
posição desejada.
As fucionalidades de pan do mapa assim como o zoom, podem ser utilizadas no
modo layout, selecionando a representação do mapa na visão.
|
Fit:
|
|

|
Serve para se obter uma visão geral de todo o modo layout (todo o
layout é enquadrado na tela).
Funcionalidades de fit no mapa selecionando a representação da visão, assim
como explicado para as outras funcionalidades.
|
|
Exemplo Zoom de papel
|
Exemplo Zoom no
Mapa Layout
Exemplo Pan Layout
|
O modo de layout além da opção de inserir objetos
através do menu Inserir, apresentado no modo mapa, possui botões para
realizar estas operações.
Os objetos podem ser criados em qualquer parte do ambiente do modo de layout,
não apenas no "papel", e possuem as mesmas funcionalidades das opções do menu Inserir.
|
Exemplo inserção Texto, Ponto, Linha e Polígono.
|
Além dos tipos de objetos já falados, O modo
de layout possui a funcionalidade inserir figura, veja que
agora a opção Figura no menu Inserir está ativa.
Assim como para a inserção dos outros objetos o modo de mayout disponibiliza um
botão para acesso rápido à funcionalidade de inserir figura .
Após clicar no botão clique na área do ambiente do modo de layout. Aparecerá
então uma tela solicitando informações da figura a ser inserida. Após a
confirmação a imagem será desenhada.
|
Opção Menu Inserir Figura
|
Selecionar Figura
|
|
Exemplo desenho Figura
|
|
Para arrastar um objeto do modo layout selecione a
ferramenta de seleção ("seta"), clique e mantenha pressionado o botão esquerdo
do mouse sobre o objeto, arraste o mouse até a posição desejada e então libere
o botão.
Exemplo arrastando um Polígono:
|
|
|
|
Observe que com a ferramenta de seleção ("seta"), ao clicar sobre um
objeto, oito pontos aparecem ao redor de sua caixa de seleção.
Para redimensionar um objeto basta clicar sobre um
destes pontos, arrastar o mouse até que a figura fique com a forma desejada e
então libere o botão.
|
|
|
|
Como já comentado, ao clicar sobre um objeto com a ferramenta de
seleção "seta" oito pontos aparecem ao redor de sua caixa de seleção. Ao clicar
novamente sobre o objeto estes pontos mudam de formato, circulo, o que indica a
mudança de funcionalidade.
Para rotacionar um objeto então, clique sobre um dos
pontos em formato de círculo, arraste o mouse até a posição desejada e então
libere o botão.
|
|
|
|
1.7) Como imprimir utilizando o modo
de impressão:
|
Observe que ao mudarmos o modo de visualização do projeto para o modo
de impressão, o botão da impressora fica ativo.
|
|
Para imprimir então a visão do layout no modo de impressão, basta
clicar neste botão e então será apresentado o assistente para as prefências de
impressão.
|
|
|
Seção 2 - Interação
com o Canvas
|
2.1 A Arquitetura VIX |
Os sistemas gráfico-interativos que utilizam o TDK utilizam diversas
ferramentas que facilitam a sua construção, como bibliotecas gráficas
(p.ex. [Nye90, TeC89, TeC96c]) e de interface (p.ex. [Ope91, Pet, LdFG+96]). Os
sistemas de interface suportam, normalmente, um conjunto padronizado de objetos
(widgets) que oferecem o que já foi chamado de "um pouco mais que um
sistema de menus glorificado" [MR93].
Com a necessidade de utilização de dois sistemas, as
aplicações gráfico-interativas lidam, em geral, com uma dicotomia: uma
biblioteca se propõe a fornecer primitivas de desenho para a representação
visual dos objetos particulares da aplicação, e outra os widgets e
eventos de interface para dar suporte a interação. Como consequência dessa
dicotomia, o programador precisa, muitas vezes, combinar esses dois sistemas no
nível da aplicação, tendo que lidar com paradigmas diferentes.
Uma forma de minimizar a dicotomia entre os sistemas gráficos e de interface vem
do conceito de objetos visuais interativos [BCCI94, CI95]. Sucintamente, tais
objetos são entidades da aplicação que são exibidas e manipuladas pelo usuário.
Além disso, encapsulam, em um único tipo abstrato de dados, suas representações
e comportamentos, facilitando sua programação de forma modular e reutilizável.
A implementação do conceito de objetos visuais interativos pode ser feita
sob uma arquitetura que defina um protocolo extensível de interação
usuário-objetos. Uma vez implementada essa arquitetura, um objeto pode ser
tratado como um componente de software que, uma vez confeccionado, pode ser
reutilizado por diversas aplicações. Ao reutilizar comportamentos de objetos,
as interações de manipulação direta podem ser tratadas por um protocolo
genérico que se aplique a qualquer tipo de objeto. Logo, uma vez construídas
essas interações, elas também podem ser guardadas para reuso em outros
programas.
Com a confecção deste tipo de arquitetura, programas com recursos
gráfico-interativos podem ser construídos de forma reutilizável, modular e sem
ter que lidar com dois paradigmas distintos. Seguindo esta idéia, [Santos,
2005] propôs a arquitetura VIX, um framework para
suporte a objetos visuais interativos.
O VIX utiliza o termo visual object, ou
simplesmente VO, para tratar objetos visuais. O conceito de VO
modela objetos gráficos ativos que oferecem métodos de desenho e de resposta a
ações do usuário. O tratamento desses objetos não é restrito somente
aos objetos gráficos de uma aplicação. Pode-se entender como VO qualquer objeto
que possua uma representação e um comportamento. A funcionalidade mínima de um
VO é a sua capacidade de responder a determinadas ações e saber
representar-se gra camente. Desta forma, sua interface contém somente ações de
respostas ao usuário e de redesenho, ou seja, feedback de suas
alterações.
Dado que um objeto visual é determinado por seu comportamento e
representação, é necessária a existência de uma entidade que transmita os
eventos do usuário e ofereça recursos para que o objeto seja desenhado. O
conceito de espaço visual/ visual space, ou
simplesmente VS, mapeia entidades que transmitem
eventos para VOs e fornecem uma superfície de visualização onde eles são
posicionados. Os VSs devem ser encarados como elementos de ligação entre o
usuário e o VO que ele está manipulando, de forma que o usuário enxerga e
manipula seu objeto através de recursos do VS.
|

|
No processo de comunicação entre estes objetos, são utilizadas mensagens. Através
delas, os objetos podem trocar dados uns com outros (o VO deve saber
responder às requisições do VS). O envio de mensagens é feito
pelos métodos sendVO ou sendVS.
A aplicação do método send em uma mensagem implica no envio desta para
o tratador do objeto envolvido. Os métodos handlers
, por sua vez, retornam se a mensagem foi tratada ou não.
Os filtros servem para modelar objetos que fazem a
interface entre um VS e um VO. Um filtro repassa para o seu VO associado os
eventos gerados em seu VS, podendo dar algum tratamento especial a esses
eventos.
|
2.2 Árvore de Eventos |
|
Com o intuito de tratar os eventos de maneira uniforme, independente do tipo de
ação que ele irá ocasionar, o TDK implementa a arquitetura VIX para dar suporte
ao tratamento de eventos das aplicações. A implementação no TDK é chamada de
árvore de eventos. Esta árvore possui os
nós esquematizados na figura seguinte e classificados da seguinte forma:
|
Nó |
Classe |
Descrição |
Controle da Aplicação
|
TdkApplicationController |
gerencia a estrutura da árvore de eventos
|
Controle de Interação
|
TdkInteractorController |
capta eventos no handle do canvas |
Controle de Modo
|
TdkModeController |
gerencia um modo de operação do TDK |
Interador
|
TdkInteractor |
traduz os eventos de mouse e teclado em informações de interação |
Tarefa
|
TdkTask |
executa uma funcionalidade bem definida para tratar um evento que trafega pela
árvore |
Visualizador
|
TdkDisplay |
realiza operações de manipulação (como zoom, pan e fit) de visualização no
canvas e desenha objetos no canvas de acordo com o modelo de dados |
Objeto
|
TdkObject
|
representa um objeto da camada de modelo de dados do Tdk.
|
|
A aplicação possui apenas uma instância da classe do Controle da Aplicação
e uma instância da classe do Controle de Interação. Já o Controle de
Modo varia de acordo com o modo da aplicação do Tdk, que atualmente pode
ser de três tipos: Controle de Modo de Mapa, Controle de Modo de Layout e
Controle de Modo de Impressão.
A classe TdkApplicationController é responsável por fazer a troca
de estado da aplicação e a troca de modo de operação.
A classe base que representa todos os interadores presentes no TDK é a TdkInteractor. Para
criar um novo interador basta criar uma classe que estenda TdkInteractor
e sobrescrever os métodos de captura de eventos, handleVSEvent e handleVOEvent
(estes métodos serão explicados abaixo). Dado um determinado estado da
aplicação (explicado abaixo), é de responsabilidade do interador traduzir
uma sequência de eventos básicos em um evento mais sofisticado que define
exatamente o que o usuário deseja que o sistema faça. Por exemplo,
ao acumular uma sequência de eventos de mouse click e mouse move,
o interador a traduz em um único evento de zoom in a ser
repassado para as tarefas responsáveis por sua execução.
A classe base que representa todas as tarefas presentes no TDK é a TdkTask.
Para criar uma nova tarefa basta criar uma classe que estenda TdkTask
e sobrescrever os métodos de captura de eventos, handleVSEvent e handleVOEvent
(estes métodos serão explicados abaixo). É de responsabilidade da tarefa
capturar os eventos e executar as ações necessárias para a execução de uma
funcionalidade bem definida, como a inserção de um ponto no banco de dados em
uma tarefa de criação de ponto, por exemplo.
Um determinado interador e o seu conjunto de tarefas define um estado
da aplicação. Além disso, o estado da aplicação só é válido
para um certo modo da aplicação. O estado da aplicação varia de acordo com a
interação que o usuário faz com a aplicação. Por exemplo, ao "pedir" ao sistema
para fazer um zoom in em um mapa, a aplicação possui o interador TdkZoomInInteractor e
um conjunto de tarefas associado que tratará deste pedido. Ao "pedir" ao
sistema para fazer um pan, existe outro interador (TdkPanInteractor) com
o seu respectivo conjunto de tarefas associado que tratará deste pedido.
O serviço do Tdk responsável por criar e registrar um estado
de aplicação , remover um estado de aplicação
e obter o estado corrente da aplicação é feito
pela classe TdkApplicationConfigService através dos métodos registerApplicationState,
unregisterApplicationState e getApplicationState, respectivamente.
Como qualquer outro serviço, a TdkApplicationConfigService é
implementada por classes básicas, internas ao Tdk. No caso, a TdkApplicationConfigService
usa a classe TdkApplicationStateManager que, na verdade, é a classe
responsável por fazer as tarefas de criação, remoção e obtenção do estado
da aplicação.
Desta forma, para criar um estado de aplicação é preciso chamar o método registerApplicationState
passando como parâmetros um interador, um vetor de tarefas e
qual o modo de aplicação (mapa, layout ou impressão) para qual este estado vai
ser utilizado.
Para alterar um estado de aplicação, é necessário utilizar o método ... da
classe ... No VIPE, por exemplo, para mudar ...
Um mesmo interador pode estar associado a um conjunto de tarefas diferentes
definindo vários estados de aplicação. De forma análoga, uma mesma tarefa pode
estar associada a diferentes interadores. Esta é uma das grandes vantagens
da utilização da árvore de eventos pois permite a modularização do
sistema e o reuso de seus componentes.
O Visualizador e o conjunto de objetos do modelo de dados do Tdk também
variam durante a execução da aplicação.
|

|
No TDK definimos a interface única TdkEventHandler para
encapsular o código referente a troca de mensagens entre os nós da árvore.
Desta forma, todos os nós da árvore implementam a interface TdkEventHandler
e possuem os métodos sendVS(TdkEvent),
handleVSEvent(TdkEvent), sendVO(TdkEvent), handleVOEvent(TdkEvent)
conforme especificado pela arquitetura VIX.
|

|
De forma geral, o método sendVS(TdkEvent) de um
nó filho chama o método handleVOEvent(TdkEvent) dos
seus nós pais. No exemplo abaixo o método sendVS(TdkEvent) do
visualizador chama o método handleVOEvent(TdkEvent) de suas
tarefas.
O método sendVO(TdkEvent) de um nó pai chama o método handleVSEvent(TdkEvent)
dos seus nós filhos. No exemplo abaixo o método sendVO(TdkEvent)
do interador chama o método handleVSEvent(TdkEvent) das
suas tarefas.
|

|
Abaixo está um pseudo-código para ilustrar a criação de um ponto no modo de
mapa. Quando o usuário clica no mouse solicitando a criação de um ponto, o
IUP captura o evento de mouse click e repassa para o TdkInteractController.
A partir daí, a comunicação entre os nós da árvore é feita através das chamadas
dos métodos explicados na figura anterior, ou seja, cada nó pai em seu método sendVO
chama o método handleVSEvent dos seus filhos.
Na criação de ponto no mapa, o estado da aplicação inclui o TdkPointInteractor
e as tarefas TdkRedrawTask e TdkCreatePointTask, por exemplo.
Antes de repassar o pedido para o um nó filho, o nó pai pode fazer um
tratamento. Veja que neste caso, o TdkPointInteractor transforma o evento de
mouse (TdkMouseEvent) em um evento de criação de ponto (TdkPointEvent).
O TdkPointInteractor repassa este evento para todas as suas tarefas.
Entretanto, somente a TdkCreatePointTask saberá tratá-lo.
|

|
Abaixo um outro pseudo-código que mostra além da comunicação entre um nó pai e
filho, também a comunicação entre nó filho e nó pai utilizando os métodos sendVS
e handleVOEvent. Este exemplo trata da criação de diálogo no modo de
mapa que depois será utilizado para o usuário escrever um texto. Da mesma forma
que no exemplo anterior, depois que o usuário interage com o sistema e o IUP
capta o evento, o evento é repassado para cada um dos nós da árvore
responsáveis pelo tratamento deste evento. No caso o interador responsável é o TdkSimplePointInteractor
e a tarefa é a TdkCreateTextTask. Note que no método sendVS da
tarefa é chamado o método handleVOEvent do seu pai, que no caso é o TdkSimplePointInteractor. Repare
também que os eventos tratados por cada um dos nós da árvore são
diferentes. O método handleVSEvent do TdkMapController e
do TdkSimplePointInteractor recebem o evento TdkMouseEvent, enquanto
o TdkCreateTextTask recebe o evento TdkPointEvent.
|

|
2.3 Exemplo de Criação de Novo Estado de
Interação, Novo Interador e Nova Tarefa
|
Como exemplo de utilização dos conceitos apresentados anteriormente veremos
a aplicação AppSample.
Considerando que SVN_ROOT é o diretório onde foi feito o checkout do
Tdk pelo SVN, o arquivo de solução que deve ser compilado é o SVN_ROOT\iupvipe\examples\appsample\build\\mak.vc71\appsample.sln.
No Visual Studio .NET 2003 abra o arquivo da
solução, acesse o menu Build -> Build Solution e aguarde a
compilação das bibliotecas.
Para executar o AppSample pelo Visual Studio, após a compilação,
aperte a tecla "F5" ou acesse pelo menu Debug -> Start.
Para executar fora do Visual Studio, clique duas vezes no nome do arquivo SVN_ROOT\iupvipe\examples\appsample\build\\mak.vc71\Debug\appsample.exe.
Este arquivo foi gerado na compilação do projeto usando o Visual
Studio.
A AppSample é uma versão simplificada do VIPE que apresenta apenas
o modo de mapa e algumas funcionalidades básicas.
Para ilustrar a criação de um novo estado de interação, de
um novo interador e de uma nova tarefa, esta aplicação
contempla uma funcionalidade para o espelhamento de uma linha.
Para começar, abra a aplicação de exemplo como descrito acima. Então acesse o
menu Arquivo -> Conectar -> Access. Escolha o arquivo TesteAS.mdb
localizado na pasta SVN_ROOT\iupvipe\examples\data . Uma caixa de diálogo
para escolha do projeto a ser visualizado aparecerá. Escolha o projeto TerraEditProject.
Agora que o projeto de teste foi carregado, para espelhar uma
linha você deve primeiro selecionar a ferramenta de espelhamento
de linha clicando com o mouse no ícone de espelhamento como mostra a figura
abaixo.
|
Para exercitar este exemplo você não precisará fazer download por aqui.
Este exemplo (tanto a aplicação quanto o banco de dados) já está disponível
junto com o código do Tdk que você fez download do SVN como dito anteriormente.
|

|
Em seguida você deve selecionar, com o botão esquerdo do mouse, a linha que
deseja espelhar.
|

|
Agora você deve clicar com o botão esquerdo do mouse em algum ponto do canvas,
para gerar a linha base do espelhamento. O padrão é a geração de uma linha
horizontal. Para gerar uma linha vertical, matenha a tecla CTRL pressionada ao
criar a linha base.
|

|
Finalmente, para efetuar o espelhamento, mantenha a tecla SHIFT pressionada e
clique com o botão esquerdo do mouse em qualquer lugar do canvas.
|

|
O estado de aplicação Espelhamento de Linha , identificado pelo inteiro
lineMirrorState_, responsável pela funcionalidade de espelhamento
de linha é formado pelo interador ASLineMirrorInteractor e um
vetor de tarefas contendo as tarefas TdkRedrawTask, TdkSelectMapObjectsTask,
TdkFeedbackTask e ASLineMirrorTask.
O registro do estado pode ser visto no código abaixo, retirado da classe ASApplicationController.
Veja que o registro é feito pela classe TdkApplicationConfigService
através do método registerApplicationState.
|
/*
keywords
-------------------
ApplicationMode InteractionState InteractionStateRegistration Task Interactor
ApplicationController TdkApplicationConfigService RegisterApplicationState OperationMode
-------------------
description: Tutorial of the Interaction Module that shows how to register a new interaction state.
*/
void ASApplicationController::registerASStates()
{
/// To register an application state, it must have an interactor and
/// some tasks (more than zero) for an operation mode. In this case,
/// the operation mode is the map (opmMap).
TdkTaskVector mapLineMirrorTasks;
/// The task ASLineMirrorTask will handle events to mirror some line.
mapLineMirrorTasks.push_back(_asLineMirrorTask);
/// The task TdkRedrawTask is used to redraw the map. This is done when
/// a redraw event is sent.
mapLineMirrorTasks.push_back(_tdkRedrawTask);
/// The task TdkSelectMapObjectsTask is used to selected map objects. The
/// application state uses a selected line to mirror.
mapLineMirrorTasks.push_back(_tdkSelectMapObjectsTask);
/// The task TdkFeedbackTask is used to draw the interaction feedback. In
/// this case, is drawn the axis to mirror the line.
mapLineMirrorTasks.push_back(_tdkFeedbackTask);
/// Creating the line mirror interactor.
TdkInteractor* interactor = new ASLineMirrorInteractor();
/// To register the application state, it must use the
/// TdkApplicationConfigService.
lineMirrorState_ =
TdkApplicationConfigService::registerApplicationState(opmMap,
interactor, mapLineMirrorTasks);
}
|
|
Neste exemplo foram criados o interador ASLineMirrorInteractor e a
tarefa ASLineMirrorTask. Este novo interador e esta nova tarefa
não fazem parte do Tdk, mas sim da própria aplicação.
Como exposto anteriormente, para se criar o ASLineMirrorInteractor foi
estendida a classe TdkLineInteractor, que por sua vez estende a classe
TdkInteractor . Basicamente foram sobrescritos os métodos de
tratamento de eventos handleVSEvent, como exemplificado nos
trechos de código a seguir. Nota-se que este método recebe uma seqüência
de eventos básicos do tipo TdkMouseClickEvent e os traduz em um
evento do tipo ASLineMirrorEvent.
|
/*
keywords
-------------------
VIXEventModel Event MouseButton MouseClickEvent KeyboardState EventTranslation
sendVO handleVSEvent LineMirrorEvent
-------------------
description: Tutorial of the Interaction Module that shows how to extend a Interactor.
*/
void ASLineMirrorInteractor::handleVSEvent(TdkMouseClickEvent& event)
{
TdkButton button = event.getButton();
TdkButtonState buttonState = event.getButtonState();
TdkKeyboardState keyboardState = event.getKeyboardState();
/// If any mouse button was not pressed, exit.
if (buttonState == btsUnpressed)
return;
/// If the right mouse button was pressed, reset the interaction.
if (button == btnRight)
{
reset();
return;
}
/// If the keyboard key shift and the left mouse button was pressed, try
/// to mirror the selected line using the axis.
if (keyboardState == kbsShift && button == btnLeft)
...
ASLineMirrorEvent lineMirrorEvent(getLine());
lineMirrorEvent.addAttender(selectedLine_);
sendVO(lineMirrorEvent);
...
|
|
A tarefa ASLineMirrorTask foi implementada estendendo-se a
classe TdkTask e sobrescrevendo os métodos de tratamento de
eventos handleVSEvent, como pode ser visto no trecho de código a
seguir. A efetiva transformação da linha é executada pelo método mirrorLineObject.
|
/*
keywords
-------------------
VIXEventModel Event Task TaskExecution
sendVO handleVSEvent
-------------------
description: Tutorial of the Interaction Module that shows how to extend a Task.
*/
void ASLineMirrorTask::handleVSEvent(ASLineMirrorEvent& event)
{
/// The line mirror event that is sent by the interactor arrives here.
/// Gets the selected line and the axis and validate them.
TdkEventHandlerVector& attenders = event.getAttenders();
if (attenders.size() == 0)
return;
TdkGeographicObject* object = (TdkGeographicObject*)attenders[0];
if (object == NULL)
return;
TeLine2D& axis = event.getLine();
/// Mirror the line.
mirrorLineObject(object, axis);
}
|
|
Note que no registro do estado usamos tarefas ( TdkRedrawTask,
TdkSelectMapObjectsTask, TdkFeedbackTask) que já existiam e
que foram reusadas para criar este novo estado de interação. Isto ilustra o
reuso de código e a vantagem da utilização da árvore de eventos.
|
|
Seção 3 -
Modo de Layout
|
Nesta seção do tutorial veremos como usar e estender o modo de Layout.
|
3.1) Introdução
|
Como vimos anteriormente, uma aplicação TDK tem basicamente três modos de
operação: Visualização, Layout e Impressão. Nesta seção estaremos demonstrando
o uso das funcionalidades dos módulos de Layout, assim como sua extensão,
mostrando como incluir um novo tipo de objeto de layout.
O Modo de Layout é o modo de operação do TDK para criação e
edição de cartas. As cartas são normalmente compostas de uma visualização
de mapa e outros objetos como legendas, caixa de texto e figuras decorativas.
Abaixo encontra-se um exemplo de uma carta, apresentada no modo de
Layout do VIPE.

Todos os objetos visualizados no canvas principal acima
(marcado com um retângulo em vermelho) são subclasses
da classe TDKLayoutObject. Para a composição de cada carta
é possível adicionar, excluir e editar esses objetos. As operações de
edição como translação, redimensionamento e rotação são definidas pela classe
abstrata TdkEditableObject, uma superclasse da classe TdkLayoutObject.
Toda a interação do usuário no modo de Layout também é feita através
da árvore de eventos apresentada anteriormente, porém com TdkLayoutObject's
na base da árvore, ao invés de TdkObject's
(que são utilizados no modo de visualização de mapa como apresentado na
seção 2) . Para isso o TdkLayoutObject também é subclasse
do TdkEventHandler.

O TDK já oferece alguns tipos de objetos de layout bastante usuais.
Estes tipos estão separados em basicamente duas classes, a TdkApplicationLayoutObject
e a TdkGeometricLayoutObject. Os objetos podem ser agrupados através
da TdkLayoutObjectCollection.
|

|
O TdkGeometricLayoutObject, como o próprio nome indica,
representa tipos geométricos básicos (como ponto, linha e polígono) que
podem ser adicionados ao layout. Esses tipos podem ser
agrupados, formando figuras mais complexas, usando a coleção TdkGeometricLayoutObjectCollection.
|

|
Para outros tipos de objetos temos a classe TdkApplicationLayoutObject.
Eles representam objetos mais específicos de cada aplicação e estão
subdivididos em duas classes: TdkViewLayoutObject e TdkImageLayoutObject.
A TdkImageLayoutObject representa uma imagem enquanto TdkViewLayoutObject
representa objetos mais complexos como mapas e legendas.
|

|
Na seção a seguir vamos mostrar como estender o atual modelo para
a inclusão de um novo tipo de objeto de layout.
|
3.2) Exemplo de Criação de Novo Tipo
de Objeto de Layout
|
Nesta seção vamos mostrar um exemplo de extensão do modo
de layout. Apresentaremos todos os passos necessários para criarmos
e depois adicionarmos um novo tipo de objeto de layout. Esta seção
está dividida em duas partes: na seção 4.2.1 mostraremos a camada
do modelo de dados com o novo tipo de objeto de layout (ou seja,
vamos mostrar a criação de um novo tipo de objeto de layout), na seção 4.2.2
mostraremos como uma aplicação pode utilizar este novo tipo de objeto (ou seja,
vamos mostrar como este novo tipo de objeto pode ser adicionado ao canvas
principal do modo de layout).
|
3.2.1) Criação do
Novo Tipo de Objeto de Layout
|
O primeiro passo então é a criação de uma nova classe, que
estenda a TdkLayoutObject ou uma de suas subclasses. No nosso exemplo
como o objeto a ser adicionado será um simples retângulo, chamado de ASLayoutObject
, vamos estender a TdkGeometricLayoutObject, como esquematizado no
diagrama abaixo e demonstrado no código seguinte.
|

|
/*
keywords
-------------------
Layout LayoutObject LayoutObjectExtension
-------------------
description: Tutorial of the Interaction Module that shows how to extend a LayoutObject.
*/
/// The string that identifies the ASLayoutObject
#define _AS_LAYOUT_OBJECT_TYPE_ "AS_LAYOUT_OBJECT_TYPE"
/// The string that indentifies this object template type
#define _AS_LAYOUT_OBJECT_NAME_ "TASLAYOUTOBJECT"
/// the string that serves as basename for all objects of this type
#define _AS_LAYOUT_OBJECT_BASE_NAME_ "aslayoutobject"
/// This is the sample group.
/// @defgroup AppSample
/// ASLayoutObject class.
///
/// @ingroup AppSample
class ASLayoutObject : public TdkGeometricLayoutObject
{
public:
ASLayoutObject(std::string name, TeBox& bBox);
ASLayoutObject(ASLayoutObject& geometricLayoutObject);
virtual ~ASLayoutObject();
virtual TdkLayoutObject* copy();
virtual std::string getType();
virtual std::string getTemplateName();
// Persistence methods.
virtual void insert(TeDatabase* driver, std::string layoutName);
virtual void load(TeDatabase* driver, std::string layoutName);
virtual void update(TeDatabase* driver, std::string layoutName);
virtual void remove(TeDatabase* driver, std::string layoutName);
// This method is called to ask the object to update it´s bounding box, represented
// by the protected atribute bBox_ .
virtual void updateBBox();
/// This method is responsable for translating, resizing and rotating the object
virtual void transform(TdkMathMatrix& matrix);
/// This method returns the vertex index that is in the
/// surroudings of a given coord
virtual int vertexPoint(TeCoord2D& coord);
/// This methods gives the two vertexes indexes that defines a
/// line of this object, that is in the surroundings of the given coord
virtual void segmentVertexes(TeCoord2D& coord, int& vertex1, int& vertex2);
virtual void point2Line(TeCoord2D& coord, int vertex1, int vertex2);
protected:
// This method is responsible for drawing the content of the object
virtual void paint(TdkCanvas* display);
}
|
|
Para que um objeto ASLayoutObject seja criado, é necessário
utilizar o métodocreateLayoutObjectda classe TdkLayoutObjectFactory.
Este método é responsável por controlar a geração de qualquer objeto
de layout, gerando nomes únicos a partir de um nome base definido. Porém, para
que o métodocreateLayoutObject funcione corretamente, a TdkLayoutObjectFactory precisa
saber como construir cada tipo de objeto. No nosso caso, ela precisa conhecer
como construir o ASLayoutObject. Isto é feito através do registro de
um método estático que é quem de fato instancia o objeto. No nosso
exemplo, este método estático é o createASLayoutObject.
O registro é feito através do método registerLayoutObjectConstructor
da classe TdkLayoutObjectFactory. Não há uma obrigatoriedade de onde
fazer a chamada do registro, mas é importante que seja feito durante
as rotinas de configuração da aplicação. Na aplicação de exemplo, esse registro
está sendo feito no método init da classe ASApplication.
|
/*
keywords
-------------------
Applicaiton LayoutObjectFactory Layout LayoutObject
LayoutObjectConstructorMethod registerLayoutObjectConstructor
-------------------
description: Tutorial of the Interaction Module that shows how to register a LayoutObject constructot method in
the object factory.
*/
bool ASApplication::init()
{
...
// Here we are registering our ASLayoutObject constructor.
// The LayoutObjectFactory controls unique name generation for TdkLayoutObjects, given a base name.
TdkLayoutObjectFactory::registerLayoutObjectConstructor(_AS_LAYOUT_OBJECT_TYPE_,createASLayoutObject);
...
}
|
|
Abaixo apresentamos o diagrama de seqüência que ilustra o registro do método
construtor e a criação de um novo ASLayoutObject por uma ASCreateASLayoutObjetTask.
|

|
O método createASLayoutObject precisa obedecer a interface TdkLayoutObjectConstructorFunction,
pois é a interface padrão dos construtores, onde estes recebem um nome e
um blob com os dados iniciais do objeto serializados. Para você utilizar o
TdkBlob para representar o blob, é preciso definir um protocolo
de serialização dos dados do seu objeto. No nosso exemplo, como é um retângulo,
precisamos definir apenas as duas coordenadas em uma ordem conhecida. No caso,
a ordem deste exemplo foi definida como x1, x2, y1, y2. Segue no código
abaixo o método createASLayoutObject que mostra
como estamos lendo de acordo com este protocolo. A frente você verá o
código onde criamos o blob de acordo com o protocolo.
|
/*
keywords
-------------------
Applicaiton LayoutObjectFactory Layout LayoutObject
LayoutObjectConstructorMethod Blob LayoutObjectDeserialization
-------------------
description: Tutorial of the Interaction Module that shows how to instantiate a new a LayoutObject.
*/
TdkLayoutObject* createASLayoutObject(std::string name, TdkBlob* blob)
{
// Here we will deserialize our layout object
// Since our object is a simple rectangle, we just read
// the two points that defines our box.
// So let´s read our geometry
blob->reset();
double x1;
double x2;
double y1;
double y2;
blob->readDouble(x1);
blob->readDouble(x2);
blob->readDouble(y1);
blob->readDouble(y2);
TeBox box(x1,y1,x2,y2);
// Now we get the object style
TdkVisual* visual = new TdkVisual();
bool hasAdvancedStyle;
blob->readBool(hasAdvancedStyle);
if (hasAdvancedStyle == true)
{
TdkPolygonStyle* style = TdkSetup::getPolygonStyleFactory().make(blob);
visual->setStyle(style);
}
else
{
int type;
blob->readInt(type);
visual->style(type);
int r, g, b;
blob->readInt(r);
blob->readInt(g);
blob->readInt(b);
visual->color().red_ = r;
visual->color().green_ = g;
visual->color().blue_ = b;
char transparency;
blob->readChar(transparency);
visual->transparency(transparency);
int contourWidth;
blob->readInt(contourWidth);
visual->contourWidth(contourWidth);
blob->readInt(r);
blob->readInt(g);
blob->readInt(b);
visual->contourColor().red_ = r;
visual->contourColor().green_ = g;
visual->contourColor().blue_ = b;
bool fixedSize;
blob->readBool(fixedSize);
visual->fixedSize(fixedSize);
}
// Here we create a new instance of our layout object
ASLayoutObject* object =
new ASLayoutObject(name, box);
// And set the object style
object->setVisual(visual);
return object;
}
|
|
3.2.2) Utilização
do Novo Tipo de Objeto de Layout - Criação e Registro de Estado de Interação,
Criação de Tarefa e Criação de Interador
|
Neste momento já é possível a criação de uma nova instância do nosso
objeto.
Vamos então mostrar como uma aplicação pode utilizar este novo
tipo de objeto ou seja, como um usuário final da aplicação, utilizando a
interface do sistema, pode adicionar este novo tipo de objeto no
canvas principal do modo de layout.
Primeiro criaremos a tarefa que instancia nosso novo objeto e o adiciona ao
conjunto de objetos do layout. Para isso basta estendermos a classe TdkTask
sobrescrevendo o método handleVSEvent, como visto na seção 2 deste
tutorial. No exemplo criamos a classe ASCreateASLayoutObjectTask como
extensão da TdkTask.
Como nosso objeto é um retângulo, vamos reutilizar o interador de retângulo já
presente no conjunto de interadores padrão do TDK, o TdkRectInteractor,
o qual capturará os eventos de clique e movimento de mouse traduzindo-os
para um TdkRectEvent e enviando-o para essa nossa nova
tarefa.
|
/*
keywords
-------------------
Event RectEvent HandleVSEvent VIX Task Layout LayoutObject LayoutObjectCreation
LayoutController VIXEventModel
-------------------
description: Tutorial of the Interaction Module that shows how create anda add a new Layout object.
*/
void ASCreateASLayoutObjectTask::handleVSEvent(TdkEvent& event)
{
if (event.name().compare(TDK_RECT_EVENT_NAME) == 0)
handleVSEvent(*((TdkRectEvent*)&event));
}
void ASCreateASLayoutObjectTask::handleVSEvent(TdkRectEvent &event)
{
// Get the result of the user interaction
TeBox& viewportBox = event.getRect();
double wx1;
double wy1;
double wx2;
double wy2;
// Here we are translating the coords from screen ( viewport) to the Layout View Paper ( world )
TdkLayoutController::getInstance()->getDisplay()->getCanvas()->viewport2Window(viewportBox.x1(),viewportBox.y1(),wx1,wy1);
TdkLayoutController::getInstance()->getDisplay()->getCanvas()->viewport2Window(viewportBox.x2(),viewportBox.y2(),wx2,wy2);
TeBox worldBox(wx1,wy1,wx2,wy2);
// We serialize this information and passes it to the LayoutObjectFactory
TdkBlob blob;
blob.clear();
blob.reset();
blob.writeDouble(worldBox.x1());
blob.writeDouble(worldBox.x2());
blob.writeDouble(worldBox.y1());
blob.writeDouble(worldBox.y2());
ASLayoutObject* asLayoutObject =
(ASLayoutObject*)TdkLayoutObjectFactory::
createLayoutObject(_AS_LAYOUT_OBJECT_TYPE_, _AS_LAYOUT_OBJECT_BASE_NAME_, &blob);
// Just completing the object information with some default values
asLayoutObject->setVisual(TdkStyleDecoder::getDefaultVisual(TePOLYGONS,0));
// Adding the object to the Layout representation
TdkLayout* layout = (TdkLayout*)TdkLayoutController::getInstance()->getModel();
layout->addObject(asLayoutObject);
// drawing the object
asLayoutObject->draw(TdkLayoutController::getInstance()->getDisplay());
TdkRefreshEvent refreshEvent;
sendVO(refreshEvent);
// The TdkEventManager is the class wich controls the undo/redo feature.
// We insert in the manager a especial event that executes our object
// creation and deletion specific routines
ASCreateLayoutObjectEvent* createEvent = new ASCreateLayoutObjectEvent(asLayoutObject);
createEvent->addAttender((TdkEventHandler*)asLayoutObject);
TdkCompletedEvent* completedEvent = new TdkCompletedEvent(createEvent);
TdkEventManager::getInstance()->insertEvent(completedEvent);
}
|
|
Agora vamos registrar um novo estado de interação que representará uma árvore de
eventos contendo a nossa nova tarefa ASCreateASLayoutObjectTask, o
interador de retângulos TdkRectInteractor e algumas tarefas
auxiliares necessárias.
Os estados de interação já disponibilizados pelo TDK, são criados e registrados
durante a execução do método init da classe TdkApplicationController.
Então para criarmos e registrarmos o nosso novo estado de interação, estendemos
este método da seguinte forma:
|
/*
keywords
-------------------
ApplicationController ApplicationControllerInit InteractionStateRegistration
ApplicaitonConfigService TaskVector
-------------------
description: Tutorial of the Interaction Module that shows how to create and register a new interaction state.
*/
void ASApplicationController::init()
{
/// Initializes the states supplied by TDK.
TdkIupApplicationController::init();
/// Register the application sample states.
registerASStates();
}
void ASApplicationController::registerASStates()
{
/// To register an application state, it must have an interactor and
/// some tasks (more than zero) for an operation mode. In this case,
/// the operation mode is the layout (opmLayout).
TdkTaskVector layoutASObjectCreateTasks;
/// The task TdkRedrawTask is used to redraw the objects. This is done when
/// a redraw event is sent.
layoutASObjectCreateTasks.push_back(_redrawTask);
/// The task ASCreateASLayoutObjectTask is the responsable for creating our
/// Layout Object
layoutASObjectCreateTasks.push_back(_asCreateASLayoutObjectTask);
/// The task TdkFeedbackTask is used to draw the interaction feedback. In
/// this case, is drawn the layout object bounding box.
layoutASObjectCreateTasks.push_back(_feedbackTask);
/// Creating the rect interactor.
TdkInteractor* interactor = new TdkRectInteractor();
/// To register the application state, it must use the
/// TdkApplicationConfigService.
asLayoutObjectCreateState_ =
TdkApplicationConfigService::registerApplicationState(opmLayout,
interactor,layoutASObjectCreateTasks);
}
|
|
Pode-se perceber que tanto as tarefas padrões do TDK quanto a nossa nova tarefa
não foi instanciada neste método. Para criar e destruir nossa nova tarefa,
vamos sobrescrever mais dois métodos do TdkApplicationController : deleteAllTasks
e instantiateAllTasks.
|
/*
keywords
-------------------
Task InstantiateTask InstantiateAllTasks DeleteTask DeleteAllTasks
ApplicationController
-------------------
description: Tutorial of the Interaction Module that shows how to initialize and delete a new task.
*/
// This method is responsable by the deletion of all tasks used
void ASApplicationController::deleteAllTasks()
{
TdkApplicationController::deleteAllTasks();
TDK_DELETE(_asCreateASLayoutObjectTask);
}
// This method is responsable by the instantiation of all tasks
// tha will be used
void ASApplicationController::instantiateAllTasks()
{
TdkApplicationController::instantiateAllTasks();
_asCreateASLayoutObjectTask = new ASCreateASLayoutObjectTask();
}
|
|
Agora já temos o nosso novo estado de interação criado e registrado. Então para
que o usuário comece a usar nossa nova funcionalidade de inserção do nosso
objeto de layout, precisamos incluir um botão ou comando para fazer a alteração
do estado de interação corrente.
Para isso precisamos fazer uma chamada ao método setCurrentState (da
classe TdkApplicationController), usando o identificador recuperado
quando registramos o nosso estado de interação.
Em nosso exemplo vamos fazer esta chamada em um
método próprio da nossa classe ASApplicationController, onde também
vamos enviar um evento para trocar o cursor do mouse, dando ao usuário uma
resposta visual indicando que o estado de interação foi configurado.
|
/*
keywords
-------------------
ApplicationController SetCurrentState ChangeMouseEvent
-------------------
description: Tutorial of the Interaction Module that shows set a interaction state.
*/
void ASApplicationController::setASLayoutObjectCreateState()
{
//To set the applicaiton state just call the setCurrentState
//using the integer indentifier gathered when we registered the
//our new layout object
setCurrentState(asLayoutObjectCreateState_);
//You can change the mouse icon to give the user a visual feedback
//showing that this feature is activated
TdkChangeMousePointerEvent eventToSend(mprCross);
dispatch(eventToSend);
}
|
|
Após a chamada do método setCurrentState, mostrado acima, o
TDK configura toda a árvore de eventos. O diagrama abaixo
retrata o estado final da árvore para o nosso exemplo.
|
|
|
Topo ^
|
|