Probleme mit der GUI

Hallo Leute,

ich brauche ein wenig Hilfe. Bin unerfahren in Java und gerade dabei eine GUI zu entwickeln. Konnte mir mitHilfe von diversen youtube-Videos schon einiges aneignen aber bei einem Punkt komme ich gerade nicht weiter.

Ich habe ein Frame mit einem Button. Klickt man auf den Button, öffnet sich ein anderer Frame[newFrame] (War mir hier nicht sicher, ob es an der Stelle egal ist, ob ich ein JDialog oder JFrame nehme? Habe als Unterschied nur gesehen, dass man den JDialog modal setzen kann aber das spielt bei mir keine Rolle - gibt es noch einen anderen Vorteil von einem JDialog?)

Mein Zwischenziel ist, dass wenn ich das neue Frame[newFrame] schließe (per klick auf das x), das alte Frame wieder erscheint und das neue Frame geschlossen wird.

Ich habe also eine Unteklasse erstellt, die das Verhalten des Listeners vom Button beschreibt. Hier habe ich ein neuen Frame erstellt und diesem Frame noch das addWindowListener zugefügt, damit ich die gewünschte Funktionalität einfügen kann. Also wieder eine Unterklasse, die den WindowListener beschreibt. Hier habe ich jetzt die Methode windowClosing(WindowEvent e) benutzt und mit setVisible(true) erreicht, dass mein Ursprungsframe wieder erscheint. Jetzt habe ich versucht mit newFrame.setVisible(false) zu arbeiten, was aber anscheinend nicht geht. Wie kann ich das machen?

Hier noch mein Code zum Verständnis…


import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JFrame;

public class UnserFrame extends JFrame {
    
    JLabel text;
    JButton button;
    
    
    
    public UnserFrame(){
                
        setSize(500,350);
        setTitle("Bedienung - LEDs");
        setLocationRelativeTo(null);                        //Fenster wird mittig geöffnet
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(null);
        
        text = new JLabel("Die Wunder der Beleuchtung");
        text.setBounds(50, 15, 500, 30);
        Font schrift = (text.getFont().deriveFont(Font.BOLD + Font.ITALIC, 25));        //Schriftart (hier Standardschriftart , Type, Größe
        text.setFont(schrift);
        add(text);
        
        button = new JButton("Klick mich");
        button.setBounds(50, 50, 100, 25);
        button.addActionListener(new UnserListener());
        add(button);
        
        
        
        
    }
    
    private class UnserListener implements ActionListener {
    
        public void actionPerformed(ActionEvent e) {
            
            JFrame newFrame = new JFrame();
            newFrame.setVisible(true);
            newFrame.setLocation(500,500);
            newFrame.setSize(500,350);
            newFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
            newFrame.addWindowListener(new WindowHandler());
            setVisible(false);
            
            
            
            /*JDialog newDialog = new JDialog();
            newDialog.setVisible(true);
            newDialog.setLocation(500,500);
            newDialog.setSize(500,350);
            newDialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
            
            setVisible(false);*/
            
            
        }

    
    private class WindowHandler implements WindowListener{

        @Override
        public void windowActivated(WindowEvent e) {
            
            
        }

        @Override
        public void windowClosed(WindowEvent e) {
            // TODO Auto-generated method stub
            
        }

        @Override
        public void windowClosing(WindowEvent e) {
            setVisible(true);
            
                    
        }

        @Override
        public void windowDeactivated(WindowEvent e) {
            // TODO Auto-generated method stub
            
        }

        @Override
        public void windowDeiconified(WindowEvent e) {
            // TODO Auto-generated method stub
            
        }

        @Override
        public void windowIconified(WindowEvent e) {
            // TODO Auto-generated method stub
            
        }

        @Override
        public void windowOpened(WindowEvent e) {
            // TODO Auto-generated method stub
            
        }
    }

}}

newFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

Damit verhinderst du, dass dein neuer Frame geschlossen wird.
In dem Fall musst du das schließen dann schon selbst übernehmen (setVisible(false) und dispose() auf dem Frame aufrufen)

So z.B.:

package net.bytewelt.forum.help.unregistriert.gui.zweiframes;

import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;

@SuppressWarnings("javadoc")
public class ZweiFrames {
	private JFrame	majorFrame;
	private JFrame	minorFrame;

	public ZweiFrames() {
		getMajorFrame().setVisible(true);
	}

	private static void chanceVisibility(JFrame... frames) {
		for (JFrame f : frames) {
			f.setVisible(!f.isVisible());
		}
	}

	public static void main(String[] args) {
		new ZweiFrames();
	}

	private JFrame getMajorFrame() {
		if (majorFrame == null) {
			majorFrame = new JFrame();
			majorFrame.setTitle("Bedienung - LEDs");
			majorFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			majorFrame.setLayout(null);

			JLabel text = new JLabel("Die Wunder der Beleuchtung");
			text.setFont(text.getFont().deriveFont(Font.BOLD | Font.ITALIC, 25));
			text.setBounds(50, 15, 500, 30);
			majorFrame.add(text);

			JButton button = new JButton("Klick mich");
			button.setBounds(50, 50, 100, 25);
			button.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					chanceVisibility(getMajorFrame(), getMinorFrame());
				}
			});
			majorFrame.add(button);

			majorFrame.setSize(500, 350);
			majorFrame.setLocationRelativeTo(null);
		}

		return majorFrame;
	}

	private JFrame getMinorFrame() {
		if (minorFrame == null) {
			minorFrame = new JFrame();
			minorFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);

			minorFrame.addWindowListener(new WindowAdapter() {
				@Override
				public void windowClosing(WindowEvent e) {
					chanceVisibility(getMajorFrame(), getMinorFrame());
				}
			});

			minorFrame.setSize(500, 350);
			minorFrame.setLocation(500, 500);
		}

		return minorFrame;
	}
}

Ist vielleicht nicht das Optimum, habs grad nur mal schnell hingeklatscht. Aber kannst dich ja dran orientieren.

Übrigens die Frames erst sichtbar machen, wenn sie bereits vollständig initialisiert sind und nicht schon vorher, sonst können Darstellungsfehler und sonstige Probleme und unerwünschte Effekte auftreten.

Pauschal gesagt hätte ich hier jetzt aber nen Dialog genommen, denn in der Regel hat man nur ein Hauptfenster (Frame) und der Rest sind quasi helferlein und daher meist Dialoge, unter anderem eben auch wegen der Sperrung durch das modal-Flag. Aber man kann auch Frames nehmen, das ist nicht so wild. Aber wie gesagt, meist gibt es nur ein Haupt-Anwendungsfenster (Frame) und die Helfer-Fenster werden eben als Dialoge erzeugt. Da muss man sich auch gar nicht groß festfahren. Sinnig ist es nämlich keinesfalls immer wieder die Frames oder Dialoge zu erzeugen, also explizit “festgesetzt”, sondern man erstellt sich die Klassen basierend auf Panels und baut dort die Masken zusammen und fügt diese einfach in ein Frame oder ein Dialog ein. Ob nun Frame oder Dialog, ist von daher eher uninteressant, das kann man zur Not auch jederzeit austauschen. Entscheidend sind nur die Masken und somit die Panels.

Dein Code mit gewünschter Funktion:

private class UnserListener implements ActionListener {
   **private JFrame newFrame;**
   
