使用图形界面(按钮)停止java中的循环

时间:2012-08-21 17:32:45

标签: java button loops graphical-interaction

我在java和2个按钮中创建了一个图形界面。

我的目标:

1)当我点击第一个按钮时,有一个循环,其中处理不同的任务(按钮“开始”)。在每个循环之间有一个10秒的停止

2)当我点击第二个按钮时,循环立即处理 ,但最后一次停止。 (我也想弹出一个突然显示它已被停止但这不是主要问题,我想我可以做到。)

我尝试了以下代码,但首先我认为它们是更简单的方法来解决我的问题。另外,我可以编译,但它不起作用,循环没有停止,窗口崩溃:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

    globalStop="Run";

    while (globalStop.equals("Run")) {

        System.out.println("GO");
        // Other stuff

        // For the break ? 
        try {
            Thread.sleep(10000);
          } catch (InterruptedException ex) {
               Logger.getLogger(main.class.getName()).log(Level.SEVERE, null, ex);
         }
    }
        System.out.println("done");
    }

}                                        

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
    globalStop = "Stop";
    System.out.println("Bouton2");
}      

我希望我很清楚,如果不是这样,请告诉我,我会改写。 提前感谢大家的帮助。

4 个答案:

答案 0 :(得分:2)

你不应该在 UI线程中循环,也不应该让它睡觉。从根本上说,你应该保持UI线程尽可能免费。

如果您需要在UI线程中的Swing UI中定期发生某些事情,use a Swing Timer

目前还不清楚你在“其他东西”中做了什么 - 你有可能完全在另一个线程中这样做,并使用(比方说)一个AtomicBoolean来表明你想要什么时候停止。

答案 1 :(得分:1)

我想知道创建美国式交通信号GUI需要多长时间。花了75分钟。我能够快速创建GUI,因为很多Swing都是样板文件。创建一个GUI后,您可以复制下一个GUI的一些类。

这是交通信号GUI的图像。

Traffic signal GUI

当您按下“开始”按钮时,交通信号将从绿色循环变为黄色变为红色。交通信号将永远循环,直到您按下停止按钮。

当您按下停止按钮时,交通信号将变为红色。它将永远保持红色,直到您按下“开始”按钮。

当交通信号循环时按下开始按钮,绿色到黄色到红色的循环重新开始。

基本上,以下步骤说明如何创建任何Swing GUI。我没有按此顺序创建代码,但以逻辑顺序解释代码是有意义的。所以,让我们深入研究代码。

这是GUI的模型类。每个GUI都需要拥有自己的模型,与应用程序的模型分开。对于此GUI,模型很简单。

package com.ggl.traffic.signal.model;

import java.awt.Dimension;

public class TrafficSignalModel {

    public static final int RED_LIGHT_TIME = 15;
    public static final int YELLOW_LIGHT_TIME = 5;
    public static final int GREEN_LIGHT_TIME = 10;

    public static final Dimension LIGHT_SIZE = new Dimension(32, 32);
}

我们在模型中设置信号灯时间,以及交通信号灯的大小。

对于更复杂的GUI,我们会跟踪模型中的字段值。

接下来,我们有交通信号GUI的主要类。

package com.ggl.traffic.signal;

import javax.swing.SwingUtilities;

import com.ggl.traffic.signal.view.TrafficSignalFrame;

public class TrafficSignal implements Runnable {

    @Override
    public void run() {
        new TrafficSignalFrame();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TrafficSignal());
    }

}

此类确保交通信号GUI位于Swing事件线程上。这就是所有这一课。您可以看到如何复制此类以启动任何GUI。

接下来,我们有GUI的Frame类。

package com.ggl.traffic.signal.view;

import java.awt.FlowLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

public class TrafficSignalFrame {

    protected ButtonPanel bPanel;

    protected JFrame frame;

    protected TrafficSignalPanel tsPanel;

    public TrafficSignalFrame() {
        createPartControl();
    }

    protected void createPartControl() {
        tsPanel = new TrafficSignalPanel();
        bPanel = new ButtonPanel();

        bPanel.setTrafficSignalPanel(tsPanel);

        frame = new JFrame();
        frame.setTitle("Traffic Signal");
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent event) {
                exitProcedure();
            }
        });


        frame.setLayout(new FlowLayout());
        frame.add(bPanel.getPanel());
        frame.add(tsPanel.getPanel());
        frame.pack();
//      frame.setBounds(100, 100, 400, 200);
        frame.setVisible(true);
    }

    public void exitProcedure() {
        frame.dispose();
        System.exit(0);
    }

    public JFrame getFrame() {
        return frame;
    }

}

