Java Swing-使用线程

Java Swing-使用线程,java,multithreading,swing,Java,Multithreading,Swing,我制作了一个简单的点击测试应用程序(你可能在网上看到过一些,你有一个大按钮。一旦你点击它,10秒计时器就会启动,目标是点击按钮的次数最多)。我认为这是一个练习SwingAPI和基本线程的好方法。这只是一些基本的东西,我知道我可以使用API作为计时器之类的东西,但现在让我们保持简单 问题似乎是我无法在setTime()方法中修改JLabel,该方法是从计时器类中的线程调用的 这是主类类: package com.tremblayalex.clicktest; import java.awt.Bo

我制作了一个简单的点击测试应用程序(你可能在网上看到过一些,你有一个大按钮。一旦你点击它,10秒计时器就会启动,目标是点击按钮的次数最多)。我认为这是一个练习
Swing
API
和基本
线程
的好方法。这只是一些基本的东西,我知道我可以使用
API
作为计时器之类的东西,但现在让我们保持简单

问题似乎是我无法在
setTime()
方法中修改
JLabel
,该方法是从
计时器
中的
线程
调用的

这是
主类

package com.tremblayalex.clicktest;

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

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Main extends JFrame
{
    private static final long serialVersionUID = 1L;

    // Initialize Variables
    private final JPanel contentPane = new JPanel();
    private JLabel topText = new JLabel();
    private JButton btnClick = new JButton();
    private int clicks = 0;
    private boolean isStarted = false;

    public static void main(String[] args) 
    {
        Main m = new Main();
        m.setVisible(true);
    }

    public Main()
    {
        if (!isStarted)
        {
            initComponents();
            registerEvents();
        }
    }

    ///////////////////////////////////////////////////////////////////////////////
    // Initialize Components
    ///////////////////////////////////////////////////////////////////////////////
    private void initComponents() 
    {
        // JFrame Settings
        setTitle("Input Box");
        setSize(1000, 400);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        add(contentPane);

        // Content Pane (BorderLayout)
        contentPane.setLayout(new BorderLayout());
        contentPane.add(topText, BorderLayout.NORTH);
        contentPane.add(btnClick, BorderLayout.CENTER);

        // Top Text
        topText.setFont(new Font("Arial", Font.PLAIN, 16));
        topText.setText("Click to Start");

        // Button Click
        btnClick.setFont(new Font("Arial", Font.BOLD, 18));
        btnClick.setText("CLICK TO START");

    }


    ///////////////////////////////////////////////////////////////////////////////
    // Register Events
    ///////////////////////////////////////////////////////////////////////////////
    private void registerEvents() 
    {
        btnClick.addActionListener(new ActionListener() 
        { 
            public void actionPerformed(ActionEvent e) 
            {
                if (isStarted == false)
                {
                    isStarted = true;
                    new Thread(new Timer()).start();
                }

                clicks++;
                btnClick.setText("[Clicks] " + clicks);

            }
        });

    }




    ///////////////////////////////////////////////////////////////////////////////
    // Getters and Setters
    ///////////////////////////////////////////////////////////////////////////////

    public void setTime(double time)
    {
        System.out.println(time);
        topText.setText("Time: " + time);

        if (time >= 10)
        {
            if (clicks < 50)
            {
                topText.setText("Your average CPS is " + (clicks / 10) + "." + " Try to do better next time!");
            } else if (clicks >= 50 || clicks < 100){
                topText.setText("Your average CPS is " + (clicks / 10) + "." + " You are in the average!");
            } else if (clicks >= 100 || clicks < 150){
                topText.setText("Your average CPS is " + (clicks / 10) + "." + " You click very fast!");
            } else if (clicks >= 150 || clicks < 250){
                topText.setText("Your average CPS is " + (clicks / 10) + "." + " Clicking is your destiny!");
            } else if (clicks >= 250){
                topText.setText("Your average CPS is " + (clicks / 10) + "." + " Hack? :D");
            } else {
                topText.setText("Your average CPS is " + (clicks / 10) + "." + " Internal Error.");
            }

            isStarted = false;

            btnClick.setText("CLICK TO RESTART");
        }
    }


}
package com.tremblayalex.clicktest;

