Java - Swing GUI无法加载

时间:2023-01-27 13:23:05

I've been trying to learn java for a few weeks now, and I'm working on a pretty simple autoclicker. The clicker itself works, but my problem is that my GUI never shows up. The GUI runs just fine when I run the GUI file itself, but when I'm trying to run it from my main program (different file) it never shows. The clicker works fine all the time though. I'm sure the problem is something really simple that I have simply missed, but this is now my 4th day without any clue on what might be wrong with it, so decided I'd ask here.

我一直在努力学习java几周,而我正在研究一个非常简单的自动转换器。点击器本身可以工作,但我的问题是我的GUI永远不会出现。当我运行GUI文件本身时GUI运行得很好,但是当我试图从我的主程序(不同的文件)运行它时,它永远不会显示。点击器一直工作正常。我确定这个问题非常简单,我错过了,但现在这是我第四天没有任何关于它可能出错的线索,所以我决定在这里问。

Beware - the code is really messy atm, because I've been trying pretty much everything possible to get it working.

要小心 - 代码非常麻烦,因为我一直在努力尝试让它运行起来。

This is the code in the main program trying to run the GUI.

这是尝试运行GUI的主程序中的代码。

package autoclicker;

import java.awt.AWTException;

/**
 * The main program for the autoclicker.
 */
public class AutoClicker {
    public static void main(String[] args) throws AWTException {
        Click click = new Click(true);
        click.clicker();
        try {
            Swingerinos sw = new Swingerinos();
            sw.initialize();
        }
        catch (AWTException e) { e. printStackTrace(); System.exit(-1); }
    }
}

And this is the whole GUI file.

这是整个GUI文件。

package autoclicker;

import java.awt.*;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;


public class Swingerinos extends Click implements WindowListener,ActionListener {

    private int numClicks = 0;
    TextField text;

    private JFrame frame;
    /**
     * @wbp.nonvisual location=181,19
     */
    private final JLabel lblAutoclicker = new JLabel("AutoClicker");

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Swingerinos window = new Swingerinos();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public Swingerinos() throws AWTException {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    public void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 109);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        frame.getContentPane().add(panel, BorderLayout.WEST);

        JButton btnNewButton = new JButton("Toggle On / Off");
        text = new TextField(20);
        text.setLocation(100, 100);
        btnNewButton.addActionListener( this);
        btnNewButton.setToolTipText("Toggles the  autoclicker on / off.");
        panel.add(btnNewButton);
        panel.add(text);
        frame.setVisible(true);
    }

    public void actionPerformed(ActionEvent e) {
        toggle();
        numClicks++;
        text.setText(""+numClicks);
    }


    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }

    public void windowOpened(WindowEvent e) {}
    public void windowActivated(WindowEvent e) {}
    public void windowIconified(WindowEvent e) {}
    public void windowDeiconified(WindowEvent e) {}
    public void windowDeactivated(WindowEvent e) {}
    public void windowClosed(WindowEvent e) {}

}

