Interfeţe grafice. 1

Ierarhia claselor folosite pentru construire de interfeţe grafice. 1

Suprafeţe de afişare. 2

Unelte pentru desenare şi afişarea imaginilor 7

Poziţionarea componentelor pe ecran. 11

Poziţionarea componentelor folosind gestionari de poziţionare. 13

Exerciţii 16

 

Interfeţe grafice

 

Interfeţele grafice (Graphical User Interfaces) reprezintă ferestre ce conţin elemente grafice ce permit interacţiunea dintre aplicaţie şi utilizator. Limbajul java pune la dispoziţia programatorului două biblioteci pentru realizarea interfeţelor grafice: java.awt şi java.swing.

 

Ierarhia claselor folosite pentru construire de interfeţe grafice

 

În figura 1 este prezentată ierarhia claselor folosite pentru construire de interfeţe grafice în Java.

 

Figura 1. Ierarhia claselor Swing

 

 

 

Suprafeţe de afişare

 

Crearea obiectelor grafice nu realizează automat si afişarea lor pe ecran. Mai întâi ele trebuie aşezate pe o suprafaţă, care poate fi o fereastra sau suprafaţa unui applet, si vor deveni vizibile în momentul în care suprafaţa pe care sunt afişate va fi vizibila. O astfel de suprafaţă pe care se aşează obiectele grafice se numeşte suprafaţă de afişare sau container si reprezintă o instanţa a unei clase obţinuta prin extensia superclasei JContainer. Atenţie, nu toate suprafeţele de afişare din java pot fi afişate direct pe ecran, unele dintre ele având nevoie de o altă suprafaţă în cadrul cărora sa fie adăugate.

 

Suprafeţele de afişare au asociate câte un gestionar de poziţionare care se ocupă cu poziţionarea componentelor în cadrul suprafeţei (se va discuta despre gestionarii de poziţionare în cadrul subcapitolului „Poziţionarea componentelor pe ecran”).

 

JFrame reprezintă o suprafaţă de afişare ce poate fi folosită ca şi container de bază pentru a afişa o interfaţa grafică. O fereastră de acest tip are asociate butoane de minimizare, maximizare şi închidere. De asemenea poate avea ataşată o bară de meniuri. Acest tip de componentă este folosit pentru contruirea ferestrei principale a aplicaţiei.  

 

JDialog este o suprafaţă de afişare folosită pentru construirea ferestrelor de dialog.

 

JPanel este o suprafaţă ce permite gruparea a mai multor componente grafice.

 

JTabbedPane permite definirea unui set de suprafeţe ce folosesc în comun acelaşi spaţiu, utilizatorul putând selecta componenta care să fie vizibilă.

 

JScrollPane permite vizualizarea componentelor a căror suprafaţă este mai mare decât suprafaţa de afişare prin intermediul barelor de derulare orizontale şi verticale.

 

Programul următor exemplifică utilizarea suprafeţelor JFrame şi JDialog.

 

package isp.grafic.dialog;

 

import javax.swing.*;

import java.awt.event.*;

 

public class TestTheDialog extends JFrame implements ActionListener {

  

    JButton myButton = null;

 

    public TestTheDialog() {

        setTitle("Test Dialog");

        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        myButton = new JButton("Test the dialog!");

        myButton.addActionListener(this);

        setLocationRelativeTo(null);

        add(myButton);

        pack();

        setVisible(true);

    }

   

    public void actionPerformed(ActionEvent e) {

        if(myButton == e.getSource()) {

            System.err.println("Opening dialog.");

            CustomDialog myDialog = new CustomDialog(this, true, "Do you like Java?");

            System.err.println("After opening dialog.");

            if(myDialog.getAnswer()) {

                System.err.println("The answer stored in CustomDialog is 'true' (i.e. user clicked yes button.)");

            }

            else {

                System.err.println("The answer stored in CustomDialog is 'false' (i.e. user clicked no button.)");

            }

        }

    }

 

