Java Swing:启用/禁用JPanel中的所有组件

8

我有一个包含JToolbar(包括几个没有文本的按钮)和JTable的JPanel,我需要启用/禁用(使内部小部件无法点击)。 我尝试了这个方法:

 JPanel panel = ....;
 for (Component c : panel.getComponents()) c.setEnabled(enabled);

但是它不能正常工作。有没有更好、更通用的解决方案来启用/禁用JPanel中的所有内部组件?
我已经从这个例子http://docs.oracle.com/javase/tutorial/uiswing/misc/jlayer.html开始使用JLayer部分解决了我的问题。
layer = new JLayer<JComponent>(myPanel, new BlurLayerUI(false));
.....
((BlurLayerUI)layer.getUI()).blur(...); // switch blur on/off


class BlurLayerUI extends LayerUI<JComponent> {
  private BufferedImage mOffscreenImage;
  private BufferedImageOp mOperation;

  private boolean blur;

  public BlurLayerUI(boolean blur) {
      this.blur = blur;
      float ninth = 1.0f / 9.0f;
        float[] blurKernel = {
          ninth, ninth, ninth,
          ninth, ninth, ninth,
          ninth, ninth, ninth
        };
        mOperation = new ConvolveOp(
                new Kernel(3, 3, blurKernel),
                ConvolveOp.EDGE_NO_OP, null);
        }

  public void blur(boolean blur) {
      this.blur=blur;
    firePropertyChange("blur", 0, 1);
   }

  @Override
  public void paint (Graphics g, JComponent c) {
      if (!blur) {
            super.paint (g, c);
            return;
        }

      int w = c.getWidth();
    int h = c.getHeight();



    if (w == 0 || h == 0) {
      return;
    }

    // Only create the offscreen image if the one we have
    // is the wrong size.
    if (mOffscreenImage == null ||
            mOffscreenImage.getWidth() != w ||
            mOffscreenImage.getHeight() != h) {
      mOffscreenImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    }

    Graphics2D ig2 = mOffscreenImage.createGraphics();
    ig2.setClip(g.getClip());
    super.paint(ig2, c);
    ig2.dispose();

    Graphics2D g2 = (Graphics2D)g;
    g2.drawImage(mOffscreenImage, mOperation, 0, 0);
  }

  @Override
  public void applyPropertyChange(PropertyChangeEvent pce, JLayer l) {
    if ("blur".equals(pce.getPropertyName())) {
      l.repaint();
    }
  }

}

我还有两个问题:

  1. 上面的链接中事件仅与鼠标相关。我如何管理键盘事件?

  2. 我如何创建一个“灰化”效果来代替模糊?


您可以直接使用 panel.setVisible(false) 来设置面板的可见性。 - Hans Z
setVisible(false) 会让组件“不可见”,但是实际上我需要它仍然可见,但呈现为灰色。 - Randomize
这个线程有帮助吗?https://dev59.com/V3VC5IYBdhLWcg3wZwTj#305551 - Hans Z
我已经检查了那个线程并尝试了其中的一些方法,但并没有真正取得成功。 - Randomize
你不觉得是时候接受一个答案了吗? - Andrew Thompson
4个回答

45

需要进行递归调用。

禁用容器中的所有内容

import java.awt.*;
import javax.swing.*;

public class DisableAllInContainer {

    public void enableComponents(Container container, boolean enable) {
        Component[] components = container.getComponents();
        for (Component component : components) {
            component.setEnabled(enable);
            if (component instanceof Container) {
                enableComponents((Container)component, enable);
            }
        }
    }

    DisableAllInContainer() {
        JPanel gui = new JPanel(new BorderLayout());

        final JPanel container = new JPanel(new BorderLayout());
        gui.add(container, BorderLayout.CENTER);

        JToolBar tb = new JToolBar();
        container.add(tb, BorderLayout.NORTH);
        for (int ii=0; ii<3; ii++) {
            tb.add(new JButton("Button"));
        }

        JTree tree = new JTree();
        tree.setVisibleRowCount(6);
        container.add(new JScrollPane(tree), BorderLayout.WEST);

        container.add(new JTextArea(5,20), BorderLayout.CENTER);

        final JCheckBox enable = new JCheckBox("Enable", true);
        enable.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent ae) {
                enableComponents(container, enable.isSelected());
            }
        });
        gui.add(enable, BorderLayout.SOUTH);

        JOptionPane.showMessageDialog(null, gui);
    }

    public static void main(String[] args)  {
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                new DisableAllInContainer();
            }
        });
    }}

谢谢,这个解决方案非常接近我的解决方案。但是它有同样的问题:我有一个 JTable,如果你在它上面应用 setEnabled(false),那么这个表格就不能被点击了,但与其他组件不同的是,它没有变成“灰色”。 - Randomize
1
它还存在一个问题,如果容器中的某些组件已启用而其他组件已禁用,则它们都将被设置为相同的启用状态,例如:您无法启用,然后轻松撤消它。 - user1062589
1
声明静态的 enableComponents(...) 函数。非常好用的工具函数。 - Exceptyon

