Text in Label ändern

nossek

Aktives Mitglied
Hallo,
(denke mal das Thema ist hier besser aufgehoben als im GUI-Unterforum, oder?!)

ich möchte ein ganz einfaches Programm schreiben, das ein Fenster öffnet, das 3 Buttons (Plus, Minus und Exit) enthält sowie ein Label (könnte auch eine TextComponent sein, soll jedenfalls nur anzeigen - für die Frage vermutlich unerheblich).

Beim Start zeigt das Label 0 an. Ihr ahnt es, wenn der Plus-Button gedrückt wird, soll der im Label angezeigte Wert um 1 erhöht werden, wenn der Minus-Button gedrückt wird eben um 1 vermindert.

Bislang sieht der code so aus, der ActionListener:
Java:
import java.awt.event.*; 

class MyActionListener implements ActionListener {
    int zaehler = 0;

    public void actionPerformed(ActionEvent ae) {
        String s = ae.getActionCommand();
        if (s.equals("Exit")) {
            System.out.println("Programm wird beendet");
            System.exit(0);
        }
        if (s.equals("Plus")) {
            zaehler++;
            System.out.println(zaehler);
        }
        if (s.equals("Minus")) {
            zaehler--;
            System.out.println(zaehler);
        }
    }

}
Das Hauptprogramm:
Java:
import java.awt.*;
import java.awt.event.*;

public class Main {
    public static void main(String[] args){

        Button b;
        Label l = new Label("1", Label.CENTER);
        ActionListener a = new MyActionListener();
        Frame f = new Frame();

        f.add(l, BorderLayout.NORTH);

        f.add(b = new Button("Plus"), BorderLayout.WEST);
        b.addActionListener(a);

        f.add(b = new Button("Minus"), BorderLayout.CENTER);
        b.addActionListener(a);

        f.add(b = new Button("Exit"), BorderLayout.EAST);
        b.addActionListener(a);

        f.pack();
        f.setVisible(true);
    }
}

Wie man sieht, wird der neue Wert des Zählers bislang nur in der Konsole ausgegeben.

Mal abgesehen davon, daß an dem Programm bestimmt vieles zu kritisieren ist, folgene Fragen:

- Wie bekomme ich es hin daß der neue Wert im Label angezeigt wird?

- Mir kommt das seltsam vor, daß die Variable zaehler ein attribut vom ActionListener ist. Nach meiner Vorstellung sollte der Zähler ein Attribut von main sein. Jedenfals nicht vom ActionListener. Wie kann denn Der ActionListener dafür sorgen, daß eine Variable "ausserhalb" verändert werden kann?

Habe folgendes Codebeispiel gefunden, ein Alptraum, vlt. sollte ich doch besser auf H9Q+ umsteigen 😉
Java/GUI Beispiel Zähler ? ZUM-Wiki
 
Zuletzt bearbeitet von einem Moderator:
Die Klasse Label hat doch eine Methode setText(String text), da kannst du doch das int zaehler als String übergeben und eine eigene Methode schreiben, die den Text bei jeder Änderung von zaehler anpasst (updateLabel() oder so).

BTW: Ich habe gehört, es solle nicht so ratsam sein, auf AWT noch eine komplette GUI aufzubauen, da es veraltet sei, und man solle lieber Swing nehmen. Da gibt's dann JButton, JLabel etc. (letztes hat auch eine Methode setText() 😉).
 
Normalerweise müsste es sich nach dem Aufruf von .setText() selbst updaten!
Hat bei mir jedenfalls immer funktioniert! ;-)
 