    public static void main(String argv[]) {

        TestTheDialog tester = new TestTheDialog();

    }

}

 

class CustomDialog extends JDialog implements ActionListener {

    private JPanel myPanel = null;

    private JButton yesButton = null;

    private JButton noButton = null;

    private boolean answer = false;

    public boolean getAnswer() { return answer; }

 

    CustomDialog(JFrame frame, boolean modal, String myMessage) {

        super(frame, modal);

        myPanel = new JPanel();

        getContentPane().add(myPanel);

        myPanel.add(new JLabel(myMessage));

        yesButton = new JButton("Yes");

        yesButton.addActionListener(this);

        myPanel.add(yesButton);       

        noButton = new JButton("No");

        noButton.addActionListener(this);

        myPanel.add(noButton);       

        pack();

        setLocationRelativeTo(frame);

        setVisible(true);

    }

 

    public void actionPerformed(ActionEvent e) {

        if(yesButton == e.getSource()) {

            System.err.println("User chose yes.");

            answer = true;

            setVisible(false);

        }

        else if(noButton == e.getSource()) {

            System.err.println("User chose no.");

            answer = false;

            setVisible(false);

        }

    }

   

}

 

Programul următor exemplifică folosirea suprafeţelor JPanel şi JTabbedPane.

 

 

import java.awt.*;

import javax.swing.*;

 

public class JTabbedPaneExample

            extends     JFrame

{

      private           JTabbedPane tabbedPane;

      private           JPanel            panel1;

      private           JPanel            panel2;

      private           JPanel            panel3;

 

 

      public JTabbedPaneExample()

      {

           

            setTitle( "Tabbed Pane Application" );

            setSize( 300, 200 );

            setBackground( Color.gray );

 

            JPanel topPanel = new JPanel();

            topPanel.setLayout( new BorderLayout() );

            getContentPane().add( topPanel );

 

            // Create the tab pages

            createPage1();

            createPage2();

            createPage3();

 

            // Create a tabbed pane

            tabbedPane = new JTabbedPane();

            tabbedPane.addTab( "Page 1", panel1 );

            tabbedPane.addTab( "Page 2", panel2 );

            tabbedPane.addTab( "Page 3", panel3 );

            topPanel.add( tabbedPane, BorderLayout.CENTER );

      }

 

      public void createPage1()

      {

            panel1 = new JPanel();

            panel1.setLayout( null );

 

            JLabel label1 = new JLabel( "Username:" );

            label1.setBounds( 10, 15, 150, 20 );

            panel1.add( label1 );

 

            JTextField field = new JTextField();

            field.setBounds( 10, 35, 150, 20 );

            panel1.add( field );

 

            JLabel label2 = new JLabel( "Password:" );

            label2.setBounds( 10, 60, 150, 20 );

            panel1.add( label2 );

 

            JPasswordField fieldPass = new JPasswordField();

            fieldPass.setBounds( 10, 80, 150, 20 );

            panel1.add( fieldPass );

      }

 

      public void createPage2()

      {

            panel2 = new JPanel();

            panel2.setLayout( new BorderLayout() );

 

            panel2.add( new JButton( "North" ), BorderLayout.NORTH );

            panel2.add( new JButton( "South" ), BorderLayout.SOUTH );

            panel2.add( new JButton( "East" ), BorderLayout.EAST );

            panel2.add( new JButton( "West" ), BorderLayout.WEST );

            panel2.add( new JButton( "Center" ), BorderLayout.CENTER );

      }

 

      public void createPage3()

      {

            panel3 = new JPanel();

            panel3.setLayout( new GridLayout( 3, 2 ) );

 

            panel3.add( new JLabel( "Field 1:" ) );

            panel3.add( new TextArea() );

            panel3.add( new JLabel( "Field 2:" ) );

            panel3.add( new TextArea() );

            panel3.add( new JLabel( "Field 3:" ) );

            panel3.add( new TextArea() );

      }

 

    // Main method to get things started

      public static void main( String args[] )

      {

            // Create an instance of the test application

            JTabbedPaneExample mainFrame  = new JTabbedPaneExample();

            mainFrame.setVisible( true );

      }

}

 

Programul următor exemplifică folosirea suprafeţei de tip JScrollPane.

 

 

import javax.swing.*;

import java.awt.*;

 

public class JScrollListExample extends JFrame {

 

  JScrollPane scrollpane;

 

  public JScrollListExample() {

    super("JScrollPane Demonstration");

    setSize(300, 200);

    setDefaultCloseOperation(EXIT_ON_CLOSE);

 

    String categories[] = { "Household", "Office", "Extended Family",

                            "Company (US)", "Company (World)", "Team",

                            "Will", "Birthday Card List", "High School",

                            "Country", "Continent", "Planet" };

    JList list = new JList(categories);

    scrollpane = new JScrollPane(list);

 

    getContentPane().add(scrollpane, BorderLayout.CENTER);

  }

 

  public static void main(String args[]) {

    JScrollListExample sl = new JScrollListExample();

    sl.setVisible(true);

  }

}

 

Unelte pentru desenare şi afişarea imaginilor

 

În cadrul unei componente grafice (ce extinde clasa JComponent) desenarea se poate face folosind contextul grafic al acesteia. Contextul grafic este reprezentat de un obiect de tip Graphics. Pentru a desena în cadrul unei componente de obicei este suficient să se suprascrie metoda paintComponent(Graphics g), având grija ca prima instrucţiune din cadrul metodei suprascrise să fie apelul către metoda de bază suprascrisa: super.paintComponent(Graphics g);.

 

Clasa Graphics pune la dispoziţia programatorului un set de metode pentru desenare şi afişare de imagini. Câteva dintre aceste metode sunt:

 

drawArfc(...)

drawImageArfc(...)

drawLineArfc(...)

drawOvalArfc(...)

drawString(...)

drawPolygin()

fillArc(...)

fillOval()

fillPolygonRect()

 

Analizaţi documentaţia clasei Graphics şi determinaţi toate metodele pe care le puteţi folosi pentru a desena pe ecran.

 

În programul următor este folosit o componentă de tip JPanel pentru a desena în cadrul acesteia o funcţie sinus.

 

 

package isp.grafic.deseneaza;

 

import javax.swing.*;

import java.awt.*;

 

/** Example demonstrating drawPolyline().*/

public class SinExample extends JFrame

{

  public SinExample()  {

     

       

      this.setSize(new Dimension(300,200)); 

    int width = getSize ().width;

    int height= getSize ().height;

 

    int num_points = 21;

 

    // Create an instance of DrawingPanel

    Polygon1Panel polygon1_panel =

        new Polygon1Panel (width,height,num_points);

     // Add the DrawingPanel to the contentPane.

    add (polygon1_panel);

    pack();

    setVisible(true);

 

  }

 

  public static void main(String[] args) {

            new SinExample();

      }

}

 

/** Draw a polygon with drawPolyline() on

  * this JPanel subclass. **/

class Polygon1Panel extends JPanel

{

  int fWidth,fHeight;

  int fNumPoints;

  double fFactor;

 

  Polygon1Panel (int width, int height, int nPoints) {

    fNumPoints = nPoints;

    fWidth = width;

    fHeight= height;

    fFactor = 2.0 * Math.PI / fWidth;

    this.setPreferredSize(new Dimension(width,height));

  } // ctor

 

