javabog.dk  |  << forrige  |  indhold  |  næste >>  |  programeksempler  |  om bogen

11 Grafiske komponenter

Indhold:

Forudsættes af kapitel 13, Hændelser.

Kapitlet forudsætter kapitel 9, Grafiske programmer, og at du har adgang til et værktøj til at udvikle grafiske brugergrænseflader (f.eks. NetBeans, Eclipse eller Oracle JDeveloper).

Når man skal lave en grafisk brugergrænseflade (eng.: GUI, graphical user interface), gøres det oftest ved at anvende standardkomponenter. Vi vil starte med at se på, hvordan det gøres i praksis med et værktøj, og derefter studere den kode, der kommer ud af det.

11.1 Generering med et værktøj

Med et værktøj kan man udarbejde en grafisk brugergrænseflade ud fra standardkomponenter på ret kort tid og uden at skulle programmere ret meget selv.

Herunder er beskrevet, hvordan man gør i NetBeans med sideløbende forklaringer til Oracle JDeveloper og Eclipse. Bruger du et andet værktøj, må du prøve dig lidt frem. Ideerne er de samme og koden, der genereres, ligner også nogenlunde, men menuerne og knapperne varierer selvfølgelig noget.

I NetBeans skal du under 'New File..' vælge 'Swing GUI Forms' og 'JPanel Form'.

I JDeveloper og Eclipse kan du tage en eksisterende klasse, der arver fra JPanel, f.eks. Grafikpanel fra kapitel 9. Hvis du vil oprette en ny, så vælg 'New...' og Application. Skriv et navn på din klasse og klik 'Finish'.

I andre værktøjer: Opret en ny JApplet eller JPanel (bruger du JPanel skal du også huske en Benyt...-klasse).

  1. Find Design-fanen (ved punkt 1 på figuren). Den er delt op i en del, hvor du designer din brugergrænseflade i midten og en tabel af egenskaber til højre (punkt 2).
    JDeveloper: Højreklik på Grafikpanel.java og vælg 'UI Editor'.
    NetBeans: Gå over på fanen 'GUI Editing', hvis du ikke allerede står der.
    Eclipse: Højreklik på Grafikpanel.java og vælg 'Open With' og 'WindowBuilder Editor'

  2. Først skal du først ændre layout til et, der lader dig placere komponenterne som du ønsker (punkt 2 til højre). Det hedder typisk 'Free design', 'null' eller 'AbsoluteLayout'.
    I NetBeans/Eclipse: Højreklik på den grå flade og vælg 'Set Layout'.

  3. Nu kan du gå i gang med at lægge komponenter ind på grænsefladen.
    Vælg først en JLabel fra komponentpaletten (punkt 3) og klik på den grå flade. Der dukker en etikette med en tekst op. På egenskabstabellen til højre kan du ændre dens variabelnavn (name øverst) til f.eks. labelHvadErDitNavn. Længere nede er egenskaben text, der bestemmer, hvad der skal stå på etiketten. Ret den til f.eks. "Hvad er dit navn?".

  4. Indsæt derefter et JTextField (et indtastningsfelt – lidt længere nede i listen).
    Ret variabelnavnet til textFieldNavn og teksten til f.eks. "Jacob".

Gå tilbage til Source-fanen. Nu ser kildeteksten nogenlunde således ud:

import java.awt.*;
import javax.swing.*;

public class Grafikpanel extends JPanel
{
  JLabel labelHvadErDitNavn = new JLabel();
  JTextField textFieldNavn = new JTextField();

  public void paintComponent(Graphics g)
  {
    super.paintComponent(g);              // tegn først baggrunden på panelet
    g.drawLine(0,0,50,50);
    g.fillOval(5,10,300,30);
    g.setColor(Color.GREEN);
    g.drawString("Hej grafiske verden!",100,30);
  }

  public Grafikpanel() {
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception {
    labelHvadErDitNavn.setText("Hvad er dit navn?");
    labelHvadErDitNavn.setBounds(new Rectangle(15, 69, 108, 15));
    textFieldNavn.setText("Jacob");
    textFieldNavn.setBounds(new Rectangle(141, 61, 112, 29));
    this.setLayout(null);
    this.add(textFieldNavn);
    this.add(labelHvadErDitNavn);
  }
}

De to objekter, vi satte på i designeren, er erklæret og oprettet øverst uden for metoderne:

  JLabel labelHvadErDitNavn = new JLabel();
  JTextField textFieldNavn = new JTextField();

Nedenunder står vores gamle paintComponent() uændret. Herunder er der oprettet en konstruktør, der kalder metoden jbInit(). I NetBeans hedder metoden initComponents().

Den andet kode, 'try{ ... } catch (Exception e) {...}' er beregnet til at håndtere exception og vil blive forklaret i kapitel 14, Exceptions. Se bort fra den for nu.

I metoden jbInit() nedenunder lægger værktøjet koden til at initialisere de grafiske komponenter. Man ser her, hvordan både JLabel og JTextField har metoden setText() og at begge objekter får kaldt denne metode (svarende til, at vi ændrede egenskaben text).

    labelHvadErDitNavn.setText("Hvad er dit navn?");
    textFieldNavn.setText("Jacob");

De andre kommandoer i jbInit() sørger for at placere komponenterne korrekt i vinduet.

"Design"- og "Source"-fanen er to måder at se programmet på og man kan frit skifte mellem dem. Laver man en designændring, vil det blive afspejlet i koden i jbInit(). Ændrer man i koden, vil designet ændre sig (i NetBeans er kildekoden dog beskyttet mod ændringer).

Retter du eller tilføjer kode til værktøjets genererede kode, så sørg for, at det ligner værktøjets egen kode, ellers kan værktøjet have svært ved at opretholde sammenhængen mellem kode og design.

Anden kode kan du putte i konstruktøren, f.eks. lige over eller under kaldet til jbInit().

11.1.1 Interaktive programmer

Lad os nu tilføje en knap og et indtastningsfelt på flere linjer (JTextArea). Jeg kalder dem for buttonOpdater og textAreaHilsen. Knappen skal selvfølgelig gøre noget. Fra Design-fanen, dobbeltklik på knappen, og vupti! Der genereres automatisk en metode til at håndtere et klik (og pakken java.awt.event bliver importeret):

  void buttonOpdater_actionPerformed(ActionEvent e) {

  }

Hvis du kigger i jbInit(), kan du se, at JBuilder har indsat følgende kode:

    buttonOpdater.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        buttonOpdater_actionPerformed(e);
      }
    });

Det er disse linjer, der sørger for at "lytte efter hændelser" på knappen, sådan at når man klikker på buttonOpdater, så kaldes metoden buttonOpdater_actionPerformed(). Det vil vi komme tilbage til i kapitel 13, Hændelser.

Nu kan du indsætte kode, der udfører en handling. Skriv f.eks. noget ud til systemoutput:

  void buttonOpdater_actionPerformed(ActionEvent e) {
    System.out.println("Opdater!");
  }

Vi kunne også lave noget sjovere, f.eks. læse den indtastede tekst fra textFieldNavn og skrive den i textAreaHilsen. JBuilder har lavet koden, der sætter teksterne for os og ved at studere den kan man få en ide til, hvordan det skal gøres:

    String navn = textFieldNavn.getText();     // aflæs navnet

    textAreaHilsen.setText("Hej kære "+navn);  // sæt navnet

Her har vi tastet "Jacob Nordfalk" ind og trykket på "opdater!"-knappen (paintComponent() er ændret til også at tegne navnet 5 gange).

Her kommer det fulde eksempel med en main-metode, der viser vinduet.

