Swing AWT GUI Anfänger Aufgabe

Diskutiere Swing AWT GUI Anfänger Aufgabe im AWT, Swing, JavaFX & SWT Bereich.
C

Codix

Hallo Zusammen

Aufgabenstellung:

Erstellen Sie eine Anwendung, in der Sie die Position des Fensters der Anwendung über vier Schaltflächen verändern können. Eine Schaltfläche soll das Fenster um 20 Pixel nach oben verschieben, eine um 20 Pixel nach unten und die beiden anderen um je 20 Pixel nach links beziehungsweise rechts.
Beachten Sie bei der Umsetzung bitte die folgenden Vorgaben:

Erstellen Sie für den Listener eine innere Klasse in der Klasse mit dem Fenster der Anwendung. Der Listener soll die Ereignisse aller vier Schaltflächen verarbeiten können.

Setzen Sie das Fenster der Anwendung fest auf die Größe 400 × 400 und positionieren Sie es zunächst an einer beliebigen Stelle auf dem Desktop.

Ordnen Sie die Schaltflächen in einem BorderLayout mit einem Abstand von 10 Pixeln an.

Stellen Sie sicher, dass das Fenster nicht aus dem Desktop herausgeschoben werden kann. Ermitteln Sie dazu die aktuelle Größe des Desktops und berechnen Sie dann die maximal möglichen Koordinaten für die Verschiebung nach rechts und nach unten. Für die Verschiebung nach links beziehungsweise oben können Sie den Wert 0 als Grenze verwenden.

Das Finden der aktuellen Größe des Desktops kann über "das Zentrieren eines Fensters auf dem Desktop" ermittelt werden.

Lösungsansatz:

äussere Klasse, die über die innere Klasse muss:


