User Interaction

Programação por Objectos 2011/12, Taguspark

Pedro Reis dos Santos

Este documento pretende descrever brevemente o funcionamento da interface utilizador utilizada para desenvolver aplicações na disciplina de Programação por Objectos. As classes que constituem a interface utilizador são distribuídas em código fonte Java no pacote pt.utl.ist.po.ui A interacção é realizada apenas com menus, forms e displays. O menu é uma lista de opções que o utilizador pode escolher. A form permite ao utilizador introduzir dados simples: números inteiros ou reais, cadeias de caracteres ou valores booleanos (sim ou não). O display é utilizada para informar o utilizador dos resultados da interacção e é apenas constituída por cadeias de caracteres. A interface utilizador disponibilizada procura facilitar o teste automático da funcionalidade dos projectos desenvolvidos, suportar diferentes interfaces e garantir a independência entre o núcleo do projecto e a sua interface gráfica. O núcleo é um conjunto de classes que modela e realiza o problema proposto. A interface dá um aspecto visível possível através do qual se podem realizar pedidos ao núcleo. Desta forma, o núcleo nunca deve aceder à interface utilizador. Da mesma forma, a interface utilizador não deve realizar operações de cálculo ou gestão mas apenas recolher dados, passá-los a um ou mais métodos do núcleo, e apresentar os resultados obtidos do núcleo. Os exemplos das aulas prática bank e editor fornecem exemplos simples para a realização de projectos mais complexos que devem ser analisados para compreender os conceitos expostos neste documento.

A interligação entre o núcleo e a interface utilizador

Se o núcleo não depende da interface utilizador utilizada, deve ser esse núcleo da aplicação a ser criado primeiro. Esse núcleo, aqui designado por App, deve ser depois passado à interface, para que esta possa fazer os pedidos e recolher os resultados. O menu inicial, aqui designado por AppMenu, é uma classe que extende a classe disponibilizada pt.utl.ist.po.ui.Menu. A colocação de um título é facultiva e serve para identificar a janela de interacção em algumas interfaces gráficas. Para activar o menu, tornando-o visível e permitindo ao utilizador a selecção de uma opção, basta invocar o método open(). A interacção termina com a invocação do método IO.close(), o que permite libertar recursos como, por exemplo, janelas em ambientes gráficos.
  App app = new App();
  Menu m = new AppMenu(app);
  IO.setTitle(title);
  m.open();
  IO.close();
  

Construção de um Menu

Os menus são classes derivadas da classe disponibilizada pt.utl.ist.po.ui.Menu. O construtor da classe recebe o título do menu (String) e um vector de opcões (Command[]). Cada uma das opções do menu é uma classe derivada da class disponibilizada pt.utl.ist.po.ui.Command. Estas opções podem ser realizadas por classes com nome, como as classes Opçao2 ou SubMenu do exemplo abaixo, ou como uma classe anónima. Em qualquer dos casos, a classe base Command deverá realizar o método execute(), a ser invocado quando o utilizador selecciona essa opção no menu. Para que nesse método se possa aceder ao núcleo da aplicação, a classe Command necessita ser parametrizada com a classe principal da aplicação, ou eventualmente uma outra classe. Uma instância deste tipo parametrizado deverá ser passada no construtor da classe Command e acedida dentro do método execute() através do método entity(). A operação entry(2).invisible() torna a segunda opção do menu não seleccionável, até que o método visible() seja invocado.
  public class AppMenu extends Menu {
      public AppMenu(App app) {
	  super(MenuEntries.TITLE, new Command[] {
	      new Command (false, "option title", app) {
		  public final void execute() {
		      App nucleo = entity();
		      Display d = new Display(title());
		      d.add("MyMenu.execute() called");
		      d.display();
		  }
	      },
	      new Opcao2(b),
	      new SubMenu(b)
	  });
	  entry(2).invisible();
      }
  }
  