   public void actionPerformed(ActionEvent e) {
   ...

    public void windowClosing(WindowEvent e) {
        newFrame.setVisible(false);
        setVisible(true);
    }
    ....

Du konntest in windowClosing nicht auf newFrame zugreifen, da newFrame nur in actionPerformed sichtbar war.
Wie von Akeshihiro schon gesagt wurde:
-setVisible immer ganz zum Schluss aufrufen, wenn alle anderen Komponenten schon gezeichnet/gesetzt wurden, um Darstellungsfehler auszuschließen

  • Normalerweise arbeitet man nur mit einem JFrame. Alle weiteren Fenster werden in der Regel über andere Komponenten (JDialog, JInternalFrame etc) realisiert.

Mal ein ganz anderer Ansatz: Da beide Frames nie gleichzeitig zu sehen sind, sollte man überlegen, ob nicht ein Frame ausreichend ist und man nur den Inhalt „auswechselt“. Stichwort [JAPI]CardLayout[/JAPI]
Guck auch mal ins Byte-Welt-Wiki. Error | OPNsense

Wie @butterbemme geschrieben hat, sollte man nur einen JFrame erzeugen. Zwei Frames führen z.B. zu zwei Einträgen in der Windows-Startleiste. Die Alternative ist hier der JInternalFrame (http://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html).

Das von @_Michael erwähnte Cardlayout ist sonst sicher eine Alternative, wenn nicht mehrere Fenster gleichzeitig angezeigt werden können müssen. Dialoge sind eher für überschaubare Sachverhalte geeignet oder z.B. um den Anwender eine sequentielle Abarbeitung in einem Wizzard zu ermöglichen.

Sollte die Möglichkeit bestehen, dass deine Anwendung irgendwann mal als Thin Client im Web oder auf einem Tablet dargestellt werden soll, solltest du möglichst von der Darstellung mehrerer Fenster absehen um dir später die Portierung zu erleichtern.

Aber auch nur wenn beide gleichzeitig sichtbar sind

edit: btw ist das das falsche Unterforum → verschieb0rn!

Danke für die vielen schnellen Antworten!

Hab eben einfach mal den zweiten JFrame zu JInternalFrame umgewandelt. Nun sagt er mir aber, dass addWindowListener nicht definiert ist für InternalFrames. Also nochmal zur Erklärung: Am Ende soll die GUI so aussehen, dass ich vom Mainframe mit ca 5 Buttons auf neue Frames/Dialoge/InternalFrames komme. Auf einigen dieser Frames/Dialoge/InternalFrames soll es dann wieder Auswahlmöglichkeiten mithilfe von Buttons geben. Das Programm soll eine Steuerung für eine LED-Beleuchtung sein. Die Wahl, welche LED um welchen Wert heller werden soll, wollte ich durch Speichern von Zahlen bezüglich der geklickten Buttons erreichen. Drückt der User auf Button LED1 wird 001 gespeichert, Button LED2 mit 010, … In dem Fenster das Button LED erzeugt geht das Spiel von vorne los. Wird der innere Button “heller” gedrückt, wird insgesamt 001 001 gespeichert, wird “dunkler” gedrückt 001 010.

Kann ich hier einfach bei den Listenern noch ein kleines unauffälliges “int y=001” einfügen?

Wie kann ich zwei Zahlen aneinanderhängen? Also ich habe von LED1 y=001 und von heller x=001 und will insgesamt mein z haben als 001 001. Muss ich die in Strings umwandeln, dann mit “+” verbinden und dann zurück? Denke da gibt es auch was für Integers oder?

Vielen Dank!

Hört sich wirklich so an, als könntest du das auch mit einem CardLayout hinkriegen, also dass du dann durch Klicken auf einen Button in ein anderes Panel mit wieder einem Button schaltest. Dann musst du dir nur noch eine Klasse (Model) schreiben, welche die Daten speichert.

Ganz hab ich nich gerallt was du machen willst:
Sollen deine Frames/Dialoge/InternalFrames die verschiedenen LED “darstellen”?

Bezüglich InternalFrames und Listener: Schau mal in den API Eintrag zu JInternalFrame und du wirst sehen welchen Listener du brauchst.

Wirklich verstanden habe ich es nicht, hört sich für mich aber danach an, dass der Ansatz mit CardLayout besser geeignet wäre wie mehrere Frames oder Dialoge. Evlt. auch einfach nur ein JTabbedPane? JInternalFrames würde ich einsetzen wenn die unterschiedlichen Daten in meheren InternalFrames angezeigt werden soll.
Geht es bei 001 und 001 zu 001 001 um irgendwelche Binärwerte? “001” ist ja eigentlich kein int.
Soll das in die Richtung gehen?

int y = 1;
int z = x | y;
System.out.println(Integer.toBinaryString(z));```

Sorry für die Verwirrung. Das ganze ist ein Teil für meine Bachelorarbeit. Ich soll mit VHDL ein FPGA programmieren, welches eine Steuerungseinheit für ~8 LEDs ist. Mit Java soll ich eine prototypische Software zur Bedienung einer Dimmereinheit dafür entwickeln. Der Plan war nun mithilfe der GUI herauszufinden, welche LED der Benutzer ansteuern möchte und um wie viel sie heller gemacht werden soll. Dafür wollte ich als Ausgabe des ganzen Java-codes ein Binärwert, den ich auf das FPGA bringen kann. Das soll wohl mit der Java Communication API funktionieren, aber dazu will ich später erst kommen.

Also ich muss erreichen, dass durch das Klicken der Buttons Werte gespeichert werden (Binärwerte [ja klar, int macht ja keinen Sinn, danke Michael, so wie dus gemacht hast klingt gut, bis auf dass ich das nicht printn will]).

Werde mich dann mal in “CardLayout” einlesen.

Danke für die Hilfe!

Heißt: Du hast eine Übersicht, auf der alle LEDs gelistet/angezeigt werden. Wird eine davon angewählt wird auf eine Art Detailsicht gewechselt (und die soll/darf nicht im Frame angezeigt werden?) In der Detailansicht wird dann zuvor ausgewählte LED gedimmt. Wenn Du da den Übersichtsframe angezeigt lassen willst und die Einstellung in einem (evtl. modalen) Dialog durchführen willst, würde ich definitiv auf das CardLayout setzen. Definiere ein Panel für die Übersicht und ein Panel für die Steuerung/Detailansicht, dann kannst Du jederzeit von einer der unzähligen Varianten zu anderen wechseln.

Persönlich würde ich mit zuerst mit der Schnittstelle auseinander setzen und die GUI zuletzt implementieren. Entscheidend ist ja letztendlich welchen Input in welcher Form die Schnittstelle benötigt.

Und was spricht dagegen, alles zusammen (also die LEDs, deren Steuerung und die Anzeige der Werte) gleichzeitig im Frame anzuzeigen? Wozu musst du irgendwas wechseln oder einen Dialog öffnen?

[QUOTE=_Michael;62149]Heißt: Du hast eine Übersicht, auf der alle LEDs gelistet/angezeigt werden. Wird eine davon angewählt wird auf eine Art Detailsicht gewechselt (und die soll/darf nicht im Frame angezeigt werden?) In der Detailansicht wird dann zuvor ausgewählte LED gedimmt. Wenn Du da den Übersichtsframe angezeigt lassen willst und die Einstellung in einem (evtl. modalen) Dialog durchführen willst, würde ich definitiv auf das CardLayout setzen. Definiere ein Panel für die Übersicht und ein Panel für die Steuerung/Detailansicht, dann kannst Du jederzeit von einer der unzähligen Varianten zu anderen wechseln.

Persönlich würde ich mit zuerst mit der Schnittstelle auseinander setzen und die GUI zuletzt implementieren. Entscheidend ist ja letztendlich welchen Input in welcher Form die Schnittstelle benötigt.[/QUOTE]

Jap mit der Schnittstelle zuerst macht eigentlich mehr Sinn aber ich hatte gerade Lust auf die GUI und habe die einfach mal angefangen, wobei die ganzen Fragen aufkamen, wollte erstmal nur das Grundgerüst machen.

Also ich wollte im Mainframe verschiedene Optionen anbieten, wie z.B. LED-Dimmer (hell/dunkel) Lauflicht (verschiedene Geschwindigkeiten/Optionen) Sonderfunktionen (wild durcheinander Leuchten,…)

Und da dachte ich, ich öffne pro Option ein neuen Frame/Dialog/…

Die Detailansicht dann im UnterFrame zu machen darf ich, habe da keine konventionen. Steige aber gerade erst in das Thema ein und habe von daher noch nicht den Überblick über alle Möglichkeiten. Wenn ich eure Beiträge verstehe denke ich macht es Sinn, dass ich pro Mainframe-Option ein neues Fenster öffne und in diesem dann alle Details reinpacke. Und wie gesagt ich muss mir mal den CardLayout ansehen.

Nochmal: Warum für jede Option ein neues Fenster? Warum nicht alles in einer Ansicht? So eine Art Mischpult, wo du dann verschiedene Optionen einstellen kannst…

Fände das glaube ich übersichtlicher, wenn man z.B. für die Steuerung der Dimmung ein neues Fenster bekommt. Da kommen insgesamt ziemlich viele Funktionen zusammen und daher denke ich alles in einem Frame wäre zu viel. Aber du hast recht, man sollte nicht zu viele pop-ups bauen, also werde ich in die UnterFenster alles wie ein Mischpult aufbauen. Oder spricht was dagegen überhaupt neue Fenster zu erzeuegn?

Viele Grüße

Ich würde nicht zu viele Fenster/Dialoge machen, das wird sonst zu unübersichtlich. Bei einem Musikmischpult hast du ja auch viele Optionen (Lautstärke, Bass, Effekte…) in einer Steuerung, und letztlich kommt hinten nur 1 Sound heraus. Warum also nicht Dimmer, Lauflicht usw. alles zusammen mit der Anzeige in ein Fenster?

Okay, ich werde mal beide Varianten ausprobieren und dann gucken was mir besser gefällt, danke für die Idee!

Weil nicht notwendig? Mehrere Fenster machen ja nur Sinn, wenn mehrerer Informationen/Optionen (die auf einem Frame evtl. zu unübersichtlich sind) für den Anwender gleichzeitig zugänglich sein sollen. Sollen z.B. während „Lauflicht“ aktiv ist einzelne LEDs gedimmt werden?