简体   繁体   English

编写Swing组件:如何添加添加ActionListeners的功能?

[英]Composing Swing Components: How do I add the ability to add ActionListeners?

I want to create a (simple, hopefully) custom Swing component by composing several existing components. 我想通过组合几个现有组件来创建一个(简单的,有希望的)自定义Swing组件。 In my case, it is an on-off switch which consists of a JLabel, and two JButtons for On and Off. 在我的例子中,它是一个开关开关,由一个JLabel和两个用于On和Off的JButton组成。 I begin OnOffSwitch by extending JPanel. 我通过扩展JPanel来开始OnOffSwitch。 The constructor adds the sub-components, and sets itself up as an ActionListener for the buttons. 构造函数添加子组件,并将其自身设置为按钮的ActionListener。 The class has an isOn() method for querying the current state of the component. 该类有一个isOn()方法,用于查询组件的当前状态。

I now want to add the ability to add ActionListeners to the OnOffSwitch class. 我现在想要添加将ActionListeners添加到OnOffSwitch类的功能。 I expected this functionality would come for free by having extended a Swing component like JPanel, but JPanel does not have this functionality. 我希望通过扩展像JPanel这样的Swing组件来免费提供这个功能,但是JPanel没有这个功能。 By the looks of the sources, every Swing component which does have this functionality re-implements it itself: the adding listeners to the list, the firing of ActionEvents, etc. 通过源代码的外观,具有此功能的每个Swing组件都会自行重新实现它:向列表添加侦听器,触发ActionEvents等等。

What is the correct way to achieve what I want? 实现我想要的正确方法是什么? I can copy/paste that code from the various Swing components (or re-write the gist of it), or I can implement my own OnOffSwitchListener interface. 我可以从各种Swing组件中复制/粘贴该代码(或重写其中的要点),或者我可以实现自己的OnOffSwitchListener接口。 To be consistent it seems that all my components should use ActionListeners. 为了保持一致,似乎所有组件都应该使用ActionListeners。

I'd use a JToggelButton , as shown here , or delegate to the contained buttons, as @duffymo suggests. 我会使用一个JToggelButton ,如图所示这里 ,或委托给包含的按钮,如@duffymo建议。 If you really need a custom OnOffSwitchEvent , the standard wiring is outlined in EventListenerList , an instance of which is contained in every JComponent . 如果您确实需要自定义OnOffSwitchEvent ,则会在EventListenerList概述标准接线,其实例包含在每个JComponent

Addendum: Here's an example of delegating to a ButtonGroup containing two buttons. 附录:这是委托给包含两个按钮的ButtonGroup的示例。 The label is decorated with a symbol, but any implementation of Icon is even more flexible. 标签用符号装饰,但Icon任何实现都更加灵活。

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();
            }
        });
    }
}

I personally don't think you need a custom Swing component. 我个人认为你不需要自定义Swing组件。 No need for your UI class to extend any Swing class; 您的UI类不需要扩展任何Swing类; you aren't likely to provide much custom behavior. 你不太可能提供很多自定义行为。 (I might concede for a JPanel that composes others.) (我可能会承认组成其他人的JPanel。)

I would prefer composition over inheritance. 我宁愿构图而不是继承。 Have a UI class that has Swing data members and give it methods to add and remove Listeners as you need them. 拥有一个具有Swing数据成员的UI类,并为其提供在需要时添加和删除Listener的方法。 You can change the behavior that way without having to rewrite the UI class. 您可以通过这种方式更改行为,而无需重写UI类。 It's nothing more than a container. 它只不过是一个容器。

public class MyUI
{
    private Button b = new Button();

    public void addButtonListener(ActionListener listener) { this.b.addActionListener(listener); }
}

By the looks of the sources, every Swing component which does have this [ActionListener] functionality re-implements it itself: the adding listeners to the list, the firing of ActionEvents, etc. 通过源代码的外观,每个具有此[ActionListener]功能的Swing组件都会自行重新实现它:向列表添加侦听器,触发ActionEvents等等。

Yep. 是的。 That's what you have to do when you're writing a custom Swing component. 这就是你在编写自定义Swing组件时必须要做的事情。

As you say, you can copy the ActionListener code from an existing Swing component, 如您所说,您可以从现有的Swing组件复制ActionListener代码,

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM