简体   繁体   English

Java-Swing GUI无法加载

[英]Java - Swing GUI doesn't load

I've been trying to learn java for a few weeks now, and I'm working on a pretty simple autoclicker. 我已经尝试学习Java几周了,并且正在开发一个非常简单的autoclicker。 The clicker itself works, but my problem is that my GUI never shows up. 答题器本身可以工作,但是我的问题是我的GUI无法显示。 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. 当我运行GUI文件本身时,GUI运行得很好,但是当我尝试从主程序(不同文件)运行它时,它永远不会显示。 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. 我确定问题确实很简单,我只是想念而已,但是现在已经是我第四天了,不知道它可能出什么问题了,所以决定在这里提出。

Beware - the code is really messy atm, because I've been trying pretty much everything possible to get it working. 当心-代码真的是凌乱的atm,因为我一直在尽一切可能使它工作。

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文件确实很乱(有2个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);
        }
    }
}

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. JVM调用您的代码时,它在主线程上运行。 It calls main(String[]) , as you know. 如您所知,它将调用main(String[]) You posted two main methods, only one of which is relevant to your nothing-is-happening problem: AutoClick#main(String[]) . 您发布了两种主要方法,其中只有一种与发生问题无关: AutoClick#main(String[]) Let's go through it: 让我们来看一下:

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 . 以上两行的第一行显然调用了Click的构造函数,该构造函数将active变量设置为true So far so good. 到现在为止还挺好。 The second line is much more interesting. 第二行更加有趣。 It calls Click#clicker() . 它调用Click#clicker() Let's look at that method: 让我们看一下该方法:

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 . 当执行此循环时,仅当active变量设置为false时,它才结束。 As long as it is true, it will keep looping. 只要它是正确的,它将保持循环。 This means that Click#clicker() only returns if active is set to false . 这意味着Click#clicker()仅在active设置为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 . 但是,您永远不会在循环本身中执行此操作,这意味着您需要一个与执行循环的线程不同的线程来更改active So, how many threads do we have? 那么,我们有多少个线程? 1, the main thread. 1,主线程。 See the problem? 看到问题了吗? Because the loop never ends, the main thread never reaches the statements in the main method after click.clicker() . 因为循环永远不会结束,所以主线程在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. 这消除了对active变量的需要,从而消除了对另一个线程的需要。

A somewhat more complicated solution 稍微复杂一点的解决方案

If you really want the active variable, you'll need to have multiple threads. 如果您确实需要active变量,则需要具有多个线程。 This is conveniently known as "multithreading" 1 , a very complicated topic. 这被方便地称为“多线程” 1 ,这是一个非常复杂的主题。 Luckily, we only need a bit of it, so it is only a bit complicated. 幸运的是,我们只需要一点它,所以它只是有点复杂。

Don't just call the method Click#clicker() like you would normally. 不要像通常那样仅调用Click#clicker()方法。 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. 创建新线程的最简单方法是调用Thread类的构造函数,该类采用一个Runnable类型的参数。 Like this: 像这样:

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. 这会相对快速地返回,并使Click#clicker()方法在另一个线程上运行。 Your main thread is now free to execute the other statements and even call click.toggle() after a while. 现在,您的主线程可以自由执行其他语句,甚至可以在一段时间后调用click.toggle()

As JB Nizet pointed out, there are some other problems with your code. 正如JB Nizet指出的那样,您的代码还有其他一些问题。 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). 例如,Swingerinos不应扩展Click,而应具有类型为Clickhttp://en.wikipedia.org/wiki/Composition_over_inheritance )的实例变量(如JB Nizet所指出的)。 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); 另外,如果您已经调用frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);则在关闭窗口时也不需要实现WindowListener来仅调用System.exit() 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 code 2 I highly recommend the StackExchange website codereview.stackexchange.com 为了获得有关工作代码 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. 1:我绝不认为自己是线程专家,因此我不会介绍它。 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. 如果您想了解更多有关它的信息,请在Google上搜索-关于多线程的很多文章-或提出另一个问题-如果您有特定问题。
2: this is important: broken code is off-topic on Code Review. 2:这很重要:损坏的代码不在“代码审查”上。

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

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