JSpinner与其他摆动组件有何不同?

时间:2012-12-12 15:35:54

标签: java swing jcomponent jspinner

我有一个方法可以递归启用/禁用JPanel中的所有组件。还有例外列表。所以我可以做以下

  • 禁用panel1中的所有组件,但应启用的textfield1, textfield3除外。
  • 启用panel2中的所有组件,但应禁用的button2, label3除外。

这是一个完全相同的SSCCE:

import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;

public class Main {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        final JPanel panel = new JPanel(new GridLayout(3, 3));

        final JTextField textfield = new JTextField("asdf");
        final JButton button = new JButton("asdf");
        final JCheckBox checkbox = new JCheckBox("asdf");
        final JSpinner spinner = new JSpinner(new SpinnerNumberModel(1, 1, 100, 1));
        final JLabel label = new JLabel("asdf");

        panel.add(textfield);
        panel.add(button);
        panel.add(checkbox);
        panel.add(spinner);
        panel.add(label);
        // fill in some random stuff
        for (int i = 0; i < 4; i++)
            panel.add(new JLabel("asdf"));

        frame.setContentPane(panel);
        frame.setSize(300, 100);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean toggle = true;
                while (true) {
                    toggle = !toggle;
                    Set<Component> enableList = new HashSet<Component>();
                    Set<Component> disableList = new HashSet<Component>();
                    enableList.add(textfield);
                    enableList.add(spinner);
                    disableList.add(checkbox);
                    setEnableAllRec(panel, toggle, disableList, enableList);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {}
                }
            }
        }).start();
        frame.setVisible(true);
    }

    public static void setEnableAllRec(Container root, boolean defaultState, Set<Component> disableList, Set<Component> enableList) {
        if (root == null) return;
        for (Component c : root.getComponents()) {
            if (disableList != null && disableList.contains(c)) {
                c.setEnabled(false);
                disableList.remove(c);
            } else if (enableList != null && enableList.contains(c)) {
                c.setEnabled(true);
                enableList.remove(c);
            } else c.setEnabled(defaultState);
            if (c instanceof Container) setEnableAllRec((Container) c, defaultState, disableList, enableList);
        }
    }
}

SSCCE每秒设置所有组件以交替启用/禁用。除了一些应该始终启用的组件和一些应该始终禁用的组件。除了JSpinner之外,这非常有效。它被检测为一个组件,但在列表中找不到(因此不作为特殊情况处理)。我尝试过的所有其他挥杆组件都按预期工作。

你能告诉我JSpinner的错误吗?

我希望SSCCE不会太混乱......;)

1 个答案:

答案 0 :(得分:3)

只是因为JSpinner包含其他组件,例如2个按钮和一个编辑器(请参阅javax.swing.plaf.basic.BasicSpinnerUI的代码),并且您在所有容器上递归,因此,也包含JSpinner的包含组件。

顺便说一下,你的线程违反了Swing-EDT。您应该在Swing Timer

中执行此操作

解决方案很简单:

import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;

public class Main {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        final JPanel panel = new JPanel(new GridLayout(3, 3));

        final JTextField textfield = new JTextField("asdf");
        final JButton button = new JButton("asdf");
        final JCheckBox checkbox = new JCheckBox("asdf");
        final JSpinner spinner = new JSpinner(new SpinnerNumberModel(1, 1, 100, 1));
        final JLabel label = new JLabel("asdf");

        panel.add(textfield);
        panel.add(button);
        panel.add(checkbox);
        panel.add(spinner);
        panel.add(label);
        // fill in some random stuff
        for (int i = 0; i < 4; i++) {
            panel.add(new JLabel("asdf"));
        }

        frame.setContentPane(panel);
        frame.setSize(300, 100);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean toggle = true;
                while (true) {
                    toggle = !toggle;
                    Set<Component> enableList = new HashSet<Component>();
                    Set<Component> disableList = new HashSet<Component>();
                    enableList.add(textfield);
                    enableList.add(spinner);
                    disableList.add(checkbox);
                    setEnableAllRec(panel, toggle, disableList, enableList);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }
            }
        }).start();
        frame.setVisible(true);
    }

    public static void setEnableAllRec(Container root, boolean defaultState, Set<Component> disableList, Set<Component> enableList) {
        if (root == null) {
            return;
        }
        for (Component c : root.getComponents()) {
            if (disableList != null && disableList.contains(c)) {
                c.setEnabled(false);
                disableList.remove(c);
            } else if (enableList != null && enableList.contains(c)) {
                c.setEnabled(true);
                enableList.remove(c);
            } else {
                c.setEnabled(defaultState);
                if (c instanceof Container) {
                    setEnableAllRec((Container) c, defaultState, disableList, enableList);
                }
            }
        }
    }
}