  public void paintComponent (Graphics g) {

    // First paint background unless you will

    // paint whole area yourself.

    super.paintComponent (g);

 

    // Create arrays of points for each

    // segment of the polygon

    int [] x = new int[fNumPoints];

    int [] y = new int[fNumPoints];

 

    // Select horizontal step size

    double x_del=  ((double)fWidth)/ (fNumPoints-1);

 

    // Find coordinates of the display center

    int x_offset = fWidth/2;

    int y_offset = fHeight/2;

 

    // Choose amplitude for the sine curve

    int amp =  (int) (y_offset * 0.9);

 

    // Create a sine curve from a sequence

    // of short line segments

    for  (int i=0; i < fNumPoints; i++) {

      x[i] =  (int) (i * x_del);

      y[i] =  (int) (amp * Math.sin (fFactor * x[i]) )

              + y_offset;

    }

 

    // Set the line color to red

    g.setColor (Color.red);

 

    // Draw curve with single call to drawPolyline

    g.drawPolyline (x,y,fNumPoints);

 

    // Change the line color and draw the x-y axes

    g.setColor (Color.green);

    g.drawLine (0,y_offset,fWidth-1,y_offset);

    g.drawLine (x_offset,0,x_offset,fHeight-1);

 

  } // paintComponent

 

} // class Polygon1Panel

 

Programul următor exemplifică folosirea contextului grafic pentru afişarea de imagini pe ecran. Imaginile sunt reprezentate în java de obiecte de tip Image. Încărcarea unei imagini de pe disc în cadrul unui obiect de tip Image se face folosind clasa Toolkit.

 

package isp.grafic.deseneaza;

import java.awt.*;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

 

import javax.swing.*;

import javax.swing.border.LineBorder;

 

import java.io.*;

public class ImageExample extends JFrame implements ActionListener{

 

      JButton bLoad;

      final JFileChooser fc = new JFileChooser();

      ImagePanel p;

     

      public ImageExample(){

            setTitle("Image viewer");

            setLayout(new BorderLayout());

            this.setDefaultCloseOperation(EXIT_ON_CLOSE);

           

            bLoad = new JButton("Load image");

            bLoad.addActionListener(this);

                 

            p  = new ImagePanel();

            p.setPreferredSize(new Dimension(400,400));

            p.setBorder(new LineBorder(Color.BLACK));

           

            add(p,BorderLayout.CENTER);

            add(bLoad,BorderLayout.SOUTH);

           

            pack();

            setVisible(true);

      }

     

      public void actionPerformed(ActionEvent e) {

            //load image from file and display it on screen

            int returnVal = fc.showOpenDialog(this);

 

        if (returnVal == JFileChooser.APPROVE_OPTION) {

            File file = fc.getSelectedFile();

           //This is where a real application would open the file.

            p.displayImage(file);

        } else {

           System.out.println("Error loading file.");

        }

      }

     

      public static void main(String[] args) {

            new ImageExample();

      }

     

      class ImagePanel extends JPanel{

            File f;

            public void paintComponent(Graphics g){

                  super.paintComponent(g);

                  if(f!=null){

                  Toolkit toolkit = Toolkit.getDefaultToolkit();

                  Image image = toolkit.getImage(f.getAbsolutePath());

                  g.drawImage(image, 0,0,this);

                  }

            }

 

            public void displayImage(File f) {

                  this.f = f;

                  repaint();

            }

      }    

}

 

Poziţionarea componentelor pe ecran

 

Componentele grafice pot fi poziţionate în cadrul ferestrelor prin două metode. Prima metodă este poziţionarea relativă faţă de colţul din stânga sus al ferestrei. A doua metodă este prin folosirea unui gestionar de poziţionare (layout manager).

 

Poziţionarea absolută a componentelor

 

În mod implicit ferestrele grafice java au instalat un gestionar de poziţionare, astfel încât pentru a putea poziţiona componentele relativ la colţul din stânga sus trebuie dezactivat acest gestionar de componente apelând metoda setLayout(null) din cadrul containerului Java.

 

