Criação de interfaces gráficas Modelos Interacção por terminal de texto Pergunta-resposta fácil de seguir Alternativa: criação de uma interface complexa com objectos variados Interacção pode ser com vários desses objectos Gera-se um evento, ao nível do sistema operativo (tecla, rato, ...), que é passado ao Java e tratado pela aplicação Construir a interface, aguardar eventos e processá-los Em vez de atitude activa de interrogar cada objecto para saber se tem algum pedido Os eventos podem ocorrer sem ordem nem momento pre-determinados Mais próximo do paradigma de objectos Cada objecto trata dos seus eventos Fluxo da computação passa mais para as mãos do utilizador Swing Criação de GUIs em Java Biblioteca de classes AWT (Abstract Window Toolkit) Fornece todas as classes básicas para a construção de interfaces Incluída em todos os sistemas Java no pacote java.awt Portável entre plataformas Modelo de eventos suportado pelo pacote java.awt.event Com problemas de eficiência e aspecto Biblioteca Swing Trabalha sobre a AWT, mas mais eficiente Incluída em javax.swing Tem mais estruturas para a construção do GUI Suporta look-and-feel (Windows, Unix, Macintosh, independente, adaptado) Swing Objectos em Swing Combo box (JComboBox) Janela (Jframe) Tela (Jpanel) Etiqueta (JLabel) Lista (Jlist) Campo de texto (JTextField) desenho Botão de rádio (JRadioButton) Grupo de botões (ButtonGroup) Botão (JButton) Campo de texto não editável Caixa de escolha (JCheckBox) Apenas se mostram alguns objectos simples; a biblioteca Swing tem muitos mais Swing Hierarquia de classes Maior parte dos objectos descende de Component Tem posição e tamanho, pode ser mostrado no ecrã e receber eventos Classe abstracta Alguns métodos void setSize( int width, int height ); Usar antes setPreferredSize; void setBackground ( Color c ); void setFont( Font f ); void show() Torna o componente visível As classes Font e Color estão definidas noutra hierarquia, em AWT (Só se mostra parte da hierarquia) Swing Contentores Container Um contentor é um componente que pode conter outros componentes É necessário saber-se como dispor os componentes Ajudante: posicionador (LayoutManager) associado com void setLayout( LayoutManager mgr ); Depois adicionam-se os componentes por ordem void add( Component c ); ou void add( Component c, Object where ); Dois tipos de contentores Janelas de topo, até Jframe Componente pesado porque interage com o sistema de janelas nativo na máquina JComponent e suas subclasses (muitos dos outros componentes) Componente leve porque é completamente desenhado numa tela pelo Swing Swing Janelas Tipos de janelas de topo JWindow : janela sem caixilho JFrame : janela com caixilho que pode ter também um menu (JMenuBar) JDialog : janela para criar diálogos Uma aplicação deve ter um JFrame ou uma sua subclasse Não é possível adicionar componentes directamente à janela Para deixar ao Swing controlo sobre o posicionamento Obtém-se um contentor que representa o conteúdo da janela Container getContentPane( ); Swing Painel Um painel destina-se a organizar componentes numa unidade de apresentação Podem existir contentores dentro de contentores e painéis dentro de painéis É habitual usar uma subclasse de Jpanel para permitir acrescentar código específico (GUI é uma subclasse de Jpanel) GUI implementa a interface ActionListener É um atendedor para tratar o evento “carregar no botão” Tem que fornecer o método actionPerformed Tem que ligar o atendedor ao objecto que pode produzir o evento theDrawButton.addActionListener( this ) JPanel herda de JComponent várias funcionalidades, incluindo palpites e dimensionamento void setToolTipText( String txt ); void setPreferredSize( Dimension d ); Swing Classe GUI principal import java.awt.*; public void actionPerformed( ActionEvent evt ) import javax.swing.*; { /* ver a frente*/ } import java.awt.event.*; class GUI extends JPanel implements ActionListener private GUICanvas theCanvas; { private JComboBox theShape; public GUI( ) private JList theColor; { private JTextField theXCoor; makeTheObjects( ); private JTextField theYCoor; doTheLayout( ); private JRadioButton smallPic; theDrawButton.addActionListener( this ); private JRadioButton mediumPic; } private JRadioButton largePic; // Make all the objects private JCheckBox private void makeTheObjects( ) private JButton { /* ver a frente*/ } theDrawButton; private JTextField theMessage; // Layout all the objects private void doTheLayout( ) theFillBox; } { /* ver a frente*/ } Swing Relacionamento entre classes JComponent ActionListener ActionPerformed extends JPanel implements extends GUI includes GUICanvas JComboBox JList ... GUICanvas Swing Etiquetas e botões Componente destinado a etiquetas: JLabel Normalmente associado a campos de texto, campos combo, listas e paineis, uma vez que os outros já têm etiqueta própria Construção de um objecto etiqueta vazio: JLabel( ); Construção de um objecto com a etiqueta theLabel: JLabel( String theLabel ); Alteração da etiqueta no objecto: setText( String theLabel ); Pode ser usado para mensagens para o utilizador mas habitualmente usa-se campos de texto não editáveis para esse fim Um botão (caso de Draw) pode ser visto como uma etiqueta activa: gera eventos para “click com o botão esquerdo” Métodos: JLabel( ); JLabel( String theLabel ); setText( String theLabel ); Swing Caixas de selecção Nas caixas de selecção (“combo box”), é possível escolher um objecto de uma lista pop-up de alternativas, ficando apenas a escolha visível No caso de a lista ser editável, pode escrever-se um valor não previsto A lista de valores pode ser fornecida na criação do objecto ou ser manipulada posteriormente Criação de caixa de selecção vazia: JComboBox( ); Idem, com as opções: JComboBox( Object[] choices ); Acrescentar opção no fim: void addItem( Object item ); Devolver o objecto correspondente ao item seleccionado: Object getSelectedItem( ); ou o respectivo número de ordem int getSelectedIndex( ); Permitir a especificação de um novo valor: void setEditable( boolean edit ); Indicar o valor seleccionado (ex. por omissão): void setSelectedIndex( int index ); Swing Listas O componente JList permite fazer escolhas numa lista de valores possivelmente com rolamento, se o número de valores exceder o espaço disponível Principais diferenças relativamente à combo box: A lista permite, por omissão, selecção múltipla A lista deixa ver vários valores simultaneamente A lista ocupa maior superfície do ecrã Criação de lista vazia: JList( ); ou com os valores: JList( Object[] values ); Indicar os valores: void setListData( Object[] values ); Selecção simples, devolver o objecto correspondente: Object getSelectedValue( ); ou o respectivo número de ordem int getSelectedIndex( ); Selecção múltipla: Object [] getSelectedValues( ); int[] getSelectedIndices( ); Escolher modo de selecção ListSelectionMode.SINGLE_SELECTION); simples: void setSelectionMode( Indicar o valor seleccionado: void setSelectedIndex( int index ); void setSelectedValue( Object value ); Swing Caixas de marcação e botões de rádio Estes componentes (JCheckBox e JRadioButton) só têm dois estados: on (true) e off (false) Por isso, têm etiqueta no próprio objecto e podem ser agrupados JCheckBox para dizer sim ou não JRadioButton para escolher um entre alternativas Criação de uma caixa sem etiqueta: JCheckBox( ); com etiqueta: JCheckBox( String theLabel); com etiqueta e estado inicial: JCheckBox( String theLabel, boolean state); Idem para JRadioButton Altera a etiqueta: void setLabel( String theLabel ); Indicar o estado: void setSelected( boolean state); Consulta o estado: boolean isSelected ( ); Para criar um grupo de escolha mutuamente exclusiva: ButtonGroup( ); Não é um componente Para adicionar os botões (ou caixas) em causa: void add( AbstractButton b ); Swing Texto Um campo de texto JTextField permite escrever uma linha de texto Para mais do que uma linha, usa-se a área de texto JTextArea A tecla Enter funciona aqui como uma mudança de linha e não como um evento do teclado a significar “fim de entrada de dados” Métodos Campo de texto: JTextField( ); Idem com indicação do comprimento: JTextField( int cols); Idem com valor inicial e comprimento: JTextField( String text, int cols); Obter o texto escrito no campo: String getText( ); Indicar o texto escrito no campo: void setText( String text ); Indicar se é editável ou não (só para display de mensagens): void setEditable( boolean editable ); Swing // Make all the objects private void makeTheObjects( ) ButtonGroup theSize = new ButtonGroup( ); { smallPic = new JRadioButton( "Small", false ); theCanvas = new GUICanvas( ); mediumPic = new JRadioButton( "Medium", true ); theCanvas.setBackground( Color.green ); largePic = new JRadioButton( "Large", false ); theCanvas.setPreferredSize( theSize.add( smallPic ); new Dimension( 100, 100 ) ); theSize.add( mediumPic ); theSize.add( largePic ); theShape = new JComboBox( new String [ ] { "Circle", "Square" } ); theFillBox = new JCheckBox( "Fill" ); theFillBox.setSelected( false ); theColor = new JList( new String [ ] { "red", "blue" } ); theDrawButton = new JButton( "Draw" ); theColor.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); theMessage = new JTextField( 25 ); theColor.setSelectedIndex( 0 ); // make red default theXCoor = new JTextField( 3 ); theMessage.setEditable( false ); } theYCoor = new JTextField( 3 ); Swing // Layout all the objects private void doTheLayout( ) { // Layout the bottom half JPanel topHalf = new JPanel( ); bottomHalf.setLayout( new FlowLayout( ) ); JPanel bottomHalf = new JPanel( ); bottomHalf.add( smallPic ); bottomHalf.add( mediumPic ); // Layout the top half bottomHalf.add( largePic ); topHalf.setLayout( new FlowLayout( ) ); bottomHalf.add( theFillBox ); topHalf.add( theCanvas ); bottomHalf.add( theDrawButton ); topHalf.add( new JLabel( "Shape" ) ); bottomHalf.add( theMessage ); topHalf.add( theShape ); topHalf.add( theColor ); // Now layout GUI topHalf.add( new JLabel( "X coor" ) ); setLayout( new BorderLayout( ) ); topHalf.add( theXCoor ); add( topHalf, "North" ); topHalf.add( new JLabel( "Y coor" ) ); add( bottomHalf, "South" ); topHalf.add( theYCoor ); } Swing Telas Uma tela é uma área rectangular onde se pode desenhar e que recebe eventos Em AWT, usava-se a classe Canvas Em Swing, cria-se uma subclasse de JPanel, que permite redefinir o método de desenhar a interface: void paintComponent( Graphics g ); g é uma instância da classe abstracta Graphics que o Swing associa ao dispositivo de visualização Métodos para desenhar void drawOval( int x, int y, int width, int heigth ); drawRect, fillOval, fillRect; indica canto superior esquerdo e dimensões void drawLine( int x1, int y1, int x2 int y2 ); superior esquerdo e inferior direito void DrawString( String str, int x, int y ); void setColor ( Color c ); Swing Definição da tela class GUICanvas extends JPanel public void paintComponent( Graphics g ) { super.paintComponent( g ); { if( theColor.equals( "red" ) ) public void setParams( String aShape, g.setColor( Color.red ); String aColor, int x, int y, int size, boolean fill ) else if( theColor.equals( "blue" ) ) { g.setColor( Color.blue ); this.theShape = aShape; this.theColor = aColor; theWidth = 25 * ( theSize + 1 ); xcoor = x; if( theShape.equals( "Square" ) ) if( fillOn ) ycoor = y; g.fillRect( xcoor, ycoor, theWidth, theWidth ); theSize = size; else fillOn = fill; g.drawRect( xcoor, ycoor, theWidth, theWidth ); repaint( ); else if( theShape.equals( "Circle" ) ) } if( fillOn ) g.fillOval( xcoor, ycoor, theWidth, theWidth ); public void update( Graphics g ) { else System.out.println( "Update called" ); g.drawOval( xcoor, ycoor, theWidth, theWidth ); } } Swing Resto da tela private String theShape = ""; private String theColor = ""; private int xcoor; private int ycoor; private int theSize; // 0 = small, 1 = med, 2 = large private boolean fillOn; private int theWidth; } Swing Responder ao evento public void actionPerformed( ActionEvent evt ) { try { theCanvas.setParams( (String) theShape.getSelectedItem( ), (String) theColor.getSelectedValue( ), Integer.parseInt( theXCoor.getText( ) ), Integer.parseInt( theYCoor.getText( ) ), smallPic.isSelected( ) ? 0 : mediumPic.isSelected( ) ? 1 : 2, theFillBox.isSelected( ) ); theMessage.setText( "" ); } catch( NumberFormatException e ) { theMessage.setText( "Incomplete input" ); } } Swing Adaptadores e classes internas JFrame WindowListener JFrame windowClosing windowClosed windowIconified windowOpened ... extends WindowListener windowClosing windowClosed windowIconified windowOpened ... extends implements implements ClosableFrame ClosableFrame (classe interior) • Jframe por si só não fecha extends BasicGUI • Para ter uma janela que feche implementa-se o WindowListener • Obriga a implementar muitos métodos vazios WindowAdapter extends • Adaptador implementa todos os métodos vazios e permite overriding extends BasicGUI • Por não haver herança múltipla, cria-se uma classe interior (para ter acesso às variáveis de ClosableFrame) que trata dos eventos • esta classe pode ser anónima Swing Tratamento de eventos // Class that implements a Window that closes on a window-close event class CloseableFrame extends JFrame { public CloseableFrame( ) { addWindowListener( new WindowAdapter( ) { public void windowClosing( WindowEvent event ) { System.exit( 0 ); } } ); } } Swing Classe principal class BasicGUI extends CloseableFrame { public static void main( String [ ] args ) { JFrame f = new BasicGUI( ); f.setTitle( "GUI Demo" ); Container contentPane = f.getContentPane( ); contentPane.add( new GUI( ) ); f.pack( ); f.show( ); } } Swing Quadro completo JFrame JComponent WindowListener windowClosing ActionListener implements ActionPerformed extends extends WindowAdapter JPanel implements ClosableFrame (classe interior) extends extends extends GUI includes GUICanvas JComboBox JList ... extends GUICanvas BasicGUI includes BasicGUI (contentPane) GUI Swing Arquitectura MVC Arquitectura para construção de aplicações OO em que se separam três dimensões Modelo: mantém dados usando os algoritmos apropriados e fornece métodos de acesso Vista: constroi uma representação visual de parte ou todos os dados do modelo Controlador: trata os eventos Quando o modelo altera os seus dados, gera eventos que fazem com que a vista actualize a sua representação, segundo as ordens do controlador Podem existir várias vistas e controladores para o mesmo modelo, o qual pode permancer inalterado quando este evolui Swing Comunicação MVC Uma alteração no modelo provoca um evento de alteração que é difundido para todos os objectos que estão à escuta desse evento e desencadeia as alterações Facilita manter o sincronismo entre vistas diferentes de um mesmo modelo Actuar numa vista pode provocar alterações no modelo que são reflectidas nas outras vistas actualiza Vista 1 vê dados actualiza vê dados Vista 2 altera altera Modelo Controlador altera No exemplo anterior, o modelo não está claramente separado da vista (GUI) as variáveis estão “misturadas” na tela GUICanvas Evento Swing Arquitectura MVC em Swing Um componente Swing leve inclui os seguintes objectos Um modelo que mantém os dados ( modelo da MVC básica) fornece métodos de acesso notifica os listeners quando é alterado Um delegado da IU que é uma vista ( vista) com listeners ( controladores) combina as duas funções colocando os listeners junto dos objectos controlados listeners são habitualmente implementados por classes internas Um componente que estende JComponent um componente fornece uma API para o programador transfere a construção de interfaces para os delegados; passa-lhes os eventos torna o modelo transparente para o programador; atravessado pelos métodos Facilita acopular diferentes estilos de interfaces (look & feel) Macintosh, Windows, Motif, Metal Swing Comunicação MVC em Swing Componente Faz alterações ao modelo e faz seguir para o modelo alterações que venham da interface Escutam o modelo para passarem os eventos para os seus listeners Listeners do delegado IU Tanto escutam o modelo como o componente Modelo actualiza Delegado IU actualiza vê dados Listeners altera altera actualiza Componente altera Pedem informação ao modelo Alteram o próprio delegado Evento Swing Perspectiva estática de um componente Bounded RangeModel DefaultBounded RangeModel JComponent Component UI JSlider SliderUI Focus Handler Scroll Listener Track Listener Metal SliderUI BasicSliderUI Windows SliderUI Component Handler PropertyChange Handler Change Handler Motif SliderUI Swing Eventos de modelo Um modelo pode produzir muitos eventos Eventos leves: ChangeEvent só indicam o objecto fonte do evento Ex: posição de uma barra de deslocamento ChangeListener Eventos com estado Transportam os parâmetros tipicamente necessários para o processamento Ex: retirar um elemento de uma lista PropertyChangeListener Swing