- Mir kommt das seltsam vor, daß die Variable zaehler ein attribut vom ActionListener ist. Nach meiner Vorstellung sollte der Zähler ein Attribut von main sein. Jedenfals nicht vom ActionListener.
main kann keine Attribute besitzen, da es sich hierbei nicht um ein Objekt sondern um eine statische Klasse handelt ;-)
Habe folgendes Codebeispiel gefunden, ein Alptraum, vlt. sollte ich doch besser auf H9Q+ umsteigen 😉
Java/GUI Beispiel Zähler ? ZUM-Wiki
Da muss ich zustimmen. Dafür das es als Beispiel dient ist es etwas unschön. (Liegt u.a. daran, das ein GUI Editor zur Erstellung der Oberfläche verwendet wurde. Aber immerhin zeigt es sehr schön wie man objektorientiert programmiert. Der Zähler ist hierbei nicht einfach eine primitive Variable sondern ein echtes Objekt.

Hier mal zwei Demos wie man Dein Problem lösen könnte. Die Variable zaehler ist dabei nicht Attribut des Listeners. Man könnte sie noch in eigenes Model auslagern, das wäre hier aber vielleicht etwas übertrieben. Ich persönlich würde die Variante in Demo1 bevorzugen, das sie recht kompakt ist:
Java:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class ActionListenerDemo extends JFrame {
	
	public ActionListenerDemo() {
		this.getContentPane().setLayout(new GridLayout(2, 1, 0, 20));
		this.getContentPane().add(new Demo1());
		this.getContentPane().add(new Demo2());
	}
	
	class Demo1 extends JPanel {
		private int zaehler;
		private JLabel label;
		
		public Demo1() {
			this.setLayout(new BorderLayout());
			zaehler = 0;
		
			label = new JLabel(String.valueOf(zaehler), JLabel.CENTER);
			this.add(label, BorderLayout.CENTER);
			JButton button = new JButton("-");
			this.add(button, BorderLayout.WEST);
			button.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent evt) {
					label.setText(String.valueOf(--zaehler));
				}	
			});
			button = new JButton("+");
			this.add(button, BorderLayout.EAST);
			button.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent evt) {
					label.setText(String.valueOf(++zaehler));
				}	
			});
		}
	}
	
	class Demo2 extends JPanel {
		private int zaehler;
		private JLabel label;
		
		public Demo2() {
			this.setLayout(new BorderLayout());
			zaehler = 0;
			label = new JLabel(String.valueOf(zaehler), JLabel.CENTER);
			this.add(label, BorderLayout.CENTER);
			
			ActionListener listener = new ZaehlerListener(this);
			JButton button = new JButton("-");
			this.add(button, BorderLayout.WEST);
			button.addActionListener(listener);
			button = new JButton("+");
			this.add(button, BorderLayout.EAST);
			button.addActionListener(listener);
		}
		
		public void increaseNumber() {
			label.setText(String.valueOf(++zaehler));
		}
		
		public void reduceNumber() {
			label.setText(String.valueOf(--zaehler));
		}
	}
	
	class ZaehlerListener implements ActionListener {
		private Demo2 demo;
		
		public ZaehlerListener(Demo2 demo) {
			this.demo = demo;
		}
		
		public void actionPerformed(ActionEvent evt) {
			String command = evt.getActionCommand();
			if (command.equals("-"))
				demo.reduceNumber();
			else if (command.equals("+"))
				demo.increaseNumber();
			else
				System.out.println("Invalid action command: " + command);
		}	
	}
	
	public static void main(String[] args) {
		JFrame frame = new ActionListenerDemo();
		frame.setBounds(0, 0, 300, 200);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
 
Danke zunächst einmal an alle! Muß mir das alles in Ruhe anschauen und probieren.

GUI-Orgrammierung scheint einer der schwierigsten Teile von Java zu sein - und wenn ich mir die Lehrbücher anschaue scheint sie auch die höchsten Ansprüche an die didaktischen Fähigkeiten der Autoren zu stellen. Daß AWT veraltet ist habe ich natürlich auch schon gelesen. Trotzdem werden in allen swing-Beispielen auch AWT-Elemente eingebunden, das ist schon alles sehr verwirrend.

Zunächst einmal:
main kann keine Attribute besitzen, da es sich hierbei nicht um ein Objekt sondern um eine statische Klasse handelt
Ähhh, daß main eine statische Klasse ist war mir schon klar. Und das eine statische Klasse keine Attribute besitzt irgendwie auch.
Wenn wir haben:
Java:
public static void main(String[] args){
     int i;
     ...
was ist den dann die korrekte Bezeichnung für i? Globale Variable?
 
Methodenvariable. Die ist dann nur im Methodenstack und ich für andere nicht sichtbar, deswegen hat es mit "global" nichts zu tun.
 
main kann keine Attribute besitzen, da es sich hierbei nicht um ein Objekt sondern um eine statische Klasse handelt
Meinte na klar statische Methode
Wenn wir haben:
Java:
public static void main(String[] args){
     int i;
     ...
was ist den dann die korrekte Bezeichnung für i? Globale Variable?
i ist eine Methodenvariable die nur lokal also innerhalb der Methode gilt.
Trotzdem werden in allen swing-Beispielen auch AWT-Elemente eingebunden, das ist schon alles sehr verwirrend.
Swing basiert auf AWT und verwendet u.a. Events aus diesem Package. Wichtig ist, dass man keine GUI Elemente beider Packages gemeinsam verwendet.
 
Michael, Deine Demo-Beispiele sind sehr hilfreich und eine gute Grundlage für eigene Experimente, vielen Dank nochmals.

Du hast Recht, Demo1 ist kompakter, allerdings ist mir die Syntax des folgenden Ausdrucks nicht vertraut:
Java:
button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    label.setText(String.valueOf(++zaehler));
                }   
            });
