【问题标题】:Java - My action event doesn't workJava - 我的动作事件不起作用
【发布时间】:2017-06-29 05:20:04
【问题描述】:

我正在学习 Java 和 Swing,但我的 JButton 不起作用。

import javax.swing.JFrame;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class Programma {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        }

        catch (Exception e){
            e.printStackTrace();
        }


        JFrame frame = new JFrame("DIG");
        JPanel panel = new JPanel();
        JButton button = new JButton("Click Me");

        frame.setSize(400, 400);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        button.setBounds(100, 100, 130, 35);

        panel.add(button);
        frame.add(panel);

        button.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub

                JLabel label = new JLabel("Hello World");
                label.setVisible(true);
                panel.add(label);

            }
        });

    }
}
  1. 框架和按钮是可见的,当我点击它时,标签没有出现。我该如何解决这个问题?

  2. 我是在 JPanel、JButton 等其他组件之前写这个,还是在代码末尾写这个:

    frame.setVisible(true);

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

有什么区别?

顺便说一句,button.setBounds(100, 100, 130, 35) 也不起作用。

【问题讨论】:

    标签: java swing user-interface jframe


    【解决方案1】:

    我在您的代码中发现了一些问题:

    1. button.setBounds(100, 100, 130, 35); 该行将被忽略,您不应手动确定组件的位置。请参阅 Null layout is evilWhy is it frowned upon to use a null layout in swing? 尽管您没有使用 null 布局,但解释了为什么您不应该手动确定组件的位置。

    2. 您正在以main 方法运行程序中的所有内容,以后将难以维护。

    3. 您在向其添加所有元素之前调用frame.setVisible(true),这会导致随机问题。

    4. 您没有在Event Dispatch Thread (EDT) 上运行您的程序,您可以通过使用以下代码启动您的程序来解决此问题,该代码将其放置在 EDT 中。推荐它,因为 Swing 不是线程安全的。

      public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
              @Override
              public void run() {
                  //Your constructor here
              }
          });
      }
      
    5. 您使用setSize(...) 设置JFrame 的大小,而不是调用frame.pack() 并覆盖JPanelgetPreferredSize() 方法。


    说完以上所有内容后,您需要在您的ActionListener 上调用revalidate()repaint(),以便您的程序绘制其新状态。

    该程序遵循上述所有建议并产生以下输出(单击之前和单击按钮 3 次之后),我故意不使图像太大,使 GUI 更短(200 x 200 而不是 400 x 400)

    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.BoxLayout;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    public class Programma {
    
        private JFrame frame;
        private JPanel panel;
        private JButton button;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Programma().createAndShowGui();
                }
            });
        }
    
        public void createAndShowGui() {
            frame = new JFrame("DIG");
            panel = new JPanel() {
                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(400, 400);
                }
            };
            button = new JButton("Click Me");
    
            panel.add(button);
    
            button.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    JLabel label = new JLabel("Hello World");
                    panel.add(label);
    
                    panel.revalidate();
                    panel.repaint();
                }
            });
    
            frame.add(panel);
    
            frame.pack();
            frame.setVisible(true);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    }
    

    我是在 JPanel、JButton 等其他组件之前写这个还是在代码末尾写这个?

    frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    有什么区别?

    尽管我在建议中回答了这个问题,但不同之处在于,如果您在将所有元素添加到框架之前调用 setVisible,那么您会发现自己遇到一些随机问题,其中组件在您通过之前并不全部可见将鼠标悬停在它们(或它们应该在的位置)上。 frame.pack()setVisible 应该是程序中最后被调用的,frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 可以在开头或结尾,不影响,但我也更喜欢在结尾。

    button.setBounds(100, 100, 130, 35);也不行。

    嗯,这是因为您使用的是 layout manager(这是制作 GUI 的正确方法)而不是 null-layout(无论如何您都不应该使用它)(参见第 1 点)。


    编辑

    frame.setSize(); 有什么区别?和 frame.setpack() ?

    如果您阅读docspack()

    调整此窗口的大小以适合其子组件的首选大小和布局。如果任一尺寸小于先前调用 setMinimumSize 方法指定的最小尺寸,则生成的窗口宽度和高度会自动放大。

    因此,它将计算您的 JFrame 的最小尺寸,其中所有元素都可见并以其首选尺寸,而 setSize 只会设置窗口大小,但如果您在其中放置 JScrollBar 例如这将减小窗口大小,正因为如此,这就是为什么您应该覆盖容器的 getPreferredSize(...) 方法,因此它将计算其首选大小,包括 JScrollBar 的宽度或其他一些可以修改其大小的元素。见Should I avoid the use of setPreferred|Maximum|MinimumSize in Swing?(普遍共识是

    【讨论】:

    • frame.setSize(); 有什么区别和 frame.setpack() ?谢谢你的回答。
    【解决方案2】:

    当您将组件动态添加到面板时,您需要重新绘制它。

    这样做

    panel.revalidate(); 
    

    之后

    panel.add(label);
    

    【讨论】:

    • 谢谢 Jayesh :) 但是 panel.validate,它有什么作用?它需要什么? A2:所以我可以把我的组件放在我想要的地方?
    • 如果它解决了你的问题,你可以接受这个答案或投票给我的答案
    • “A2:你把它们放在哪里和按什么顺序都没有关系。” 哦,是的!很重要!看我的回答...不是validate,应该是revalidate():看这个stackoverflow.com/questions/9510125/…
    • 你写了“panel.validate();”我现在很困惑:D
    猜你喜欢
    • 1970-01-01
    • 2014-07-20
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多