public class Timer implements Runnable
{   
    private final Main main = new Main();

    public void run()
    {
        for (double time = 0; time <= 10; time += 0.1)
        {
            main.setTime(time);

            try {
                Thread.sleep(100);
            } catch (InterruptedException e)
            {}
        }
    }
}
编辑:

感谢您的帮助,我使用
定时器制作了一个新版本:

package com.tremblayalex.clicktest;

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

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Main extends JFrame
{
    private static final long serialVersionUID = 1L;

    // Initialize Variables
    private final JPanel contentPane = new JPanel();
    private JLabel topText = new JLabel();
    private JButton btnClick = new JButton();
    private JButton btnRestart = new JButton();
    private double clicks = 0;
    private double time;
    private boolean isStarted = false;


    private Timer timer = new Timer(100, new ActionListener() 
    {
        @Override
        public void actionPerformed(ActionEvent paramActionEvent) 
        {
            if (time < 100)
            {
                time++;
                topText.setText("Time: " + (time / 10));    
            } 
            else {

                if (clicks < 50)
                {
                    topText.setText("Your average CPS is " + (clicks / 10) + "  Try to do better next time!");
                } else if (clicks >= 50 && clicks < 100){
                    topText.setText("Your average CPS is " + (clicks / 10) + "  You are in the average!");
                } else if (clicks >= 100 && clicks < 150){
                    topText.setText("Your average CPS is " + (clicks / 10) + "  You click very fast!");
                } else if (clicks >= 150 && clicks < 250){
                    topText.setText("Your average CPS is " + (clicks / 10) + "  Clicking is your destiny!");
                } else if (clicks >= 250){
                    topText.setText("Your average CPS is " + (clicks / 10) + "  Hack? :D");
                } else {
                    topText.setText("Your average CPS is " + (clicks / 10) + "  Internal Error.");
                }

                timer.stop();

                isStarted = false;
                btnClick.setEnabled(false);
                btnRestart.setEnabled(true);
            }
        }
    });


    public static void main(String[] args) 
    {
        Main m = new Main();
        m.setVisible(true);
    }

    public Main()
    {
        initComponents();
        registerEvents();
    }

    ///////////////////////////////////////////////////////////////////////////////
    // Initialize Components
    ///////////////////////////////////////////////////////////////////////////////
    private void initComponents() 
    {
        // JFrame Settings
        setTitle("Click Test");
        setSize(1000, 400);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        add(contentPane);

        // Content Pane (BorderLayout)
        contentPane.setLayout(new BorderLayout());
        contentPane.add(topText, BorderLayout.NORTH);
        contentPane.add(btnClick, BorderLayout.CENTER);
        contentPane.add(btnRestart, BorderLayout.SOUTH);

        // Top Text
        topText.setFont(new Font("Arial", Font.PLAIN, 16));
        topText.setText("Click to Start");

        // Button Click
        btnClick.setFont(new Font("Arial", Font.BOLD, 18));
        btnClick.setText("CLICK TO START");

        // Button Restart
        btnRestart.setFont(new Font("Arial", Font.PLAIN, 15));
        btnRestart.setText("Restart");
        btnRestart.setEnabled(false);

    }


    ///////////////////////////////////////////////////////////////////////////////
    // Register Events
    ///////////////////////////////////////////////////////////////////////////////
    private void registerEvents() 
    {
        btnClick.addActionListener(new ActionListener() 
        { 
            public void actionPerformed(ActionEvent e) 
            {
                if (isStarted == false)
                {
                    isStarted = true;
                    clicks = 0;
                    time = 0;
                    topText.setText("Time: " + time);

                    timer.start();
                }



                clicks++;
                btnClick.setText("[Clicks] " + (int)clicks);

            }
        });


        btnRestart.addActionListener(new ActionListener() 
        { 
            public void actionPerformed(ActionEvent e) 
            {

                btnClick.setEnabled(true);
                btnClick.setText("CLICK TO RESTART");
                btnRestart.setEnabled(false);

            }
        });

    }


}
package com.tremblayalex.clicktest;
导入java.awt.BorderLayout;
导入java.awt.Font;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
导入javax.swing.Timer;
公共类主框架
{
私有静态最终长serialVersionUID=1L;
//初始化变量
private final JPanel contentPane=new JPanel();
private JLabel topText=new JLabel();
private JButton btnClick=new JButton();
private JButton btnRestart=new JButton();
私人双击=0;
私人双倍时间;
私有布尔值isStarted=false;
私有计时器=新计时器(100,新ActionListener()
{
@凌驾
已执行的公共无效操作(ActionEvent paramActionEvent)
{
如果(时间<100)
{
时间++;
setText(“时间:”+(Time/10));
} 
否则{
如果(单击次数<50次)
{
setText(“您的平均CPS是”+(点击/10)+“下次尝试做得更好!”);
}否则如果(单击次数>=50次和单击次数<100次(&C){
setText(“你的平均点击次数是”+(点击次数/10)+“你处于平均水平!”);
}否则,如果(单击次数>=100&&clicks<150){
setText(“你的平均点击次数是”+(点击/10)+“你点击得很快!”);
}否则,如果(单击次数>=150和单击次数<250){
setText(“你的平均点击次数是”+(点击/10)+“点击就是你的命运!”);
}否则如果(单击次数>=250){
setText(“您的平均CPS为“+(点击/10)+”黑客?:D”);
}否则{
setText(“您的平均CPS为“+(点击/10)+“内部错误”);
}
timer.stop();
isStarted=false;
b单击.setEnabled(false);
btnRestart.setEnabled(true);
}
}
});
公共静态void main(字符串[]args)
{
Main m=新的Main();
m、 setVisible(真);
}
公用干管()
{
初始化组件();
registerEvents();
}
///////////////////////////////////////////////////////////////////////////////
//初始化组件
///////////////////////////////////////////////////////////////////////////////
私有组件()
{
//JFrame设置
设置标题(“点击测试”);
设置大小(1000400);
可设置大小(假);
setDefaultCloseOperation(关闭时退出);
setLocationRelativeTo(空);
添加(内容窗格);
//内容窗格(边框布局)
setLayout(新的BorderLayout());
添加(topText,BorderLayout.NORTH);
添加(b单击,BorderLayout.CENTER);
添加(btnRestart,BorderLayout.SOUTH);
//顶部文本
setFont(新字体(“Arial”,Font.PLAIN,16));
setText(“单击开始”);
//按钮点击
btnClick.setFont(新字体(“Arial”,Font.BOLD,18));
btnClick.setText(“单击开始”);
//按钮重启
setFont(新字体(“Arial”,Font.PLAIN,15));
btnRestart.setText(“重启”);
btnRestart.setEnabled(false);
}
///////////////////////////////////////////////////////////////////////////////
//注册事件
///////////////////////////////////////////////////////////////////////////////
私有无效注册表事件()
{
btnClick.addActionListener(新建ActionListener()
{ 
已执行的公共无效操作(操作事件e)
{
如果(isStarted==false)
{
IsStart=true;
点击次数=0;
时间=0;
setText(“时间:+Time”);
timer.start();
}
点击++;
btnClick.setText(“[单击]”+(int)单击);
}
});
btnRestart.addActionListener(新的ActionListener()
{ 
已执行的公共无效操作(操作事件e)
{
btnClick.setEnabled(true);
btnClick.setText(“单击以重新启动”);
btnRestart.setEnabled(false);
}
});
}
}

此处不需要直接使用线程,只需使用一个线程即可。它更干净、更安全。基本上,尤其是作为新手,永远不要调用Thread.sleep()或Thread.yield()。尤其是在使用和时千万不要睡觉。@markspace:不,这里绝对不是
java.util.Timer
,因为这是一个Swing应用程序。实用程序计时器几乎肯定会导致间歇性线程异常。如果结果不需要在EDT上运行,java.util.Timer将正常工作。如果他打算做其他事情,比如测试一个文件,那没关系。