Se uma classe derivada de Command não for anónima será codificada separadamente. A estrutura é idêntica ao exemplo anónimo acima, mas o construtor aparece explicitamente. Qualquer uma das opções de um menu pode ser um outro menu, cuja operação de execute() deverá invocar o método open() do outro menu para o activar. Quando esse outro menu terminar, o controlo regressa ao menu actual.
  public class SubMenu extends Command {
	  public AppMenu(App app) {
		  super(false, "SubMenu title, app);
	  }
	  public final void execute() throws InvalidOperation {
		  Menu m = new OtherMenu(entity());
		  m.open();
	  }
  }
  

Apresentação de mensagens ao utilizador

A apresentação de mensagens para o utilizador realiza-se através da classe Display, onde o método display(boolean force) apresenta o texto recolhido pelos métodos add(String) e addNewLine(String). A utilização da opção force executa a operação mesmo que não tenha sido adicionado texto, enquanto o método addNewLine(String) cria uma nova linha antes de adicionar o texto passado como argumento.

Pedido de valores ao utilizador

Para obter dados do utilizador, para definir pesquisas ou criar objectos, por exemplo, é necessário utilizar forms. Uma Form é uma classe que agrupa diversos pedidos numa só interacção. Os pedidos resumem-se a valores de quatro tipos da linguagem Java: int, real, boolean e String. Para cada valor a pedir ao utilizador deverá ser criada uma instância das classes InputInteger, InputFloat, InputString e InputString, respectivamente. Cada um dos construtores dessas classes recebe a Form onde deve ser integrado o pedido e uma mensagem descritiva do pedido. Existe ainda um separador, designado por InputNone que não pede qualquer valor. O método parse() da Form efectua o pedido ao utilizador, podendo os valores ser recolhidos posteriomente através do método value() de cada uma das instâncias de Input introduzidas na Form.
  public final void execute() throws InvalidOperation {
	  Form f = new Form("Titulo");
	  InputInteger id = new InputInteger(f, "Introduza um valor inteiro");
	  InputFloat real = new InputFloat(f, "Distância");
	  InputNone   sep = new InputNone(f, "-----");
	  InputString str = new InputString(f, "Nome");
	  InputBoolean sn = new InputBoolean(f, "OK?");
	  f.parse();
	  IO.message("Id = " + id.value() + " Real = " + real.value() +
		     " Str = " + str.value() + " OK = " + sn.value());
  }
  

Interfaces disponíveis

O modo normal de funcionamento da interface utilizador é o modo texto. Este modo é o utilizado para efectuar os testes automáticos, e manuais, pelo que ao desenvolver o projecto deve garantir o bom da aplicação neste modo. A execução da aplicação neste modo deve ser efectuada numa janela de texto e não necessita de quaisquer parâmetros específicos.
  java aplic.Main
  
Notar que se a variável de ambiente CLASSPATH não estiver correctamente definida é necessário indicar o seu valor em cada invocação.
  java -cp . aplic.Main
  
Para efectuar testes de uma forma automatizada, incluindo os testes disponibilizados ao longo do semestre, deve ser definidas duas variáveis de ambiente. Estas variáveis, designadas por in e out, permitem que a interface utilizador redireccione, quando em modo texto, a entrada de valores a partir de um ficheiro (in.txt) bem como a recolha dos resultados (out.txt), respectivamente.
  java -Din=in.txt -Dout=out.txt aplic.Main
  
A construção de um ficheiro jar (Java ARchive) permite agrupar vários ficheiros compilados (.class) num só ficheiro. Para que este ficheiro possa ser executado como uma aplicação é necessário declarar um manifesto (MANIFEST.MF) onde se indica, por exemplo, a classe de arranque (Main-Class) ou outros ficheiros .jar a utilizar (Class-Path)
  Main-Class: aplic.Main
  Class-Path: pt.jar
  
O ficheiro .jar é criado com o comando
  jar -cfm aplic.jar MANIFEST.MF *.class
  
Onde *.class representa todos os ficheiros da aplicação. A aplicação pode agora ser invocada com
  java -jar aplic.jar
  
Não confundir este ficheiro com um outro .jar que contém apenas os ficheiros fonte (.java) a submeter para avaliação. A utilização da interface gráfica swing é efectuada através da atribuição à variável de ambiente ui:
  java -Dui=swing aplic.Main
  
Este é o comportamento por omissão no sistema windows quando directamente invocado a partir do explorer, se o ficheiro jar estiver correctamente construído e associação com o interpretador Java definida. Embora experimental, também é possível executar a aplicação a partir de um browser utilizando um applet. Para tal basta incluir a sua invocação num ficheiro de hipertexto (.html). Neste caso a execução já não se inicia pela rotina main() pelo que a classe de arranque é sempre pt.utl.ist.po.ui.AppletInteraction. Como parâmetro é necessário definir a localização da rotina main() como valor do parâmetro mainClass.
<applet width=300 height=300 code="pt.utl.ist.po.ui.AppletInteraction" archive = 'aplic.jar'>
<param name="mainClass" value="aplic.Main" >
</applet>