除了构成GUI的特定JPanel之外,这个类是样板文件。如果您的JFrame有一个JMenu,那么这就是将JMenu附加到JFrame的地方。

请注意,我没有扩展JFrame来创建此类。扩展Swing组件的唯一时间是覆盖一个或多个组件的方法。如果我需要实际的JFrame,我会调用getFrame()方法。使用Swing组件而不是扩展Swing组件可以使我的方法与Swing方法分开。

接下来,我们将看一下交通信号灯面板。该面板构成交通信号灯中的3个灯之一。

package com.ggl.traffic.signal.view;

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JPanel;

public class TrafficSignalLightPanel extends JPanel {

    private static final long serialVersionUID = 1L;

    protected boolean lightOn;

    protected Color lightColor;
    protected Color darkColor;

    public TrafficSignalLightPanel(Color lightColor) {
        this.lightColor = lightColor;
        this.darkColor = Color.WHITE;
        this.lightOn = false;
    }

    public void setLightOn(boolean lightOn) {
        this.lightOn = lightOn;
        this.repaint();
    }

    @Override
    public void paintComponent(Graphics g) {
        if (lightOn) {
            g.setColor(lightColor);
        } else {
            g.setColor(darkColor);
        }
        g.fillRect(0, 0, getWidth(), getHeight());
    }

}

这个类扩展了JPanel,因为我们想要覆盖paintComponent方法。这是一个简单的课程。它所做的就是在面板上涂上一种颜色或白色。

接下来,我们将看一下交通信号面板。该面板创建3个光板,并将它们排列成垂直的一行。

package com.ggl.traffic.signal.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.border.Border;

import com.ggl.traffic.signal.model.TrafficSignalModel;

public class TrafficSignalPanel {

    protected JPanel panel;

    protected TrafficSignalLightPanel redLight;
    protected TrafficSignalLightPanel yellowLight;
    protected TrafficSignalLightPanel greenLight;

    public TrafficSignalPanel() {
        createPartControl();
    }

    protected void createPartControl() {
        Border border = BorderFactory.createLineBorder(Color.BLACK, 4);

        redLight = new TrafficSignalLightPanel(Color.RED);
        redLight.setBorder(border);
        redLight.setPreferredSize(TrafficSignalModel.LIGHT_SIZE);

        yellowLight = new TrafficSignalLightPanel(Color.YELLOW);
        yellowLight.setBorder(border);
        yellowLight.setPreferredSize(TrafficSignalModel.LIGHT_SIZE);

        greenLight = new TrafficSignalLightPanel(Color.GREEN);
        greenLight.setBorder(border);
        greenLight.setPreferredSize(TrafficSignalModel.LIGHT_SIZE);

        panel = new JPanel();
        panel.setLayout(new FlowLayout());
        panel.setPreferredSize(
                new Dimension(TrafficSignalModel.LIGHT_SIZE.width + 10, 
                        TrafficSignalModel.LIGHT_SIZE.height * 3 + 25));

        panel.add(redLight);
        panel.add(yellowLight);
        panel.add(greenLight);
    }

    public JPanel getPanel() {
        return panel;
    }

    public TrafficSignalLightPanel getRedLight() {
        return redLight;
    }

    public TrafficSignalLightPanel getYellowLight() {
        return yellowLight;
    }

    public TrafficSignalLightPanel getGreenLight() {
        return greenLight;
    }

}

从3个JPanels中相当简单地创建JPanel。我设置了JPanel的首选大小,因此灯光将垂直排列。

接下来,我们将看一下按钮面板。您几乎可以将此代码复制到任何具有按钮面板的GUI中。

package com.ggl.traffic.signal.view;

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

import javax.swing.JButton;
import javax.swing.JPanel;

import com.ggl.traffic.signal.thread.TrafficSignalCycle;

public class ButtonPanel {

    protected JButton startButton;
    protected JButton stopButton;

    protected JPanel panel;

    protected TrafficSignalCycle thread;

    protected TrafficSignalPanel tsPanel;

    public ButtonPanel() {
        this.thread = null;
        createPartControl();
    }