I know the GUI file is really messy (there's 2x initialize(), one in the main program and one in the GUI file, and lots of other stuff, but I'm just too confused as for what to do now.

我知道GUI文件非常混乱(有2x initialize(),一个在主程序中,一个在GUI文件中,还有很多其他的东西,但是我对现在该做什么感到困惑。

EDIT: I added the whole main program code, also this is the code for the autoclicker.

编辑:我添加了整个主程序代码,这也是autoclicker的代码。

package autoclicker;

import java.awt.*;
import java.awt.event.InputEvent;

public class Click {
    private boolean active;
    private Robot robot;

    public Click(boolean active, Robot robot) {
        this.active = active;
        this.robot = robot;
    }

    public Click() throws AWTException {
        this(false, new Robot());
    }

    public Click(boolean active) throws AWTException {
        this(active, new Robot());
    }

    //TODO: add click.toggle() to somewhere and control da clicker
    public void toggle() {
        active = !active;
    }

    public void clicker() {
        while (active) {
            robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
            robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
            robot.setAutoDelay(10000);
        }
    }
}

1 个解决方案

#1


Expanding JB Nizet's comment(s) into an answer.

将JB Nizet的评论扩展为答案。

The immediate cause:

When the JVM calls your code, it is run on the main thread. It calls main(String[]), as you know. You posted two main methods, only one of which is relevant to your nothing-is-happening problem: AutoClick#main(String[]). Let's go through it:

当JVM调用您的代码时,它将在主线程上运行。如你所知,它调用main(String [])。您发布了两个主要方法,其中只有一个方法与您发生的无关紧要的问题相关:AutoClick#main(String [])。我们来看看吧:

Click click = new Click(true);
click.clicker();

This first of the above two lines obviously calls the constructor of Click, which sets the active variable to true. So far so good. The second line is much more interesting. It calls Click#clicker(). Let's look at that method:

上面两行中的第一行显然调用了Click的构造函数,它将活动变量设置为true。到现在为止还挺好。第二行更有趣。它调用Click#clicker()。我们来看看那个方法:

public void clicker() {
    while (active) {
        // <snip>
    }
}

This method is the problem. Since you haven't started any other threads, the main thread is the only one you have at that moment, the only thread on which you can execute code. When this loop is executed it only finishes when the active variable is set to false. As long as it is true, it will keep looping. This means that Click#clicker() only returns if active is set to false. But, you never do that in the loop itself, meaning you need a thread different from the thread executing the loop to change active. So, how many threads do we have? 1, the main thread. See the problem? Because the loop never ends, the main thread never reaches the statements in the main method after click.clicker().

这种方法就是问题所在。由于您还没有启动任何其他线程,因此主线程是您当时唯一拥有的线程,也是您可以执行代码的唯一线程。执行此循环时,仅在活动变量设置为false时才结束。只要它是真的,它将保持循环。这意味着Click#clicker()仅在active设置为false时返回。但是,你永远不会在循环本身中这样做,这意味着你需要一个与执行循环的线程不同的线程来改变活动。那么,我们有多少线程? 1,主线程。看到问题?因为循环永远不会结束,所以主线程在click.clicker()之后永远不会到达main方法中的语句。

Simple solution

You could just set a fixed number of iterations:

您可以设置固定数量的迭代:

public void clicker() {
    int i = 0;
    while (i < 100) { // iterate 100 times
        // <snip>
        ++i;
    }
}

Or using a for-loop (recommended):

或者使用for循环(推荐):

public void clicker() {
    for (int i = 0; i < 100; ++i) {
        // <snip>
    }
}

This eliminates the need for the active variable and hence the need for another thread.

这消除了对活动变量的需要,因此需要另一个线程。

A somewhat more complicated solution

If you really want the active variable, you'll need to have multiple threads. This is conveniently known as "multithreading"1, a very complicated topic. Luckily, we only need a bit of it, so it is only a bit complicated.

如果你真的想要活动变量,你需要有多个线程。这被称为“多线程”1,这是一个非常复杂的主题。幸运的是,我们只需要一点点,所以它只是有点复杂。

Don't just call the method Click#clicker() like you would normally. This creates your current problem. You'll need a worker thread, which can call the method. The easiest way to create a new thread is to call the constructor of the class Thread which takes a single argument of type Runnable. Like this:

不要像通常那样调用方法Click#clicker()。这会产生您当前的问题。你需要一个可以调用该方法的工作线程。创建新线程的最简单方法是调用类Thread的构造函数,该类采用Runnable类型的单个参数。像这样:

Thread worker = new Thread(new Runnable() {
    public void run() {
        click.clicker();
    }
});

This returns relatively quickly and leaves the Click#clicker() method running on another thread. Your main thread is now free to execute the other statements and even call click.toggle() after a while.

这会相对快速地返回并使Click#clicker()方法在另一个线程上运行。您的主线程现在可以*执行其他语句,甚至可以在一段时间后调用click.toggle()。

As JB Nizet pointed out, there are some other problems with your code. For example, Swingerinos shouldn't extend Click, but have an instance variable of type Click (http://en.wikipedia.org/wiki/Composition_over_inheritance) (as JB Nizet pointed out). Also, you shouldn't need to implement WindowListener to just call System.exit() when the window closes if you already call frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. To get all kinds of feedback (not limited to but including this kind of issues, style and design) on working code2 I highly recommend the StackExchange website codereview.stackexchange.com

正如JB Nizet指出的那样,您的代码还存在其他一些问题。例如,Swingerinos不应该扩展Click,而是具有Click类型的实例变量(http://en.wikipedia.org/wiki/Composition_over_inheritance)(正如JB Nizet指出的那样)。此外,如果已经调用了frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);则窗口关闭时,您不需要实现WindowListener来调用System.exit()。为了获得有关工作代码2的各种反馈(不仅限于此类问题,风格和设计),我强烈推荐StackExchange网站codereview.stackexchange.com

1: I by no means consider myself even remotely an expert on threading, so I won't go into it. If you want to know more about it, google it - there's lots of texts on multithreading - or ask another question - if you have a specific problem.
2: this is important: broken code is off-topic on Code Review.

1:我绝不认为自己甚至远程是线程专家,所以我不会进入它。如果您想了解更多信息,请谷歌 - 有很多关于多线程的文本 - 或者提出另一个问题 - 如果您有特定问题。 2:这很重要:破解代码在Code Review上是偏离主题的。

#1


Expanding JB Nizet's comment(s) into an answer.

将JB Nizet的评论扩展为答案。

The immediate cause:

When the JVM calls your code, it is run on the main thread. It calls main(String[]), as you know. You posted two main methods, only one of which is relevant to your nothing-is-happening problem: AutoClick#main(String[]). Let's go through it:

当JVM调用您的代码时,它将在主线程上运行。如你所知,它调用main(String [])。您发布了两个主要方法,其中只有一个方法与您发生的无关紧要的问题相关:AutoClick#main(String [])。我们来看看吧:

Click click = new Click(true);
click.clicker();

This first of the above two lines obviously calls the constructor of Click, which sets the active variable to true. So far so good. The second line is much more interesting. It calls Click#clicker(). Let's look at that method:

上面两行中的第一行显然调用了Click的构造函数,它将活动变量设置为true。到现在为止还挺好。第二行更有趣。它调用Click#clicker()。我们来看看那个方法:

public void clicker() {
    while (active) {
        // <snip>
    }
}

This method is the problem. Since you haven't started any other threads, the main thread is the only one you have at that moment, the only thread on which you can execute code. When this loop is executed it only finishes when the active variable is set to false. As long as it is true, it will keep looping. This means that Click#clicker() only returns if active is set to false. But, you never do that in the loop itself, meaning you need a thread different from the thread executing the loop to change active. So, how many threads do we have? 1, the main thread. See the problem? Because the loop never ends, the main thread never reaches the statements in the main method after click.clicker().

这种方法就是问题所在。由于您还没有启动任何其他线程,因此主线程是您当时唯一拥有的线程,也是您可以执行代码的唯一线程。执行此循环时,仅在活动变量设置为false时才结束。只要它是真的,它将保持循环。这意味着Click#clicker()仅在active设置为false时返回。但是,你永远不会在循环本身中这样做,这意味着你需要一个与执行循环的线程不同的线程来改变活动。那么,我们有多少线程? 1,主线程。看到问题?因为循环永远不会结束,所以主线程在click.clicker()之后永远不会到达main方法中的语句。

Simple solution

You could just set a fixed number of iterations:

您可以设置固定数量的迭代:

public void clicker() {
    int i = 0;
    while (i < 100) { // iterate 100 times
        // <snip>
        ++i;
    }
}

Or using a for-loop (recommended):

或者使用for循环(推荐):

public void clicker() {
    for (int i = 0; i < 100; ++i) {
        // <snip>
    }
}

This eliminates the need for the active variable and hence the need for another thread.

这消除了对活动变量的需要,因此需要另一个线程。

A somewhat more complicated solution

If you really want the active variable, you'll need to have multiple threads. This is conveniently known as "multithreading"1, a very complicated topic. Luckily, we only need a bit of it, so it is only a bit complicated.

如果你真的想要活动变量,你需要有多个线程。这被称为“多线程”1,这是一个非常复杂的主题。幸运的是,我们只需要一点点,所以它只是有点复杂。

Don't just call the method Click#clicker() like you would normally. This creates your current problem. You'll need a worker thread, which can call the method. The easiest way to create a new thread is to call the constructor of the class Thread which takes a single argument of type Runnable. Like this:

不要像通常那样调用方法Click#clicker()。这会产生您当前的问题。你需要一个可以调用该方法的工作线程。创建新线程的最简单方法是调用类Thread的构造函数,该类采用Runnable类型的单个参数。像这样:

Thread worker = new Thread(new Runnable() {
    public void run() {
        click.clicker();
    }
});

This returns relatively quickly and leaves the Click#clicker() method running on another thread. Your main thread is now free to execute the other statements and even call click.toggle() after a while.

这会相对快速地返回并使Click#clicker()方法在另一个线程上运行。您的主线程现在可以*执行其他语句,甚至可以在一段时间后调用click.toggle()。

As JB Nizet pointed out, there are some other problems with your code. For example, Swingerinos shouldn't extend Click, but have an instance variable of type Click (http://en.wikipedia.org/wiki/Composition_over_inheritance) (as JB Nizet pointed out). Also, you shouldn't need to implement WindowListener to just call System.exit() when the window closes if you already call frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. To get all kinds of feedback (not limited to but including this kind of issues, style and design) on working code2 I highly recommend the StackExchange website codereview.stackexchange.com

正如JB Nizet指出的那样,您的代码还存在其他一些问题。例如,Swingerinos不应该扩展Click,而是具有Click类型的实例变量(http://en.wikipedia.org/wiki/Composition_over_inheritance)(正如JB Nizet指出的那样)。此外,如果已经调用了frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);则窗口关闭时,您不需要实现WindowListener来调用System.exit()。为了获得有关工作代码2的各种反馈(不仅限于此类问题,风格和设计),我强烈推荐StackExchange网站codereview.stackexchange.com

1: I by no means consider myself even remotely an expert on threading, so I won't go into it. If you want to know more about it, google it - there's lots of texts on multithreading - or ask another question - if you have a specific problem.
2: this is important: broken code is off-topic on Code Review.

1:我绝不认为自己甚至远程是线程专家,所以我不会进入它。如果您想了解更多信息,请谷歌 - 有很多关于多线程的文本 - 或者提出另一个问题 - 如果您有特定问题。 2:这很重要:破解代码在Code Review上是偏离主题的。