import javax.swing.*;
public class BenytGrafikpanelMedKomponenter
{
  public static void main(String[] arg)
  {
    JFrame vindue = new JFrame( "GrafikpanelMedKomponenter" ); 
    vindue.add( new GrafikpanelMedKomponenter() );
    vindue.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    vindue.setSize(350,300);
    vindue.setVisible(true);
  }
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class GrafikpanelMedKomponenter extends JPanel
{
  JLabel labelHvadErDitNavn = new JLabel();
  JTextField textFieldNavn = new JTextField();
  JButton buttonOpdater = new JButton();
  JTextArea textAreaHilsen = new JTextArea();

  public void paintComponent(Graphics g)
  {
    super.paintComponent(g);     // tegn baggrunden på panelet
    g.drawLine(0,0,50,50);
    g.fillOval(5,10,300,30);
    g.setColor(Color.GREEN);
    String navn = textFieldNavn.getText();
    for (int i=0; i<50; i=i+10)
      g.drawString("Hej "+navn+" !",100+i,30+i);
  }

  public GrafikpanelMedKomponenter() {
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  /** Udviklingsværktøjets initialisering af komponenter.
   *  Udviklingsværktøj definerer gerne en separat metode hvor de 
   *  initialiserer komponenterne. I JBuilder og JDeveloper hedder
   *  den jbInit(), mens den hedder initComponents() i Betbeans.
   *  Initialiseringen kunne dog lige så godt ligge direkte i konstruktøren.
   *  Ændr med varsomhed, ellers kan værktøjet ikke genkende "sin" kode!
   */
  private void jbInit() throws Exception {
    labelHvadErDitNavn.setText("Hvad er dit navn?");
    labelHvadErDitNavn.setBounds(new Rectangle(15, 69, 108, 15));
    textFieldNavn.setText("Jacob");
    textFieldNavn.setBounds(new Rectangle(129, 61, 95, 29));
    buttonOpdater.setText("Opdater!");
    buttonOpdater.setMnemonic(KeyEvent.VK_O);
    buttonOpdater.setBounds(new Rectangle(231, 60, 91, 32));
    buttonOpdater.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        buttonOpdater_actionPerformed(e);
      }
    });
    textAreaHilsen.setText("Her kommer en tekst...");
    textAreaHilsen.setBounds(new Rectangle(6, 102, 316, 78));
    this.setLayout(null);
    this.add(labelHvadErDitNavn);
    this.add(textAreaHilsen);
    this.add(buttonOpdater);
    this.add(textFieldNavn);
  }

  void buttonOpdater_actionPerformed(ActionEvent e) {
    String navn = textFieldNavn.getText();
    System.out.println("Opdater! navn="+navn);
    textAreaHilsen.setText("Hej kære "+navn);
    repaint(); // gentegn vinduet
  }
}

11.1.2 Genvejstaster

Genvejstaster kan laves på de fleste komponenter med kaldet setMnemonic(). I ovenstående eksempel kan man trykke Alt-O for at trykke på knappen 'Opdater', fordi vi kaldte:

    buttonOpdater.setMnemonic(KeyEvent.VK_O);

11.2 Overblik over komponenter

Grafiske komponenter er objekter, der bruges som en synlig del af en grafisk brugergrænseflade, f.eks. knapper, valglister, indtastningsfelter, etiketter.

Alle komponenter arver fra JComponent-klassen og har derfor dennes træk til fælles:

Metoderne setForeground(Color c) og setBackground(Color c) sætter hhv. forgrundsfarven og baggrundsfarven for komponenten, svarende til egenskaberne foreground og background. Egenskaberne kan aflæses med getForeground() og getBackground().

En anden egenskab er font, der bestemmer skrifttypen. I tråd med de andre egenskaber sættes den med setFont(Font f) og aflæses med getFont().

Dette kan sammenfattes i en tabel over egenskaber, der er fælles for alle komponenter.

Egenskab

Type

Sættes med

Læses med

foreground

Color

setForeground(Color c)

getForeground()

background

Color

setBackground(Color c)

getBackground()

font

Font

setFont(Font f)

getFont()

visible

boolean

setVisible(boolean synlig)

isVisible()

Nedenfor er de mest almindelige komponenter beskrevet sammen med deres egenskaber.

11.2.1 JLabel

En etiket, der viser en tekst (som brugeren ikke kan redigere i).

Udover de fælles egenskaber findes egenskaben text, der angiver, hvad der står i feltet.

Egenskab

Type

Sættes med

Læses med

text

String

setText(String t)

GetText()

Mere info: http://docs.oracle.com/javase/tutorial/uiswing/components/label.html

11.2.2 JButton

En trykknap. Egenskaben text angiver, hvad der står på knappen.

Egenskab

Type

Sættes med

Læses med

text

String

setText(String t)

getText()

11.2.3 JCheckBox og JRadioButton


JCheckBox giver et afkrydsningsfelt, som brugeren kan sætte et flueben i (eller fjerne).

JRadioButton bruges til radioknapper, der gensidigt udelukker hinanden. En gruppe af radioknapper skal knyttes sammen af et ButtonGroup-objekt (se eksemplet senere).

text angiver, hvad der står ved feltet. selected angiver, om feltet/radioknappen er afkrydset.

Egenskab

Type

Sættes med

Læses med

text

String

setText(String t)

getText()

selected

boolean

setSelected (boolean afkrydset)

IsSelected()

11.2.4 JTextField

Et indtastningsfelt på én linje. Egenskaben text angiver, hvad der står i feltet.

columns angiver, hvor bredt feltet skal være.

editable angiver, om brugeren kan redigere teksten i indtastningsfeltet.

Egenskab

Type

Sættes med

Læses med

text

String

setText(String t)

getText()

editable

boolean

setEditable(boolean rediger)

isEditable()

columns

int

setColumns(int bredde)

getColumns()

11.2.5 JTextArea

Et indtastningsfelt på flere linjer.

Egenskaberne text, rows og columns angiver, hvad der står i feltet, hhv. bredde og højde.

Egenskab

Type

Sættes med

Læses med

text

String

setText(String t)

getText()

editable

boolean

setEditable(boolean rediger)

isEditable()

columns

int

setColumns(int bredde)

getColumns()

rows

int

setRows(int højde)

getRows()

JTextField og JTextArea har en del egenskaber til fælles og disse fællestræk ligger i superklassen JTextComponent, der også har andre arvinger, f.eks. JPasswordField og JTextPane (der tillader redigering af HTML- og RTF-tekst med typografier).

11.2.6 JComboBox

En valgliste. Det er nemmest at bruge metoden addItem(String elementnavn) til at tilføje indgange, men der er også bl.a. mulighed for at give et array af elementer i konstruktøren.

  JComboBox comboBox1 = new JComboBox();
...
    comboBox1.addItem("ComboBox Rød");
    comboBox1.addItem("ComboBox Grøn");
    comboBox1.addItem("ComboBox Blå");

Med getSelectedItem() undersøger man, hvad brugeren har valgt. Hvis man foretrækker at kende nummeret på det valgte element, bruger man getSelectedIndex().

Se også: http://docs.oracle.com/javase/tutorial/uiswing/components/combobox.html .

11.2.7 JList



En liste, hvor flere af indgangene kan ses samtidigt og hvor man kan vælge en eller flere elementer. Desværre er komponenten lidt svær at bruge for begyndere; det nemmeste er at oprette et array af elementer og overføre arrayet i konstruktøren:

  String[] listedata = {"List rød", "List grøn", "List blå"};
  JList list1 = new JList(listedata);

Med getSelectedValue() undersøger man, hvad brugeren har valgt. Hvis man foretrækker at kende nummeret på det valgte element bruger man getSelectedIndex().

Egenskaberne rows og multipleMode angiver hhv. hvor mange indgange, der kan ses ad gangen og om man kan vælge flere indgange samtidigt (ved at holde Ctrl nede og klikke).

Egenskab

Type

Sættes med

Læses med

rows

int

setRows(int højde)

getRows()

multipleMode

boolean

setMultipleMode(boolean m)

getMultipleMode()

Er multipleMode slået til, kan man løbe gennem antallet af indgange og for hver indgang bruge isIndexSelected(int indeks) til at se, om indgangen er valgt.

11.3 Eksempel

Herunder et eksempel med komponenterne omtalt i forrige afsnit.




import javax.swing.*;
public class BenytOverblikOverKomponenter
{
  public static void main(String[] arg)
  {
    JFrame vindue = new JFrame( "OverblikOverKomponenter" ); 
    vindue.add( new OverblikOverKomponenter() );
    vindue.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    vindue.setSize(500,150);
    vindue.setVisible(true);
  }
}
import java.awt.*;
import javax.swing.*;

public class OverblikOverKomponenter extends JPanel
{
  // opret alle komponenterne og husk dem i nogle felter
  JLabel label1 = new JLabel();
  JButton button1 = new JButton();
  JCheckBox checkbox1 = new JCheckBox();
  JCheckBox checkbox2 = new JCheckBox();
  JCheckBox checkbox3 = new JCheckBox();
  JRadioButton radio1 = new JRadioButton();
  JRadioButton radio2 = new JRadioButton();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JTextField textField1 = new JTextField();
  JTextArea textArea1 = new JTextArea();
  JComboBox comboBox1 = new JComboBox();

  String[] listedata = {"List rød", "List grøn", "List blå"};
  JList list1 = new JList(listedata);

  FlowLayout flowLayout1 = new FlowLayout(); // layout-manager (se senere)

  public OverblikOverKomponenter() {
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception {
    label1.setText("En Label");

    button1.setText("OK");

    checkbox1.setText("En");    // sæt afkrydsningsfelternes navne
    checkbox2.setText("To");
    checkbox3.setText("Tre");

    radio1.setText("Radio1");   // sæt radioknappernes navne og
    radio2.setText("Radio2");
    buttonGroup1.add(radio1);   // gruppe - så de gensidigt udelukker hinanden
    buttonGroup1.add(radio2);
    radio1.setSelected(true);

    comboBox1.addItem("ComboBox Rød");
    comboBox1.addItem("ComboBox Grøn");
    comboBox1.addItem("ComboBox Blå");

    textField1.setColumns(10);
    textField1.setText("Et TextField");

    textArea1.setColumns(15);
    textArea1.setRows(5);
    textArea1.setText("Et TextArea");

    this.setLayout(flowLayout1);// sæt layout-manager (se senere)

    this.add(label1);     // til sidst skal komponenterne føjes
    this.add(button1);    // til containeren (se senere)
    this.add(checkbox1);
    this.add(checkbox2);
    this.add(checkbox3);
    this.add(radio1);
    this.add(radio2);
    this.add(textField1);
    this.add(textArea1);
    this.add(comboBox1);
    this.add(list1);
  }
}

11.4 Overblik over containere

En container er beregnet til at indeholde komponenter og styre, hvordan de vises på skærmen. Alle containere har en såkaldt layout-manager tilknyttet, der hjælper containeren med at afgøre, hvor og med hvilken størrelse komponenterne skal vises.

For at en komponent bliver vist, skal den tilføjes en container. I eksemplet ovenfor er panelet den container, komponenterne bliver tilføjet og derfor står der sidst i initialiseringen:

    this.add(button1);

11.4.1 JWindow

JWindow repræsenterer et bart vindue uden en titellinje eller lukkeknap øverst. Det bruges meget sjældent direkte. Man bruger i stedet arvingerne JFrame og JDialog.

11.4.2 JDialog

Dialog bruges til dialog-bokse, vinduer, der dukker op med et eller andet spørgsmål, som skal besvares, før man kan gå videre. Egenskaben modal angiver, om dialog-boksen er modal, dvs. om man skal lukke den, før man kan få adgang til ejer-vinduet. Den sættes med setModal(boolean m) og aflæses med isModal(). Hvis vinduet er modalt vil et kald til setVisible(true) vente, indtil brugeren har udfyldt og lukket dialog-boksen igen.

I mange tilfælde vil JOptionPane, der er beskrevet i afsnit 2.12.1, være nemmere at bruge. Således kunne man f.eks. vise panelet OverblikOverKomponenter i en dialog med koden:

import javax.swing.*;
public class DialogMedOverblikOverKomponenter
{
  public static void main(String[] arg)
  {
    JOptionPane.showMessageDialog(null,new OverblikOverKomponenter());
  }
}

11.4.3 JFrame

En JFrame er den simpleste og oftest brugte måde at definere et "normalt" vindue med titel, luk-knap, minimér-knap etc. Den er brugt i næsten alle eksempler i denne bog.

11.4.4 JPanel

Et panel er den simpleste og oftest brugte container. Den indeholder simpelthen komponenterne (i henhold til layout-manageren).

Kan ens vindue opdeles i flere logiske dele (f.eks. har JBuilder i afsnit 11.1 en komponentpalette, designvindue og egenskabstabel) er det god praksis at lægge disse i hver sit panel.

11.4.5 Egne paneler som komponenter

JPanel er en meget fleksibel container og er samtidig også en komponent, dvs. man kan tilføje den til enhver anden container (et vindue eller endda til et andet JPanel).

Det gælder også dine egne nedarvninger af JPanel – at de kan bruges som komponenter og bruges i designeren på linje med f.eks. JButton og JTextField. Har du lavet dine egne nogle get- og set-metoder kan disse endda også ses i designeren.

Det er et ekstremt kraftigt værktøj at kunne definere sine egne 'komponenter', da det kan hjælpe med at strukturere den visuelle del af dit program på en fornuftig måde.

I Eclipse skal du vælge 'Choose component' i paletten.

I NetBeans kan du trække javafiler fra projektfanen til venstre direkte over i designeren til højre og anvende dem som komponenter.

11.4.6 JApplet

En applet er et panel, der er beregnet til at blive vist i en browser. Se kapitel 10, Appletter.

11.4.7 JTabbedPane

Et panel, der viser et sæt af faneblade, der hver kan indeholde én komponent – som næsten altid er et et JPanel. Herunder viser vi alle eksemplerne fra dette kapitel i hver sit faneblad:




import javax.swing.*;
public class BenytFaneblade
{
  public static void main(String[] arg)
  {
    JTabbedPane faneblade = new JTabbedPane();

    faneblade.add("GrafikpanelMedKomponenter", new GrafikpanelMedKomponenter());
    faneblade.add("OverblikOverKomponenter", new OverblikOverKomponenter());
    faneblade.add("PanelMedBorderLayout", new PanelMedBorderLayout());
    faneblade.add("PanelMedGridBagLayout", new PanelMedGridBagLayout());

    JFrame vindue = new JFrame("Faneblade");
    vindue.add( faneblade );
    vindue.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // reagér på luk
    vindue.pack();                  // lad vinduet selv bestemme sin størrelse
    vindue.setVisible(true);                                  // åbn vinduet

  }
}

11.5 Layout-managere

En layout-manager styrer layoutet af komponenterne på et JPanel eller en anden container. Alle containere har egenskaben layout, der kan sættes med metoden setLayout(Layout l).

For mere info, se: http://docs.oracle.com/javase/tutorial/uiswing/layout/

11.5.1 Ingen styring (null-layout)

I udviklingsfasen er det mest bekvemt at sætte layout-manageren til null. Dette tillader udvikleren at sætte komponenterne, som han vil på en hvilken som helst (x,y)-position og med en hvilken som helst højde og bredde. Koden ser således ud:

    this.setLayout(null);                              // sæt null-layout
    this.add(button1);                                 // tilføj knap
    button1.setBounds(new Rectangle(231, 60, 91, 32)); // sæt position/størrelse

null-layout tager slet ikke højde for vinduets størrelse, så hvis vinduet bliver for lille, vil nogle af komponenterne ikke blive vist. Når programmet er ved at være færdigt, bør man derfor ændre programmet til at bruge en layout-manager, der kan styre komponenternes størrelse og indbyrdes placering ud fra deres behov.

11.5.2 FlowLayout

FlowLayout placerer komponenterne ligesom tekst, der er centreret: Øverst fra venstre mod højre og på en ny linje nedenunder, når der ikke er mere plads.

I eksemplet OverblikOverKomponenter ovenfor blev FlowLayout brugt (egentligt var det overflødigt at angive, for angiver man ikke nogen layout-manager i et panel/applet, vil FlowLayout blive brugt automatisk).

11.5.3 BorderLayout

BorderLayout tager højde for vinduets størrelse og tilpasser komponenternes størrelse efter den tilgængelige plads. Komponenterne kan placeres på 5 mulige positioner, nemlig NORTH, SOUTH, EAST, WEST og CENTER.

Den mest almindelige måde at lave det grafiske layout af et skærmbillede er med BorderLayout. I de områder, hvor man ønsker at placere flere komponenter, sætter man først et JPanel og komponenterne tilføjes så panelet.

Angiver man ikke nogen layout-manager i et vindue, vil BorderLayout blive brugt (i eksemplet nedenfor kunne de to linjer omkring BorderLayout strengt taget fjernes).

import java.awt.*;
import javax.swing.*;

public class PanelMedBorderLayout extends JPanel
{
  JButton button1 = new JButton();
  JButton button2 = new JButton();
  JButton button3 = new JButton();
  JButton button4 = new JButton();
  JButton button5 = new JButton();