Objekt.methode(Argument)
ist soweit natürlich bekannt, nur das Argument ist in diesem Fall ja
new InterfaceName() Anweisungsblock
das habe ich bislang nocht nicht gesehen und verstehe es nicht. Kann das jemand näher erläutern? Gibt es andere Beispiele für diese Syntax? (hat wohl was damit zu tun daß ActionListener ein Interface ist?!).

Frage 2:
Spricht etwas dagegen daß (bei einem überschaubaren Projekt wie diesem) die Komponenten (JBUtton, JPanel etc.) Attribute der von JFrame abgeleiteten Klasse sind? Das erscheint mir zunächst einmal übersichtlicher.

Frage 3:
Irgendwie erscheint es mir nicht richtig, daß die Varible zaehler ein Attribut vom JPanel oder JFrame ist. Nach meinem Verständnis ist ein JFrame bzw. JPanel ja dazu dar, Daten darzustellen bzw. Zugriff auf Daten zu ermöglichen. Und nicht, die Daten zu enthalten.

Grübel, die Klasse Frame muß wohl schon eine Referenz auf ein Objekt der Klasse Zaehler als Attribut enthalten, gell? Und dann eine Methode setZaehler(Zaehler) haben, um die Verbindung herzustellen.

Und dann vielleicht so:
Java:
public class Main {
    public static void main(String[] args) {
        Zaehler zaheler = new Zaheler();
        MyJFrame frame = new MyJFrame();
        frame.setZaehler(zaehler);     
    }
}
Geht das in die richtige Richtung?
 
Du hast Recht, Demo1 ist kompakter, allerdings ist mir die Syntax des folgenden Ausdrucks nicht vertraut:
Java:
button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    label.setText(String.valueOf(++zaehler));
                }   
            });
Objekt.methode(Argument)
ist soweit natürlich bekannt, nur das Argument ist in diesem Fall ja
new InterfaceName() Anweisungsblock
das habe ich bislang nocht nicht gesehen und verstehe es nicht. Kann das jemand näher erläutern? Gibt es andere Beispiele für diese Syntax? (hat wohl was damit zu tun daß ActionListener ein Interface ist?!).
Das nennt sich anonyme Klasse - hier mal ein Link, was die Java-Insel dazu sagt: Klick
 
, allerdings ist mir die Syntax des folgenden Ausdrucks nicht vertraut:
Java:
button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    label.setText(String.valueOf(++zaehler));
                }   
            });
Objekt.methode(Argument)
ist soweit natürlich bekannt, nur das Argument ist in diesem Fall ja
new InterfaceName() Anweisungsblock
das habe ich bislang nocht nicht gesehen und verstehe es nicht. Kann das jemand näher erläutern? Gibt es andere Beispiele für diese Syntax? (hat wohl was damit zu tun daß ActionListener ein Interface ist?!).
Hat jetzt nicht direkt was damit zu tun, dass es sich um ein Interface handelt, das geht auch mit Klassen.
Hier wird einfach eine innere anonyme Klasse definiert, die ActionListener implementiert. Im Gegensatz zu Demo2 hier wird eine "bekannte" Klasse verwendet.
Frage 2:
Spricht etwas dagegen daß (bei einem überschaubaren Projekt wie diesem) die Komponenten (JBUtton, JPanel etc.) Attribute der von JFrame abgeleiteten Klasse sind? Das erscheint mir zunächst einmal übersichtlicher.
Meiner Meinung spricht da nichts dagegen.
Frage 3:
Irgendwie erscheint es mir nicht richtig, daß die Varible zaehler ein Attribut vom JPanel oder JFrame ist. Nach meinem Verständnis ist ein JFrame bzw. JPanel ja dazu dar, Daten darzustellen bzw. Zugriff auf Daten zu ermöglichen. Und nicht, die Daten zu enthalten.

Grübel, die Klasse Frame muß wohl schon eine Referenz auf ein Objekt der Klasse Zaehler als Attribut enthalten, gell? Und dann eine Methode setZaehler(Zaehler) haben, um die Verbindung herzustellen.

Und dann vielleicht so:
Java:
public class Main {
    public static void main(String[] args) {
        Zaehler zaheler = new Zaheler();
        MyJFrame frame = new MyJFrame();
        frame.setZaehler(zaehler);     
    }
}
Geht das in die richtige Richtung?
Bei so einfachen Sachen nicht unbedingt notwendig, bei umfangreicheren Projekten aber üblich. siehe Link den Du mal gepostest hast oder auch MVC Pattern
 
Herzlichen Dank für die wieder einmal schnellen und hilfreichen Antworten!
Vielleicht muß ich nun doch nicht auf H9Q+ umsteigen.
Da die ursprüngliche Frage beantwortet ist drücke ich den "Erledigt-Button".
 
Zuletzt bearbeitet:

Zurück
Oben