Interfete grafice 2

Suprafete de afisare (paneluri)

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);
        }
    }
 
}

Exemplu utilizare JPanel si JTabbedPane

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 );
      }
}
 

Exemplu utilizare 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);
  }
}

Desenarea si afisarea 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 java.awt.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();
            }
      }    
}

Pozitionarea 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();
    }
}