  BorderLayout borderLayout1 = new BorderLayout();

  public PanelMedBorderLayout() {
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception {
    button1.setText("NORTH");
    button2.setText("SOUTH");
    button3.setText("EAST");
    button4.setText("WEST");
    button5.setText("CENTER");

    this.setLayout(borderLayout1);

    this.add(button1, BorderLayout.NORTH);
    this.add(button2, BorderLayout.SOUTH);
    this.add(button3, BorderLayout.EAST);
    this.add(button4, BorderLayout.WEST);
    this.add(button5, BorderLayout.CENTER);
  }
}

Man sætter altså først layoutet ved at kalde setLayout() med et BorderLayout-objekt. Derefter kan add() kaldes med komponenterne og deres placering på borderlayoutet.

Bemærk, at når man bruger en layout-manager, bør man lade den afgøre vinduets størrelse ud fra komponenternes behov, ved at kalde pack() i stedet for setSize() på vinduet. Denne metode pakker komponenterne i vinduet optimalt og sætter vinduesstørrelsen passende.

import javax.swing.*;
public class BenytPanelMedBorderLayout
{
  public static void main(String[] arg)
  {
    JFrame vindue = new JFrame( "PanelMedBorderLayout" ); 
    vindue.add( new PanelMedBorderLayout() );
    vindue.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    vindue.pack();// sætter en rimelig vinduesstørrelse (i stedet for setSize())
    vindue.setVisible(true);
  }
}

11.5.4 GridBagLayout

En anden måde at lave layout er med GridBagLayout, som lægger komponenterne efter et usynligt gitter. Hver komponent kan fylde en eller flere celler i højden eller bredden.

import java.awt.*;
import javax.swing.*;

public class PanelMedGridBagLayout extends JPanel
{
  GridBagLayout gridBagLayout1 = new GridBagLayout();
  JButton   knap1 = new JButton();
  JButton   knap2 = new JButton();
  JButton   knap3 = new JButton();
  JButton   knap4 = new JButton();
  JButton   knap5 = new JButton();
  JCheckBox chkHø = new JCheckBox();
  JCheckBox chkVe = new JCheckBox();
  JCheckBox chkCe = new JCheckBox();
  JTextArea tekst = new JTextArea();

