Komponieren von Swing-Komponenten: Wie füge ich die Fähigkeit hinzu, ActionListeners hinzuzufügen?

Ich möchte eine (einfache, hoffentlich) benutzerdefinierte Swing-Komponente erstellen, indem ich mehrere vorhandene Komponenten zusammensetze. In meinem Fall ist es ein Ein-Aus-Schalter, der aus einem JLabel und zwei JButtons für On und Off besteht. Ich beginne OnOffSwitch, indem ich JPanel erweitere. Der Konstruktor fügt die Unterkomponenten hinzu und richtet sich als ActionListener für die Schaltflächen ein. Die class verfügt über eine isOn () – Methode zum Abfragen des aktuellen Status der Komponente.

Ich möchte jetzt die Möglichkeit hinzufügen, ActionListeners der OnOffSwitch-class hinzuzufügen. Ich hatte erwartet, dass diese functionalität kostenlos zur Verfügung stehen würde, indem ich eine Swing-Komponente wie JPanel erweitert habe, aber JPanel hat diese functionalität nicht. Nach dem Aussehen der Quellen implementiert jede Swing-Komponente, die über diese functionalität verfügt, sie selbst erneut: das Hinzufügen von Listenern zur Liste, das Auslösen von ActionEvents usw.

Was ist der richtige Weg, um das zu erreichen, was ich will? Ich kann diesen Code aus den verschiedenen Swing-Komponenten kopieren oder einfügen (oder den core davon neu schreiben), oder ich kann meine eigene OnOffSwitchListener-Schnittstelle implementieren. Um konsistent zu sein, sollten alle meine Komponenten ActionListeners verwenden.

Ich persönlich denke nicht, dass Sie eine benutzerdefinierte Swing-Komponente benötigen. Es ist nicht erforderlich, dass Ihre UI-class eine Swing-class erweitert. Sie werden wahrscheinlich nicht viel benutzerdefiniertes Verhalten bieten. (Ich könnte für ein JPanel einräumen, das andere zusammensetzt.)

Ich würde die Komposition der inheritance vorziehen. Haben Sie eine UI-class mit Swing-Datenmembern und geben Sie Methoden an, um Listener hinzuzufügen und zu entfernen, wenn Sie sie benötigen. Sie können das Verhalten auf diese Weise ändern, ohne die UI-class neu schreiben zu müssen. Es ist nichts weiter als ein Container.

public class MyUI { private Button b = new Button(); public void addButtonListener(ActionListener listener) { this.b.addActionListener(listener); } } 

Ich würde einen JToggelButton wie hier gezeigt verwenden oder an die enthaltenen Schaltflächen delegieren, wie @duffymo es vorschlägt. Wenn Sie wirklich ein benutzerdefiniertes OnOffSwitchEvent benötigen, wird die Standardverdrahtung in EventListenerList , eine Instanz, die in jeder JComponent .

Nachtrag: Hier ist ein Beispiel für das Delegieren an eine ButtonGroup die zwei Schaltflächen enthält. Das Etikett ist mit einem Symbol verziert, aber jede Implementierung von Icon ist noch flexibler.

BttonGroupTest Iamge

 import java.awt.Color; import java.awt.EventQueue; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ButtonGroup; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JToggleButton; /** @see https://stackoverflow.com/questions/6035834 */ public class ButtonGroupTest extends JComponent { private static final String ON = "On"; private static final String OFF = "Off"; private final JToggleButton bOn = new JToggleButton(ON); private final JToggleButton bOff = new JToggleButton(OFF); private final JLabel label = new JLabel(" \u2301 "); private final ButtonHandler handler = new ButtonHandler(); public ButtonGroupTest() { this.setLayout(new FlowLayout()); label.setOpaque(true); label.setBackground(Color.red); label.setFont(label.getFont().deriveFont(36f)); ButtonGroup bg = new ButtonGroup(); this.add(bOn); bg.add(bOn); bOn.setSelected(true); bOn.addActionListener(handler); this.add(label); this.add(bOff); bg.add(bOff); bOff.addActionListener(handler); } public void addActionListener(ActionListener listener) { bOn.addActionListener(listener); bOff.addActionListener(listener); } private class ButtonHandler implements ActionListener { @Override public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if (ON.equals(cmd)) { label.setBackground(Color.red); } else { label.setBackground(Color.black); } } } private void display() { JFrame f = new JFrame("ButtonGroupTest"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(this); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new ButtonGroupTest().display(); } }); } } 

Nach dem Aussehen der Quellen implementiert jede Swing-Komponente, die über diese [ActionListener] -functionalität verfügt, diese selbst erneut: das Hinzufügen von Listenern zur Liste, das Auslösen von ActionEvents usw.

Ja. Das müssen Sie tun, wenn Sie eine benutzerdefinierte Swing-Komponente schreiben.

Wie Sie sagen, können Sie den ActionListener Code aus einer vorhandenen Swing-Komponente kopieren,