0

Javaと2つのボタンでグラフィックインターフェイスを作成しました。

私の目的:

1)最初のボタンをクリックすると、さまざまなタスクが処理されるループが発生します(ボタン「開始」)。各ループの間に10秒の停止があります

2)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

4 に答える 4

2

UIスレッド内でループしたり、スリープするように指示したりしないでください。基本的に、UIスレッドは可能な限り自由に保つ必要があります。

UIスレッドのSwingUIで定期的に何かが発生する必要がある場合は、Swingタイマーを使用します。

ただし、「その他」で何をしているのかは不明です。別のスレッドでそれを完全AtomicBooleanに実行し、停止するタイミングを示すために(たとえば)を使用する必要がある可能性があります。

于 2012-08-21T17:37:34.480 に答える
2

米国型の信号機GUIを作成するのにどれくらい時間がかかるのだろうかと思いました。75分かかりました。Swingの多くは定型文であるため、GUIをすばやく作成できました。1つのGUIを作成したら、次のGUI用にいくつかのクラスをコピーできます。

これが信号機GUIの画像です。

信号機GUI

スタートボタンを押すと、信号機は緑から黄色、そして赤へと循環します。停止ボタンを押すまで、信号機は永久に循環します。

停止ボタンを押すと、信号機が赤くなります。スタートボタンを押すまで、それは永遠に赤のままになります。

信号機が循環しているときにスタートボタンを押すと、緑から黄色、赤へのサイクルが最初からやり直します。

基本的に、次の手順は、SwingGUIを作成する方法を示しています。この順序でコードを作成しませんでしたが、論理的な順序でコードを説明するのは理にかなっています。それでは、コードを掘り下げてみましょう。

これは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コンポーネントを拡張するのは、コンポーネントの1つ以上のメソッドをオーバーライドする場合のみです。実際のJFrameが必要な場合は、getFrame()メソッドを呼び出します。Swingコンポーネントを拡張するのではなく、Swingコンポーネントを使用すると、メソッドがSwingメソッドから分離されます。

次に、信号機のパネルを見てみましょう。このパネルは、信号機の3つのライトの1つを構成します。

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());
    }

}

このクラスは、paintComponentメソッドをオーバーライドするため、JPanelを拡張します。これは単純なクラスです。パネルを色または白でペイントするだけです。

次に、信号機パネルを見てみましょう。このパネルは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つのJPanelからの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を呼び出すことによって行うことです。

数ミリ秒でスレッドを停止できるようにするため、タイミングループは少し複雑です。isFinishedブール値は、スレッドが完全に停止することを保証し、ライトを設定できるようにします。

これはかなり長い答えですが、SwingGUIを作成する人の役に立つことを願っています。

于 2012-08-21T17:37:42.457 に答える
1

1. UI作業用のUIスレッドと、非UI作業用の非UIスレッドを常に保持する必要があります。

2. Java GUIでは、main()GUIの構築をに割り当てた後、は長続きしませんEvent Dispatcher Threadmain()終了し、EDTの責任でGUIを処理します。

3.したがって、ボタンをクリックすると、実行している作業が重いプロセスを実行するか、時間のかかる作業になりますSeparate thread

4.Threadまたはを使用できますSwingWorker

例:

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();
            }
        });
于 2012-08-21T17:42:14.450 に答える
0

簡単だが汚い方法:

プログラムをマルチスレッド化し、1つのスレッドでループを実行し、2番目のスレッドでボタンを監視します。ボタンでglobalStop変数を変更してもらいます

それほど簡単ではありませんが、よりクリーンな方法です。

ボタンに割り込みをスローさせて値を変更します。割り込み後、forループは最後まで続きます。

于 2012-08-21T17:38:09.987 に答える