Java:
public class FensterPositionVerschiebungGUI extends JFrame{
//vier Schaltflächen als Instanzvariablen
private JButton schaltflaecheO, schaltflaecheU, schaltflaecheR, schaltflaecheL; //für die Verschiebung

Erstellen Sie eine Anwendung, in der Sie die Position des Fensters der Anwendung über vier Schaltflächen verändern können. Eine Schaltfläche soll das Fenster um 20 Pixel nach oben verschieben, eine um 20 Pixel nach unten und die beiden anderen um je 20 Pixel nach links beziehungsweise rechts.

Java:
//4 Schaltflächen erzeugen:
JButton schaltflaecheO = new JButton (Fenster nach oben);
JButton schaltflaecheU = new JButton (Fenster nach unten);
JButton schaltflaecheL = new JButton (Fenster nach links);
JButton schaltflaecheR = new JButton (Fenster nach rechts);
//adden von Schaltflächen
add(schaltflaecheO);
add(schaltflaecheU);
add(schaltflaecheL);
add(schaltflaecheR);
==
//Fenstergrösse der Anwendung setzen
fenster.setSize(400, 400);  //Breite 400 & Höhe 400
Frage hierzu: muss das in einen Konstruktor? Ich habe es nicht ganz begriffen, gibt es bei den grapfischen Oberflächen keine Main Class mehr sondern eine Konstruktor Class als Testklasse? Bitte um Erläuterungen, wer was Genaueres dazu weiss. Danke im Voraus.

===

Ordnen Sie die Schaltflächen in einem BorderLayout mit einem Abstand von 25 Pixeln an.

Java:
setLayout(new BorderLayout());
//beim BorderLayout: Argument des gewünschten Bereichs angeben
BorderLayout.NORTH
BorderLayout.SOUTH
BorderLayout.EAST
BorderLayout.WEST
BorderLayout.CENTER
==
// Abstand über setVgap(25)  setHgap(25)   //Abstand 25 pixel vertikal & horizontal
==
===

Innere Klasse für Listener verarbeitet Ereignisse aller 4 Schaltflächen.
das ist die innere Klasse die wir in die äussere einfügen müssen

Java:
class SchaltflaechenListenerInner implements ActionListener{
//Instanzvariablen für horizontale & vertikale Verschiebung
private int x, y;
/Methode actionPerformed wird beim Klicken auf Schaltflächen aufgerufen
        public void actionPerformed(ActionEvent e) {      
// Methode actionComman liefert Text, der auf Schaltfläche steht  
//wenn schaltflaecheL geklickt, dann
            if (e.getActionCommand().equals("Fenster nach links")){
// um 20 nach links verschieben
                setLocation(x-20, y);
            }                        
            if (e.getActionCommand().equals("Fenster nach rechts")){
                            setLocation(x+20, y);
            }
            if (e.getActionCommand().equals("Fenster nach oben")){
                setLocation(x, y-20);
            }    
            if (e.getActionCommand().equals("Fenster nach unten")){
                setLocation(x, y+20);
            }
        }
    }
===
Aufgabenstellung:
Stellen Sie sicher, dass das Fenster nicht aus dem Desktop herausgeschoben werden kann. Ermitteln Sie dazu die aktuelle Größe des Desktops und berechnen Sie dann die maximal möglichen Koordinaten für die Verschiebung nach rechts und nach unten. Für die Verschiebung nach links beziehungsweise oben können Sie den Wert 0 als Grenze verwenden.

=
Anhaltspunkte zum Lösen:
über die Methode Toolkit.getDefaultToolKit().getScreenSize() die aktuelle Bildschirmauflösung ermitteln. Die Methode liefert die Werte als einen Typ Dimension zurück. Dimension.width enthält dabei die Breite und Dimension.height die Höhe.
Von diesen Werten ziehen Sie jeweils die aktuelle Größe des Fensters ab und teilen das Ergebnis durch 2. Die Breite des Fensters erhalten Sie durch getSize().width und die Höhe durch getSize().height.
Ausprogrammiert könnte das Zentrieren eines Fensters auf dem Desktop so aussehen:
//die Bildschirmauflösung beschaffen und in einer
//Variablen vom Typ Dimension speichern
//bitte jeweils als eine Zeile eingeben

Dimension bGroesse= Toolkit.getDefaultToolkit(). getScreenSize();

//das Fenster positionieren

setLocation((bGroesse.width – getSize().width) / 2,
(bGroesse.height – getSize().height) / 2);
Ein wenig einfacher geht das Zentrieren mit der Anweisung
setLocationRelativeTo(null);
Die Methode setLocationRelativeTo() setzt eigentlich die Position eines Fensters relativ zu einer anderen Komponente. Durch das Argument null wird das Fenster aber zentriert auf dem Desktop dargestellt.

=========================================
Das bis jetzt waren alles Code-Entwürfe (ungegliedert).
=========================================


jetzt kommt der Code-Strukturvorschlag (in welcher Reihenfolge alles programmiert werden muss):
Fachfrage: Konstruktor (Instanzen anlegen) beim GUI, müssen wir immer eine zusätzliche Klasse haben beim GUI, ist es anders als auf der Grundlagenebene ( Klasse/n & eine Main-Klasse, das wars). Ist es beim GUi anders? Ist die Konstruktor Klasse als Main Klasse anzusehen? Weil wir dort Instanzen der Variablen aus der public class erzeugen und Werte zuweisen, die Methoden und Komponenten (Instanzvariabeln) also bearbeiten, ihnen Werte zuwesien, sie manipulieren, gestalten, etc.
Wo bleibt die Main Klasse = Test-Klasse?

Java:
// verschiedene importe
public class FensterPositionVerschiebungGUI extends JFrame{
//vier Schaltflächen als Instanzvariablen
private JButton schaltflaecheO, schaltflaecheU, schaltflaecheR, schaltflaecheL; //für die Verschiebung
// nach Instanzvariablen die innere Klasse
//das ist die innere Klasse die wir in die äussere einfügen müssen
class SchaltflaechenListenerInner implements ActionListener{
//Instanzvariablen für horizontale & vertikale Verschiebung
private int x, y;
/Methode actionPerformed wird beim Klicken auf Schaltflächen aufgerufen
        public void actionPerformed(ActionEvent e) {      
// Methode actionComman liefert Text, der auf Schaltfläche steht  
//wenn schaltflaecheL geklickt, dann
            if (e.getActionCommand().equals("Fenster nach links")){
// um 20 nach links verschieben
                setLocation(x-20, y);
            }                        
            if (e.getActionCommand().equals("Fenster nach rechts")){
                            setLocation(x+20, y);
            }
            if (e.getActionCommand().equals("Fenster nach oben")){
                setLocation(x, y-20);
            }    
            if (e.getActionCommand().equals("Fenster nach unten")){
                setLocation(x, y+20);
            }
        }
    }
// Ende der inneren Klasse

Java:
//der Konstruktor

//er erzeugt die Komponenten und setzt die

//Fenstereinstellungen

public FensterPositionVerschiebungGUI(String titel) {

//den Konstruktor der Basisklasse aufrufen und den

//Fenstertitel übergeben (wo sollen wir den Titel hernehmen?)

super(titel);



JButton schaltflaecheO = new JButton (Fenster nach oben);

JButton schaltflaecheU = new JButton (Fenster nach unten);

JButton schaltflaecheL = new JButton (Fenster nach links);

JButton schaltflaecheR = new JButton (Fenster nach rechts);



setLayout(new BorderLayout());

//beim BorderLayout: Argument des gewünschten Bereichs angeben

BorderLayout.NORTH

BorderLayout.SOUTH

BorderLayout.EAST

BorderLayout.WEST

BorderLayout.CENTER

fenster.setSize(300, 300);  //Breite 300 & Höhe 300    S.42

add(schaltflaecheO);

add(schaltflaecheU);

add(schaltflaecheL);

add(schaltflaecheR);

//den Listener verbinden

MeinKompakterListener listener = new MeinKompakterListener();

addActionlistener(listener);

schaltflaecheO.addActionListener(listener);

schaltflaecheU.addActionListener(listener);

schaltflaecheR.addActionListener(listener);

schaltflaecheL.addActionListener(listener);

//das Fenster packen

pack();

//die Standardaktion beim Schließen festlegen

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//das Fenster anzeigen setVisible(true);
bitte um eure Unterstützung bei der Lösung dieser komplexen Aufgabe. Danke im Voraus.
 
C

Codix

Fachfrage: Konstruktor (Instanzen anlegen) beim GUI, müssen wir immer eine zusätzliche Klasse haben beim GUI, ist es anders als auf der Grundlagenebene ( Klasse/n & eine Main-Klasse, das wars). Ist es beim GUi anders? Ist die Konstruktor Klasse als Main Klasse anzusehen? Weil wir dort Instanzen der Variablen aus der public class erzeugen und Werte zuweisen, die Methoden und Komponenten (Instanzvariabeln) also bearbeiten, ihnen Werte zuwesien, sie manipulieren, gestalten, etc.
Wo bleibt die Main Klasse = Test-Klasse?
so wie ich es jetzt nach dem Nachschlagen verstanden habe, wird die Main Klasse immer kurz gefasst und der Konstruktor ist als public class zusätzlich unter der ersten public class zu finden.

Im Konstruktor bearbeiten wir dann die "Bauplan" Klasse, also die erste public Class, in dieser Aufgabe die
public class FensterPositionVerschiebungGUI extends JFrame.

also muss der Lösungsansatz so sein:

Java:
class SchaltflaechenListenerInner implements ActionListener{
//Instanzvariablen für horizontale & vertikale Verschiebung
private int x, y;
/Methode actionPerformed wird beim Klicken auf Schaltflächen aufgerufen
        public void actionPerformed(ActionEvent e) {    
// Methode actionComman liefert Text, der auf Schaltfläche steht
//wenn schaltflaecheL geklickt, dann
            if (e.getActionCommand().equals("Fenster nach links")){
// um 20 nach links verschieben
                setLocation(x-20, y);
            }                      
            if (e.getActionCommand().equals("Fenster nach rechts")){
                            setLocation(x+20, y);
            }
            if (e.getActionCommand().equals("Fenster nach oben")){
                setLocation(x, y-20);
            }  
            if (e.getActionCommand().equals("Fenster nach unten")){
                setLocation(x, y+20);
            }
        }
    }
   
//     etc.

// und drunter die public "Konstruktor" class

/der Konstruktor

//er erzeugt die Komponenten und setzt die

//Fenstereinstellungen

public FensterPositionVerschiebungGUI(String titel) {

//den Konstruktor der Basisklasse aufrufen und den

//Fenstertitel übergeben (wo sollen wir den Titel hernehmen?)

super(titel);



JButton schaltflaecheO = new JButton (Fenster nach oben);

JButton schaltflaecheU = new JButton (Fenster nach unten);

JButton schaltflaecheL = new JButton (Fenster nach links);

JButton schaltflaecheR = new JButton (Fenster nach rechts);



setLayout(new BorderLayout());

//beim BorderLayout: Argument des gewünschten Bereichs angeben

BorderLayout.NORTH

BorderLayout.SOUTH

BorderLayout.EAST

BorderLayout.WEST

BorderLayout.CENTER

fenster.setSize(300, 300);  //Breite 300 & Höhe 300    S.42

add(schaltflaecheO);

add(schaltflaecheU);

add(schaltflaecheL);

add(schaltflaecheR);

//den Listener verbinden

MeinKompakterListener listener = new MeinKompakterListener();

addActionlistener(listener);

schaltflaecheO.addActionListener(listener);

schaltflaecheU.addActionListener(listener);

schaltflaecheR.addActionListener(listener);

schaltflaecheL.addActionListener(listener);

//das Fenster packen

pack();

//die Standardaktion beim Schließen festlegen

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//das Fenster anzeigen

setVisible(true);
und die Main class schreiben wir wie immer extra, kurzgefasst, z.B. so:

Java:
public class FensterPositionVerschiebungGUIProgramm {
    public static void main(String[] args) {
        new FensterPositionVerschiebungGUI("Irgendein kurzer Text");
    }
}
 
mihe7

mihe7

Frage hierzu: muss das in einen Konstruktor? Ich habe es nicht ganz begriffen, gibt es bei den grapfischen Oberflächen keine Main Class mehr sondern eine Konstruktor Class als Testklasse?
Grundsätzlich gibt es in Java keine "Main Class", sondern lediglich eine main-Methode (public static void main(String[] args)).

Beim Aufruf(!) von Java (Runtime, nicht Compiler) wird nun der Name einer Klasse verlangt, die eben eine solche main-Methode definiert. Diese Klasse wird dann gerne auch als "Main Class" bezeichnet. D. h. die "Main Class" wird nur dadurch zur "Main Class", dass sie einerseits eine main-Methode enthält und andererseits beim Programmstart angegeben wird.

Du kannst theoretisch in einem Programm auch in jeder Klasse eine main-Methode definieren. Ausgeführt wird beim Programmstart dann die main-Methode der Klasse, die Du angibst. Im Aufruf java mein.paket.Klasse1 würde also die Klasse mein.paket.Klasse1 als Main-Class fungieren und die Java Virtual Machine würde die Methode mein.paket.Klasse1.main als Programmeinstiegspunkt verwenden.

Das Schlüsslwort static deklariert ein Attribut bzw. eine Methode als etwas, das der Klasse, nicht aber dem einzelnen Objekt zugeschrieben wird. Somit kann z. B. main von der Java Virtual Machine ausgeführt werden, ohne erst ein Objekt der betreffenden Klasse erzeugen zu müssen.

Da der Start des Programms mit entsprechender Initialisierung einhergeht (z. B. Objekte erzeugen), was eine Aufgabe für sich darstellt, sollte die "Main Class" tatsächlich auch nichts anderes tun.

Was Konstruktoren betrifft: diese dienen einfach dazu, neu erzeugte Objekte zu initialisieren.

Ansonsten bist Du schon auf dem richtigen Weg, wie es aussieht, obgleich es Verbesserungspotenzial gibt. Ein paar Beispiele:
  1. Steht in der Aufgabenstellung etwas davon, dass Du von JFrame ableiten sollst?
  2. Du brauchst keine Instanzvariablen für die Schaltflächen.
  3. Du brauchst keine Instanzvariablen für x und y.
  4. Bezeichner "SchaltflaechenListenerInner" ist absolut nichtssagend.
  5. Bezeichner "schaltflaecheO"... Du schreibst ja auch nicht "ganzzahlX", warum dann "schaltflaecheO"? Das gilt natürlich analog für die Bezeichner der anderen Schaltflächen.
 
C

Codix

Erstmal danke für die Antwort. Sehr ausführlich.

zu 1. nein, in der Aufgabenstellung steht nichts von der Ableitung von Jframe.

Die Aufgabenstellung ist komplett oben im Text zu finden.

zu 2 & 3. Keine Instanzvariablen für Schaltflächen? Wie sollen wir dann Instanzen von Schaltflächen erzeugen?

Welche Instanzvariablen sollen wir denn erstellen?

zu 4. wie willst du den Bezeichner umbenennen?

zu 5. wie willst du denn die Schaltflächen untereinander unterscheiden, wenn du sie nicht verschieden benennst?

Bitte um konkrete Verbesserungsvorschläge, so dass ich von konkret (ganz unten) mich nach aussen hin (zum fertigen Code) durcharbeiten kann.

Danke im Voraus.
 
mihe7

mihe7

zu 5.: ich habe nicht gemeint, dass sie alle gleich heißen sollen, sondern dass der Präfix "schaltflaeche" unsinnig ist (das ist ja letztlich nur die Übersetzung des Typs), insbesonere im Vergleich zum Suffix "O", "U", "L" oder "R".

Man schreibt ja z. B. int anzahl; und nicht int ganzzahlA;, weil anzahl etwas aussagt, ganzzahlA dagegen nichtssagend ist. Da der Typ int bekannt ist, fragt sich jeder: was zur Hölle ist A?!?

zu 4.: naja, worum geht es denn? Um eine Verschiebungs-Aktion. Im Englischen würde ich das Teil z. B. MoveWindowAction o. ä. nennen. Im Deutschen ist das meistens etwas sperrig, evtl. FensterVerschiebung(sAktion).

zu 3.: Du kannst die aktuelle Position des Fensters ermitteln. Beim Klick auf die für eine Linksverschiebung des Fensters zuständige Schaltfläche sollte das Fenster doch auch nach links verschoben werden, wenn ich zuvor eine manuelle Verschiebung per Maus durchgeführt habe, oder?

zu 2.: lokale Variablen nutzen, so wie Du es z. B. in Deinem Konstruktor schon machst (Achtung das ist eine beliebte Fehlerquelle: lokale Variablen überdecken gleichnamige Instanzvariablen, d. h. die Instanzvariablen werden durch Deinem Konstruktor nicht geändert).

zu 1.: warum leitest Du dann von JFrame ab?
 
C

Codix

d.h.

5. du würdest die Schaltflächen so benennen:
private JButton O, U, R, L

4. d.h. du würdest es:

class MoveWindowAction implements ActionListener

nennen?

zu 3. wie willst du es denn verschieben? Wir brauchen doch Schaltflächen als Instanzvariablen, von den wir Instanzen erzeugen im Konstruktor


Du brauchst keine Instanzvariablen für die Schaltflächen.

&

zu 2.: lokale Variablen nutzen, so wie Du es z. B. in Deinem Konstruktor schon machst (Achtung das ist eine beliebte Fehlerquelle: lokale Variablen überdecken gleichnamige Instanzvariablen, d. h. die Instanzvariablen werden durch Deinem Konstruktor nicht geändert).
also wir sollen lokale Variablen nutzen? Und keine Instanzvariablen und Instanzmethoden?


1. Begründung: Die Klasse JFrame ist als Top-Level-Container für grafische Benutzeroberflächen von Applikationen gedacht, die eigenständig auf einem Rechner laufen sollen.
Diese Klasse muss man immer benutzen, sobald man mit GUIs arbeitet.
 
mihe7

mihe7

5. Nein. O, U etc. ist genauso nichtssagend. Nenn sie halt einfach oben, unten, links und rechts. Dann weiß man im Code schneller, worum es geht.

4. Ja, zum Beispiel. Da es eine innere Klasse ist, kann man auf "Window" im Namen ggf. auch verzichten.

3. Wie ich das Fenster verschieben würde?

a) Aktuelle Position des Fensters ermitteln (cx, cy)
b) Position des Fensters auf (cx+dx, cy+dy) setzen, wobei (dx, dy) der Verschiebungsvektor ist.

2. Der Gültigkeitsbereich von Variablen sollte immer so klein wie möglich sein. Wenn eine lokale Variable reicht, brauchst Du keine Instanzvariable. Instanzmethoden sollst Du natürlich schon verwenden.

1. Das ist kein Grund.

Diese Klasse muss man immer benutzen, sobald man mit GUIs arbeitet.
"Benutzen" ja, "Erweitern" nein.

Hier mal ein Beispiel:
Java:
import java.awt.Point;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class Test {
    public static final int STEP = 10;

    private JFrame frame;

    public void run() {
        MoveAction moveAction = new MoveAction();
        JButton left = new JButton("<-");
        left.addActionListener(moveAction);

        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(left, BorderLayout.WEST);
        frame.setSize(400, 400);
        frame.setResizable(false);
        frame.setVisible(true);
    }

    private class MoveAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            String command = e.getActionCommand();
            if (command == null) {
                return;
            }

            switch (command) {
                 case "<-": move(-STEP, 0); break;
                 default: // unbekannte Befehle ignorieren.
                     break;
            }
        }