Stabilirea poziţiei şi dimensiunii fiecărei componente ce urmează a fi afişate în cadrul ferestrei se face prin apelarea metodei setBounds(int x, int y, int width, int heigt). Primii doi parametri reprezintă poziţia componentei faţă de colţul din stânga sus al ferestrei iar ultimii doi reprezintă lăţimea, respectiv înălţimea componentei.

 

package ips.grafic.layout;

 

import java.awt.event.*;

import javax.swing.*;

public class NoLayoutExample extends JFrame {

 

public NoLayoutExample(String name) {

super(name);

 

JTextField newItemField;

JList itemsList;

JButton addButton;

JButton removeButton;

 

getContentPane().setLayout(null);

 

//The text field

newItemField = new JTextField();

newItemField.setLocation(12,12);

newItemField.setSize(150,30);

add(newItemField);

 

//The Add button

addButton = new JButton("Add");

addButton.setMnemonic('A');

addButton.setLocation(174, 12);

addButton.setSize(100,30);

add(addButton);

 

//The List

itemsList = new JList();

JScrollPane scrollPane = new JScrollPane(itemsList,

ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,

ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

scrollPane.setLocation(12,45);

scrollPane.setSize(150,150);

add(scrollPane);

 

//The Remove button

removeButton = new JButton("Remove");

removeButton.setMnemonic('R');

removeButton.setLocation(174,45);

removeButton.setSize(100,30);

add(removeButton);

}

 

public static void main(String[] args) {

JFrame frame = new NoLayoutExample("NULL Example");

frame.setDefaultCloseOperation(EXIT_ON_CLOSE);

frame.setSize(286, 230);

frame.setResizable(false);

frame.setVisible(true);

}

}

 

Se recomandă folosirea gestionarilor de poziţionare de fiecare dată când este posibil deoarece aceştia permit interfeţelor grafice să aibă aceiaşi „înfăţişare” indiferent de rezoluţie sau de dimensiunea ferestrei.

 

Poziţionarea componentelor folosind gestionari de poziţionare

 

Un gestionar de poziţionare este o componentă ce asigură aranjare componentelor grafice dintr-o fereastră. Fiecare fereastră java are asociat un astfel de gestionar. Setarea unui gestionar se face folosind metoda setLayout(gestionar), unde obiectul gestionar reprezintă un obiect de tip gestionar de poziţionare.

 

În continuare vor fi prezentate exemple de utilizare a câtorva dintre cei mai utilizaţi gestionari de poziţionare în java.

 

Gestionarul FlowLayout

 

Acest gestionar afişează componentele liniar una după alta în ordinea în care acestea au fost adăugate. În momentul în care nu mai este spaţiu pe linia curentă se trece a următoarea linie.      

 

 

import java.awt.Container;

import java.awt.FlowLayout;

import javax.swing.JButton;

import javax.swing.JFrame;

 

import java.awt.Dimension;

import java.awt.ComponentOrientation;

 

public class FlowLayoutDemo extends JFrame{

     

      public FlowLayoutDemo(String s) {

        setLayout(new FlowLayout());

        setTitle(s);

        add(new JButton("Button 1"));

        add(new JButton("Button 2"));

        add(new JButton("Button 3"));

        add(new JButton("Long-Named Button 4"));

        add(new JButton("5"));

       

        pack();

        setVisible(true);

    }

 

  

    public static void main(String[] args) {

      new FlowLayoutDemo("flow demo");

    }

}

 

Gestionarul BorderLayout

 

Gestionarul BorderLayout împarte suprafaţa de afişare în cinci regiuni, corespunzatoare celor patru puncte cardinale si centrului. O componenta poate fi plasata în oricare din aceste regiuni, dimensiunea componentei fiind calculata astfel încât să ocupe întreg spaţiul de afişare oferit de regiunea respectiva.

 

 

package ips.grafic.layout;

 

import java.awt.*;

 

import javax.swing.JFrame;

public class TestBorderLayout {

      public static void main(String args[]) {

            JFrame f = new JFrame("Border Layout");

            f.setLayout(new BorderLayout());//poate sa lipseasca

     

            f.add(new Button("Nord"), BorderLayout.NORTH);

            f.add(new Button("Sud"), BorderLayout.SOUTH);

            f.add(new Button("Est"), BorderLayout.EAST);

            f.add(new Button("Vest"), BorderLayout.WEST);

            f.add(new Button("Centru"), BorderLayout.CENTER);

            f.pack();

            f.setVisible(true);

      }

}

 

Gestionarul GridLayout

 

Acest gestionar organizează suprafaţa de afişare ca un tabel cu x coloane şi y linii. Fiecare componentă este aşezată în câte o celulă. Căsuţele au dimensiuni egale, iar fiecare componentă poate ocupa o singură celulă.

 

 

package ips.grafic.layout;

 

import java.awt.*;

import javax.swing.*;

 

public class GridLayoutDemo extends JFrame{

 

      public GridLayoutDemo(){

     

        setLayout(new GridLayout(2,2));

        add(new JButton("Button 1"));

        add(new JButton("Button 2"));

        add(new JButton("Button 3"));

        add(new JButton("Long-Named Button 4"));

       

        pack();

        setVisible(true);

    }

 

 

 

    public static void main(String[] args) {

      new GridLayoutDemo();

    }

}

 

Gestionarul CardLayout

 

 

 

Gestionarul CardLayout tratează componentele adăugate pe suprafata într-o maniera asemănătoare cu cea a dispunerii carţilor de joc într-un pachet. Suprafaţa de afişare poate fi asemănata cu pachetul de carţi iar fiecare componenta este o carte din pachet. La un moment dat numai o singura componenta este vizibila.

 

package ips.grafic.layout;

 

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

 

public class CardLayoutDemo extends JFrame implements ItemListener {

    JPanel cards; //a panel that uses CardLayout

    final static String BUTTONPANEL = "JPanel with JButtons";

    final static String TEXTPANEL = "JPanel with JTextField";

   

    public CardLayoutDemo(){

        //Put the JComboBox in a JPanel to get a nicer look.

        JPanel comboBoxPane = new JPanel(); //use FlowLayout

        String comboBoxItems[] = { BUTTONPANEL, TEXTPANEL };

        JComboBox cb = new JComboBox(comboBoxItems);

        cb.setEditable(false);

        cb.addItemListener(this);

        comboBoxPane.add(cb);

 

        //Create the "cards".

        JPanel card1 = new JPanel();

        card1.add(new JButton("Button 1"));

        card1.add(new JButton("Button 2"));

        card1.add(new JButton("Button 3"));

 

        JPanel card2 = new JPanel();

        card2.add(new JTextField("TextField", 20));

 

        //Create the panel that contains the "cards".

        cards = new JPanel(new CardLayout());

        cards.add(card1, BUTTONPANEL);

        cards.add(card2, TEXTPANEL);

 

        add(comboBoxPane, BorderLayout.PAGE_START);

        add(cards, BorderLayout.CENTER);

       

        pack();

        setVisible(true);

    }

 

    public void itemStateChanged(ItemEvent evt) {

        CardLayout cl = (CardLayout)(cards.getLayout());

        cl.show(cards, (String)evt.getItem());

    }

 

    public static void main(String[] args) {

       new CardLayoutDemo();

    }

}

 

 

Exerciţii

 

Exerciţiul 1: Modificaţia aplicaţia Dictionar din cadrul laboratorului Colecţii de obiecte, şi adăugaţi o interfaţă grafică pentru aceasta.

 

Exerciţiu 2: Construiţi o aplicaţie care să permită construirea şi afişarea pe ecran a diferite forme geometrice. Aplicaţia trebuie să permită salvarea desenelor pe disc şi încărcarea desenelor de pe disc (pentru aceasta se va folosi mecanismul de serializare \ deserializare).