    protected void createPartControl() {
        panel = new JPanel();
        panel.setLayout(new FlowLayout());

        startButton = new JButton("Start");
        startButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if (thread != null) {
                    thread.stopRunning();
                }
                tsPanel.getRedLight().setLightOn(false);
                tsPanel.getYellowLight().setLightOn(false);
                tsPanel.getGreenLight().setLightOn(false);
                thread = new TrafficSignalCycle(tsPanel);
                thread.start();
            }
        });

        panel.add(startButton);

        stopButton = new JButton("Stop");
        stopButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                if (thread != null) {
                    thread.stopRunning();
                    thread = null;
                }
                tsPanel.getRedLight().setLightOn(true);
                tsPanel.getYellowLight().setLightOn(false);
                tsPanel.getGreenLight().setLightOn(false);
            }
        });

        panel.add(stopButton);

        setButtonSizes(startButton, stopButton);
    }

    protected void setButtonSizes(JButton ... buttons) {
        Dimension preferredSize = new Dimension();
        for (JButton button : buttons) {
            Dimension d = button.getPreferredSize();
            preferredSize = setLarger(preferredSize, d);
        }
        for (JButton button : buttons) {
            button.setPreferredSize(preferredSize);
        }
    }

    protected Dimension setLarger(Dimension a, Dimension b) {
        Dimension d = new Dimension();
        d.height = Math.max(a.height, b.height);
        d.width = Math.max(a.width, b.width);
        return d;
    }

    public void setTrafficSignalPanel(TrafficSignalPanel tsPanel) {
        this.tsPanel = tsPanel;
    }

    public JPanel getPanel() {
        return panel;
    }

}

按钮操作非常简单,我可以将它们保留在按钮面板中。如果需要,您可以编写单独的操作类。

最后,这是运行红绿灯周期的代码。它是Thread类的扩展,因此它可以在GUI的单独线程中运行。在与GUI线程分开的线程中进行工作总是一个好主意。

package com.ggl.traffic.signal.thread;

import javax.swing.SwingUtilities;

import com.ggl.traffic.signal.model.TrafficSignalModel;
import com.ggl.traffic.signal.view.TrafficSignalLightPanel;
import com.ggl.traffic.signal.view.TrafficSignalPanel;

public class TrafficSignalCycle extends Thread {

    protected boolean isRunning;
    protected boolean isFinished;

    protected TrafficSignalPanel tsPanel;

    public TrafficSignalCycle(TrafficSignalPanel tsPanel) {
        this.tsPanel = tsPanel;
        this.isRunning = true;
        this.isFinished = false;
    }

    @Override
    public void run() {
        while (isRunning) {
            signalLightOn(tsPanel.getGreenLight(), TrafficSignalModel.GREEN_LIGHT_TIME);
            signalLightOn(tsPanel.getYellowLight(), TrafficSignalModel.YELLOW_LIGHT_TIME);
            signalLightOn(tsPanel.getRedLight(), TrafficSignalModel.RED_LIGHT_TIME);
        }
        this.isFinished = true;
    }

    protected void signalLightOn(TrafficSignalLightPanel light, int seconds) {
        if (isRunning) {
            setLightOn(light, true);
        }

        for (int i = 0; i < 1000 && isRunning; i++) {
            try {
                Thread.sleep(1L * seconds);
            } catch (InterruptedException e) {
            }
        }
        setLightOn(light, false);
    }

    protected void setLightOn(final TrafficSignalLightPanel light,
            final boolean isLightOn) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                light.setLightOn(isLightOn);

            }       
        });
    }

    public void stopRunning() {
        this.isRunning = false;
        while (!isFinished) {
            try {
                Thread.sleep(10L);
            } catch (InterruptedException e) {
            }
        }
    }

}

实际更改信号灯颜色的方法必须在Swing事件线程中执行。这就是setLightOn方法通过调用SwingUtilities来做的事情。

时序循环有点复杂,因为我们希望能够在几毫秒内停止线程。

这是一个相当长的答案,但我希望它对任何创建Swing GUI的人都有帮助。

答案 2 :(得分:1)

1。您应该始终保持用于UI工作的 UI线程和用于非UI工作的非UI线程

2. 在Java GUI中,main()在为Event Dispatcher Threadmain()退出并分配GUI的构造后,并不是长期存在的,现在它的EDT负责处理GUI。

3。因此,当您点击按钮时,您正在做的工作正在进行一些繁重的过程或耗费时间......然后跨越Separate thread

4. 您可以使用ThreadSwingWorker

示例:

Button b = new Button("Click me");

b.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {

                              Thread t = new Thread(new Runnable(){


                                     public void run(){


                                           // Do the Heavy Processing work.....

                                       }

                                });

                t.start();
            }
        });

答案 3 :(得分:0)

简单而又肮脏的方式:

多线程程序,让一个线程执行循环,第二个线程监视按钮。让按钮改变你的globalStop变量

不那么容易但更干净的方式:

使按钮抛出中断以更改值。中断后,for循环将继续结束。