  public PanelMedGridBagLayout() {
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception {
    knap1.setText("knap1 (på 3x1 celler)");
    knap2.setText("knap2 (1x2)");
    knap3.setText("knap3 (på 1x1 celle)");
    knap4.setText("knap4 (1x1)");
    knap5.setText("knap5 (1x1)");
    chkHø.setText("Højre");
    chkVe.setText("Venstre");
    chkCe.setText("Centreret");
    tekst.setColumns(15);
    tekst.setRows(2);
    tekst.setText("Tekstfelt (3x3 celler)");

    this.setLayout(gridBagLayout1);

    // til sidst skal komponenterne føjes til containeren
    this.add(knap1, new GridBagConstraints(0, 0, 3, 1, 0.0, 0.0, 
    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
    this.add(knap2, new GridBagConstraints(3, 0, 1, 2, 0.0, 0.0,
    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
    this.add(knap3, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
    this.add(knap4, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0,
    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
    this.add(knap5, new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0,
    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
    this.add(chkHø, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0,
    GridBagConstraints.EAST,  GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
    this.add(chkVe, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0,
    GridBagConstraints.WEST,  GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
    this.add(chkCe, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0,
    GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
    this.add(tekst, new GridBagConstraints(1, 2, 3, 3, 0.0, 0.0,
    GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
  }
}

Når en komponent tilføjes, angives i et GridBagConstraints-objekt:

  • Komponentens position (cellekolonne og -række)

  • Komponentens spændvidde i højde og bredde

  • Vægt i højde og bredde (komponenter med størst værdi får mest af eventuel overskydende plads)

  • Justering i tilfælde af overskydende plads (CENTER, EAST, WEST, NORTHEAST, ...)

  • Om komponenten skal strækkes til at fylde overskydende plads (BOTH, NONE,
    HORIZONTAL, VERTICAL)

  • Til sidst nogle parametre til indsættelse af ekstra plads.

Her er koden, der viser vinduet.

import javax.swing.*;
public class BenytPanelMedGridBagLayout
{
  public static void main(String[] arg)
  {
    JFrame vindue = new JFrame( "PanelMedGridBagLayout" ); 
    vindue.add( new PanelMedGridBagLayout() );
    vindue.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    vindue.pack();
    vindue.setVisible(true);
  }
}

11.6 Menuer

En JFrame, JApplet og JDialog (men ikke JPanel og andre containere som ikke er selvstændige vinduer) kan have en menubjælke med rullegardiner tilknyttet.

Herunder har vi puttet en menu på vinduet, der viser GrafikpanelMedKomponenter.

Menuer er relativt enkle at lave: En menubjælke laves med new JMenuBar(), en menu (et rullegardin) med new JMenu() og et menupunkt med new JMenuItem(). Derefter skal menupunkterne tilføjes menuerne, og menuerne føjes til menubjælken (er det en undermenu føjes den til overmenuen) med add(). Man sætter teksterne med setText(). Til sidst sættes menubjælken på vinduet ved at kalde vindue.setJMenuBar(menubjælke).

import java.awt.event.*;
import javax.swing.*;

public class BenytGrafikpanelMedKomponenterOgMenu
{
  public static void main(String[] arg)
  {
    JFrame vindue = new JFrame( "GrafikpanelMedKomponenterOgMenu" ); 
    final GrafikpanelMedKomponenter panel = new GrafikpanelMedKomponenter();
    vindue.add( panel );
    vindue.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    vindue.setSize(350,300);

    JMenuBar  menubjælke = new JMenuBar();

    JMenu     rullegardinFil   = new JMenu();
    JMenuItem menupunktOpdat   = new JMenuItem();
    JMenuItem menupunktAfslut  = new JMenuItem();

    JMenu     rullegardinHjælp = new JMenu();

    rullegardinFil.setText("Fil");
    rullegardinFil.setMnemonic(KeyEvent.VK_F);
    menupunktOpdat.setText("Opdater");
    menupunktAfslut.setText("Afslut");
    menupunktAfslut.setMnemonic(KeyEvent.VK_A);

    rullegardinHjælp.setText("Hjælp");

    rullegardinFil.add(menupunktOpdat);
    rullegardinFil.add(menupunktAfslut);
    menubjælke.add(rullegardinFil);
    menubjælke.add(rullegardinHjælp);

    vindue.setJMenuBar(menubjælke);

    menupunktOpdat.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
        panel.buttonOpdater_actionPerformed(e);
      }
    });

    menupunktAfslut.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
        System.out.println("Farvel!");
        System.exit(0);
      }
    });

    vindue.setVisible(true); // som det allersidste: vis vinduet
  }
}

Man kan også sætte genvejstaster på menuer, med setMnemonic(). Disse aktiveres, som andre genvejstaster, med Alt-tasten, sådan at Alt-F åbner Fil-menuen.

For at fange når brugeren vælger et menupunkt, skal man lytte efter actionPerformed ligesom med JButton-klassen (det blev diskuteret i afsnit 11.1.1).

Mere info: http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html

11.7 Test dig selv

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

11.8 Resumé

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

11.9 Avanceret

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

11.9.1 HTML-kode i komponenter

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

11.9.2 Flertrådet komponentprogrammering

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

11.9.3 Brug af komponenter vs. paintComponent()

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.
javabog.dk  |  << forrige  |  indhold  |  næste >>  |  programeksempler  |  om bogen
http://javabog.dk/ - Forord af Jacob Nordfalk.
Licens og kopiering under Åben Dokumentlicens (ÅDL) hvor intet andet er nævnt (79% af værket).

Ønsker du at se de sidste 21% af dette værk (267325 tegn) skal du købe bogen. Så får du pæne figurer og layout, stikordsregister og en trykt bog med i købet.