5
我使用了以下函数:
void setPanelEnabled(JPanel panel, Boolean isEnabled) {
    panel.setEnabled(isEnabled);

    Component[] components = panel.getComponents();

    for(int i = 0; i < components.length; i++) {
        if(components[i].getClass().getName() == "javax.swing.JPanel") {
            setPanelEnabled((JPanel) components[i], isEnabled);
        }

        components[i].setEnabled(isEnabled);
    }
}

2
您可以覆盖整个Container / JComponent
  1. GlassPane默认情况下会阻止鼠标事件,但不会阻止键盘事件,需要从Toolkit中消耗所有键盘事件

  2. JLayer(Java7)基于JXLayer(Java6)

  3. 无法看到为什么您的操作不起作用

enter image description here

enter image description here

enter image description here

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

public class AddComponentsAtRuntime {

    private JFrame f;
    private JPanel panel;
    private JCheckBox checkValidate, checkReValidate, checkRepaint, checkPack;

    public AddComponentsAtRuntime() {
        JButton b = new JButton();
        //b.setBackground(Color.red);
        b.setBorder(new LineBorder(Color.black, 2));
        b.setPreferredSize(new Dimension(600, 20));
        panel = new JPanel(new GridLayout(0, 1));
        panel.add(b);
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(panel, "Center");
        f.add(getCheckBoxPanel(), "South");
        f.setLocation(200, 200);
        f.pack();
        f.setVisible(true);
    }

    private JPanel getCheckBoxPanel() {
        checkValidate = new JCheckBox("validate");
        checkValidate.setSelected(false);
        checkReValidate = new JCheckBox("revalidate");
        checkReValidate.setSelected(true);
        checkRepaint = new JCheckBox("repaint");
        checkRepaint.setSelected(true);
        checkPack = new JCheckBox("pack");
        checkPack.setSelected(true);
        JButton addComp = new JButton("Add New One");
        addComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JButton b = new JButton();
                //b.setBackground(Color.red);
                b.setBorder(new LineBorder(Color.black, 2));
                b.setPreferredSize(new Dimension(400, 10));
                panel.add(b);
                makeChange();
                System.out.println(" Components Count after Adds :" + panel.getComponentCount());
            }
        });
        JButton removeComp = new JButton("Remove One");
        removeComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int count = panel.getComponentCount();
                if (count > 0) {
                    panel.remove(0);
                }
                makeChange();
                System.out.println(" Components Count after Removes :" + panel.getComponentCount());
            }
        });
        JButton disabledComp = new JButton("Disabled All");
        disabledComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (Component c : panel.getComponents()) {
                    c.setEnabled(false);
                }
            }
        });
        JButton enabledComp = new JButton("Enabled All");
        enabledComp.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                for (Component c : panel.getComponents()) {
                    c.setEnabled(true);
                }
            }
        });
        JPanel panel2 = new JPanel();
        panel2.add(checkValidate);
        panel2.add(checkReValidate);
        panel2.add(checkRepaint);
        panel2.add(checkPack);
        panel2.add(addComp);
        panel2.add(removeComp);
        panel2.add(disabledComp);
        panel2.add(enabledComp);
        return panel2;
    }

    private void makeChange() {
        if (checkValidate.isSelected()) {
            panel.validate();
        }
        if (checkReValidate.isSelected()) {
            panel.revalidate();
        }
        if (checkRepaint.isSelected()) {
            panel.repaint();
        }
        if (checkPack.isSelected()) {
            f.pack();
        }
    }

    public static void main(String[] args) {
        AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
    }
}

感谢多位回答者:1)GlassPane很有趣,但我不知道如何实现模糊或灰化效果。2)我正在使用Java 6,目前不想使用外部库。3)这个解决方案在JTable上存在问题。 - Randomize
  1. 没有问题,在那里使用JLabel.setOpaque(false),并放入一些颜色(int,int,int,alpha)。
  2. JXLabel不是外部库,这是个人项目被接受为JLayer。
  3. 将JLabel放到(与第一个点相同的)JViewPort中(我希望JTable在JScrollPane中)。
  4. 你可以检查我的帖子,标记了GlassPane和JViewport。
- mKorbel
我正在尝试使用JLayer,并且我已经部分解决了问题。请查看我的重新编辑的问题。 - Randomize

0

@Kesavamoorthi 如果你想让它更加通用:

void setPanelEnabled(java.awt.Container cont, Boolean isEnabled) {
    cont.setEnabled(isEnabled);

    java.awt.Component[] components = cont.getComponents();

    for (int i = 0; i < components.length; i++) {
        if (components[i] instanceof java.awt.Container) {
            setPanelEnabled((java.awt.Container) components[i], isEnabled);
        }
        components[i].setEnabled(isEnabled);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接