        private void move(int dx, int dy) {
            Point pos = frame.getLocationOnScreen(); 
            pos.x += dx;
            pos.y += dy;
            frame.setLocation(pos);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
Den Rest bekommst Du sicher selbst hin :)
 
C

Codix

5. Nein. O, U etc. ist genauso nichtssagend. Nenn sie halt einfach oben, unten, links und rechts. Dann weiß man im Code schneller, worum es geht.

4. Ja, zum Beispiel. Da es eine innere Klasse ist, kann man auf "Window" im Namen ggf. auch verzichten.

3. Wie ich das Fenster verschieben würde?

a) Aktuelle Position des Fensters ermitteln (cx, cy)
b) Position des Fensters auf (cx+dx, cy+dy) setzen, wobei (dx, dy) der Verschiebungsvektor ist.

2. Der Gültigkeitsbereich von Variablen sollte immer so klein wie möglich sein. Wenn eine lokale Variable reicht, brauchst Du keine Instanzvariable. Instanzmethoden sollst Du natürlich schon verwenden.

1. Das ist kein Grund.



"Benutzen" ja, "Erweitern" nein.

Hier mal ein Beispiel:
Java:
import java.awt.Point;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class Test {
    public static final int STEP = 10;

    private JFrame frame;

    public void run() {
        MoveAction moveAction = new MoveAction();
        JButton left = new JButton("<-");
        left.addActionListener(moveAction);

        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(left, BorderLayout.WEST);
        frame.setSize(400, 400);
        frame.setResizable(false);
        frame.setVisible(true);
    }

    private class MoveAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            String command = e.getActionCommand();
            if (command == null) {
                return;
            }

            switch (command) {
                 case "<-": move(-STEP, 0); break;
                 default: // unbekannte Befehle ignorieren.
                     break;
            }
        }

        private void move(int dx, int dy) {
            Point pos = frame.getLocationOnScreen();
            pos.x += dx;
            pos.y += dy;
            frame.setLocation(pos);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
Den Rest bekommst Du sicher selbst hin :)
welchen Rest?
 
Thema: 

Swing AWT GUI Anfänger Aufgabe

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben