Grafische Benutzeroberfläche Fenster Vorbemerkung Für die hier verwendeten Programme wurden aus didaktischen Gründen folgende Vereinbarungen getroffen; 1)Alle Klassen, in denen sich die Methode main befindet, beginnen mit Main... Bem: Die Programmdatei muss also den gleichen Namen haben und public sein. 2) Alle von uns frei wählbaren Bezeichnungen für Klassen, Variablen, Methoden usw. beginnen mit dem Bezeichner my... Ausnahme: Einfache Variablen wie z.B. i,j, usw. import java.awt.*; import javax.swing.*; public class MainFenster1 { public static void main(String[] args) { JFrame myF = new JFrame(); myF.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); myF.setLocation(200,200); myF.setSize(400,200); myF.setVisible(true); } } Hier wird ein Objekt, also myF der Klasse JFrame, also ein Fenster erzeugt und später auf den Bildschirm gebracht. Deshalb muss "dankenswerterweise" der Bauplan nicht von uns gebastelt werden. import java.awt.*; import javax.swing.*; public class MainFenster1 { public static void main(String[] args) { JFrame myF = new JFrame(); myF.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); myF.setLocation(200,200); myF.setSize(400,200); Programm wird beendet (aus myF.setVisible(true); dem Arbeitsspeicher entfernt), } wenn Fenster weggeklickt wird. } Nachprüfen mit Task-Manager Linke obere Ecke des Fensters bringt das Fenster auf den Bildschirm Grösse des Fensters festlegen, das auf den Bildschirm kommt import java.awt.*; import javax.swing.*; public class MainFenster1 { public static void main(String[] args) { JFrame myF = new JFrame(); myF.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); myF.setLocation(200,200); myF.setSize(400,200); myF.setVisible(true); } } Aus Gründen der OOP soll zukünftig dieses Fenster in einer eigenen, selbst gebastelten Klasse entworfen werden. Welche Eigenschaft der OOP muss dabei verwendet werden? Die Vererbung! Deswegen ... import java.awt.*; import javax.swing.*; public class MainFenster1 { public static void main(String[] args) { MyFenster myF = new MyFenster(); myF.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); } } Hier wird ein Objekt, also myF, der selbstgebastelten Klasse MyFenster erzeugt, d.h. auf den Bildschirm gebracht Programm wird beendet (aus dem Arbeitsspeicher entfernt), wenn Fenster weggeklickt wird. Nachprüfen mit Task-Manager class MyFenster extends JFrame{ Buttons deklarieren private JButton myB1, myB2; private JTextField myT1, myT2; Textfelder private JLabel myL1, myL2; deklarieren private Container myCont; private GridLayout myGL_2_3; Labels deklarieren public MyFenster(){ Liefert die Stelle, an der die sichtbaren Komponenten (Buttons, usw.) an das Fenster montiert werden. Layout deklarieren, es besteht aus 2 Zeilen und 3 Spalten Ein Layout ist eine Vorgabe, wie die sichtbaren Komponenten innerhalb beim Einfügen (mit add) in das Fenster oder in ein Panel (siehe später) angeordnet werden class MyFenster extends JFrame{ private JButton myB1, myB2; private JTextField myT1, myT2; private JLabel myL1, myL2; private Container myCont; private GridLayout myGL_2_3; public MyFenster(){ 1) Beim GridLayout werden die Elemente zeilenweise eingefügt, d.h. zuerst wird die 1. Zeile aufgefüllt, dann die 2. Zeile, usw. Mit myGL_2_3 = new GridLayout(2,3); wird ein Layout von 2 Zeilen und 3 Spalten angelegt. 2) Es müssen _ALLE_ Zeilen bis zur letzten Spalte befüllt werden myB1=new JButton("Go"); myB2=new JButton("Ok"); Buttons anlegen Textfelder anlegen myT1=new JTextField("hier eingeben",30); myT2=new JTextField("hier eingeben",30); Labels anlegen myL1=new JLabel("Euro-->Dollar"); myL2=new JLabel("Dollar-->Euro"); Stelle des Anmontierens myCont=getContentPane(); bestimmen myGL_2_3=new GridLayout(2,3); myCont.setLayout(myGL_2_3); GridLayout mit 2 Zeilen und 3 Spalten anlegen. Die Stelle, an der die Elemente angefügt werden, muss mit einem Layout versehen werden. myB1=new JButton("Go"); myB2=new JButton("Ok"); myT1=new JTextField("hier eingeben",30); myT2=new JTextField("hier eingeben",30); myL1=new JLabel("Euro-->Dollar"); myL2=new JLabel("Dollar-->Euro"); myCont=getContentPane(); myGL_2_3=new GridLayout(2,3); myCont.setLayout(myGL_2_3); Die sichtbaren Komponenten müssen an unser Fenster “MyFenster“ an eine dafür vorgesehene, ganz bestimmte Stelle, montiert werden. Die Methode getContentPane() liefert die Stelle, an die das Panel an den Top-Level-Container JFrame montiert werden muß. myCont.add(myL1); myCont.add(myT1); myCont.add(myB1); myCont.add(myL2); myCont.add(myT2); myCont.add(myB2); Lables, Textfelder und Buttons werden an das Fenster montiert unter der Regie des GridLayouts, das aus 2 Zeilen und 3 Spalten besteht. Fensterüberschrift setTitle("Meine Zeichnung"); setLocation(30,60); setSize(600,400); setVisible(true); } } Linke obere Ecke des Fensters Grösse des Fensters festlegen bringt das Fenster auf den Bildschirm Man kann nicht nur direkt am Fenster sichtbare Komponenten (Buttons, ...) anbringen, sondern Behälter (Container), in die man (wieder Untercontainer) oder sichtbare Komponenten anbringt. Diese Behälter haben die ähnliche Bedeutung wie die Ordner im Explorer. Diese Behälter werden realisiert durch Objekte vom Typ JPanel. Sie werden hier auch oft Zeichenflächen genannt. Im Folgenden sollen hier 2 Zeichenflächen an das Fenster montiert werden, wobei in diese Zeichenflächen vorher sichtbare Komponenten eingefügt wurden. Wichtig: Auch diese Zeichenflächen müssen (genauso wie die Stelle, an der wiederum diese angebracht werden) ein Layout bekommen (müssen "formatiert" werden). In diesen 2 Zeichenflächen sollen jeweils 1 Button, 1 Label und 1 Textfeld angebracht werden. Damit diese sichtbaren Komponenten nicht zu groß werden, sollen zusätzlich noch weitere "DummyLabels" angebracht werden. Konkret: (siehe nächste Folie) Konkret: 1. Zeichenfläche: Button | Label | Textfeld | Dummy Dummy | Dummy | Dummy | Dummy 2. Zeichenfläche: Dummy | Dummy | Dummy | Dummy Button | Label | Textfeld | Dummy import java.awt.*; import javax.swing.*; public class MainFenster1 { public static void main(String[] args) { MyFenster myF = new MyFenster(); myF.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); } } Das gleiche wie vorher... Was neu hinzukommt wird rot gekennzeichnet. class MyFenster extends JFrame{ Zeichenflächen deklarieren private JButton myB1, myB2; private JTextField myT1, myT2; private JLabel myL1, myL2; // Zeichenflächen private JPanel myPan1; private JPanel myPan2; private Container myCont; private GridLayout myGL_2_1; private GridLayout myGL1_2_4; private GridLayout myGL2_2_4; public MyFenster(){ Für jede Zeichenfläche ein eigenes Layout (auch wenn alle Layouts die gleiche Zeilen- und Spaltenzahl haben). myB1=new JButton("Go"); Zeichenflächen anlegen myB2=new JButton("Ok"); myT1=new JTextField("hier eingeben",30); myT2=new JTextField("hier eingeben",30); myL1=new JLabel("Euro-->Dollar"); myL2=new JLabel("Dollar-->Euro"); myPan1=new JPanel(); GridLayouts anlegen myPan2=new JPanel(); myCont=getContentPane(); myGL_2_1=new GridLayout(2,1); myGL1_2_4=new GridLayout(2,4); myGL2_2_4=new GridLayout(2,4); myCont.setLayout(myGL_2_1); myPan1.setLayout(myGL1_2_4); myPan2.setLayout(myGL2_2_4); GridLayouts an die entsprechenden Stellen anbringen myPan1.add(myL1); Anbringen des Labels, myPan1.add(myT1); Textfelds und Buttons an myPan1.add(myB1); die 1. Zeichenfläche. myPan1.add(new JLabel()); myPan1.add(new JLabel()); myPan1.add(new JLabel()); Anbringen der myPan1.add(new JLabel()); DummyLabels myPan1.add(new JLabel()); Beachte: Durch jedes new JLabel() wird ein neues Objekt angelegt. Man hat nachher also 5 verschiedene JLabels Label Textfeld Button DummyLabel DummyLabel DummyLabel DummyLabel DummyLabel myPan2.add(new JLabel()); myPan2.add(new JLabel()); myPan2.add(new JLabel()); myPan2.add(new JLabel()); myPan2.add(myL2); myPan2.add(myT2); myPan2.add(myB2); myPan2.add(new JLabel()); Anbringen der DummyLabels Anbringen des Labels, Textfelds und Buttons an die 2. Zeichenfläche. Beachte: Durch jedes new JLabel() wird ein neues Objekt angelegt. Man hat nachher also 5 verschiedene JLabels DummyLabel DummyLabel DummyLabel DummyLabel Label Textfeld Button DummyLabel myCont.add(myPan1); myCont.add(myPan2); Anbringen der zwei Zeichenflächen an das Fenster setTitle("Meine Zeichnung"); setLocation(30,60); setSize(600,400); setVisible(true); } } Zeichnen mit Java Um in Java zu zeichnen, müssen alle Linien, Kreise, usw. in eine Zeichenfläche (JPanel) gezeichnet werden. Aus Demogründen soll hier neben der Zeichenfläche noch eine weitere Zeichenfläche erstellt werden, in die nur sichtbare Elemente (1 Label, 1 Textfeld, 1 Button) montiert werden sollen. Gezeichnet wird durch den Aufruf der Methode (hier müssen dann z.B. die Befehle zum Zeichnen von Ellipsen, Linien, Rechtecken, usw. stehen) paintComponent(Graphics g) Diese soll niemals direkt innerhalb des selbst geschriebenen Programms aufgerufen werden ! Java (bzw. das Betriebssystem) entscheidet selbst, wenn es paintComponent(Graphics g) aufruft. Dies geschieht: --> bei der ersten Anzeige des Fensters (setVisible(true)) --> nachdem ein Fenster vergrößert (verkleinert) wurde, --> nach dem Wegziehen überlagernder Fenster (verdeckte Elemente werden aufgedeckt) --> nach dem Aufruf des Befehls repaint() im Programm Bemerkung: 1) Den Parameter Graphics g in paintComponent(Graphics g) kann man sich als den Teil des Bildspeicherbereichs vorstellen, der die zugehörige grafische Komponente (z.B. Ellipse) auf dem Bildschirm repräsentiert. 2) Die erste Anweisung in paintComponent(Graphics g) sollte super.paintComponent(g) sein, da super.paintComponent(g) die Methode paintComponent(g) der Vaterklasse aufruft. Die Standard-Implementation dieser Methode der Klasse JPanel löscht den kompletten Inhalt des Panels. Ansonsten wird auch noch der alte Inhalt des Panels auf dem Bildschirm ausgegeben. Wie kann der Programmierer eine Zeichenfläche (Panel) erzeugen und in diese Ellipsen, Linien, Rechtecke, usw. anbringen? Zusätzlich soll er außerdem noch die ganzen Möglichkeiten von JPanel (z.B. wird durch paintComponent automatisch die Zeichnung auf den Bildschirm gebracht) verwenden können! Indem man eine Klasse bastelt, die von JPanel erbt ! import java.awt.*; import javax.swing.*; public class MainZeichnen1 { public static void main(String[] args) { MyFenster myf = new MyFenster(); myf.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); } } Das gleiche wie vorher... class MyFenster extends JFrame{ private JButton myB1; private JTextField myT1; private JLabel myL1; private JPanel myPan1; private MyZeichenflaeche myZf1; private Container myCont; private BorderLayout myBoLa; private GridLayout myGL_1_2; public MyFenster(){ Ein JPanel deklarieren Eine selbstgebastelte Zeichenflaeche deklarieren Nur für myPan1 braucht man ein Layout: Da an myZf1 keine sichtbaren Komponenten (wie Buttons, usw.) angebracht werden. class MyFenster extends JFrame{ private JButton myB1; private JTextField myT1; private JLabel myL1; private JPanel myPan1; private MyZeichenflaeche myZf1; private Container myCont; private BorderLayout myBoLa; private GridLayout myGL_1_2; Ein JPanel deklarieren Eine selbstgebastelte Zeichenflaeche deklarieren public MyFenster(){ Das BorderLayout unterteilt in 5 Bereiche: North, South, East, West, Center. Einem Bereich kann dabei immer nur eine Komponente (z.B. ein Button) zugeordnet werden. Will man einem Bereich mehrere Komponenten zuordnen, muß dieser Bereich auch mit einem LayoutManager bestückt werden (siehe nächste Folien). Wird ein Bereich nicht gefüllt, wird diese Fläche von den anderen Bereichen genutzt. Ein Border-Layout, siehe wie folgt aus (wenn alle Bereiche gefüllt sind)... CENTER SOUTH EAST WEST NORTH Wichtige Bemerkung: Wenn kein Layout-Manager benutzt wird, gilt standardmäßig folgende Zuweisung (Vorbelegung): JFrame-Objekt --> BorderLayout JPanel-Objekt --> FlowLayout myB1 = new JButton("Go"); Zeichenflächen anlegen myT1 = new JTextField("hier eingeben",30); myL1 = new JLabel("Rechts Text eingeben"); myPan1 = new JPanel(); myZf1 = new MyZeichenflaeche(); myCont = getContentPane(); myBoLa = new BorderLayout(); myGL_1_2 = new GridLayout(1,2); myCont.setLayout(myBoLa); myPan1.setLayout(myGL_1_2); Selbstgebasteltes Objekt der KLasse MyZeichenflaeche anlegen. myPan1.add(myL1); myPan1.add(myT1); myPan1.add(myB1); Anbringen des Labels, Textfelds und Buttons an die 1. Zeichenfläche. myCont.add(myZf1,BorderLayout.CENTER); myCont.add(myPan1,BorderLayout.SOUTH); setTitle("Meine Zeichnung"); setLocation(30,60); setSize(600,800); setVisible(true); } } Anbringen der zwei Zeichenflächen an das Fenster class MyZeichenflaeche extends JPanel{ public void paintComponent(Graphics myG){ Color myFarbe = new Color(100, 250, 200); myG.setColor(myFarbe); Diese myG.drawOval(100, 50, 250, 300); Farbe myG.fillOval(100, 50, 250, 300); setzen myG.setColor(Color.red); myG.drawString("Das bin ich",200,20); myG.drawLine(150,160,180,160); myG.drawLine(270,160,300,160); myG.drawLine(230,200,230,230); myG.drawRect(200,280,50,30); } } Eigene Farbe basteln: 150, 180, 234 sind die Rot-, Grün- und Blauteile einer Farbe jeweils im Bereich zwischen 0 und 255 class MyZeichenflaeche extends JPanel{ public void paintComponent(Graphics myG){ Color myFarbe = new Color(100, 250, 200); myG.setColor(myFarbe); myG.drawOval(100, 50, 250, 300); myG.fillOval(100, 50, 250, 300); myG.setColor(Color.red); myG.drawString("Das bin ich",200,20); myG.drawLine(150,160,180,160); myG.drawLine(270,160,300,160); myG.drawLine(230,200,230,230); Zeichnet die Randlinie einer Ellipse, die sich in einem myG.drawRect(200,280,50,30); gedachten Rechteck befindet. Der linke obere Punkt hat } die Koordinaten } Koordinate x = 100, Koordinate y = 50. Die Breite des Rechtecks in x-Richtung = 250 Die Breite des Rechtecks in y-Richtung = 300 class MyZeichenflaeche extends JPanel{ public void paintComponent(Graphics myG){ Color myFarbe = new Color(100, 250, 200); myG.setColor(myFarbe); myG.drawOval(100, 50, 250, 300); myG.fillOval(100, 50, 250, 300); myG.setColor(Color.red); myG.drawString("Das bin ich",200,20); myG.drawLine(150,160,180,160); myG.drawLine(270,160,300,160); myG.drawLine(230,200,230,230); myG.drawRect(200,280,50,30); } } Füllt die Ellipse mit der vorher gesetzten Farbe Die Farbe rot auswählen (setzen) Text ausgeben class MyZeichenflaeche extends JPanel{ public void paintComponent(Graphics myG){ Color myFarbe = new Color(100, 250, 200); myG.setColor(myFarbe); myG.drawOval(100, 50, 250, 300); myG.fillOval(100, 50, 250, 300); myG.setColor(Color.red); myG.drawString("Das bin ich",200,20); myG.drawLine(150,160,180,160); myG.drawLine(270,160,300,160); myG.drawLine(230,200,230,230); myG.drawRect(200,280,50,30); } } Linie zeichnen Rechteck zeichnen Hier nochmals das Border-Layout kurz beschrieben: Das Border-Layout besteht aus 5 Zonen, in denen jeweils eine Komponente eingefügt werden kann. Sollen z.B. mehrere Buttons in eine Zone eingefügt werden, fügt man diese zuerst in ein Panel ein und danach dieses Panel in die Zone! Nimmt man weniger als fünf Komponenten auf, so werden die nicht benutzten Zonen von den benutzten Zonen belegt. CENTER SOUTH EAST WEST NORTH NORTH und SOUTH nehmen die volle Breite ein. Die Höhe hängt von der einzufügenden Komponente ab. WEST und EAST nehmen die Breite der einzufügenden Komponente an und belegen in der Höhe den restlichen freien Raum. Den Rest bekommt CENTER. CENTER SOUTH EAST WEST NORTH