0

我对java很陌生,我刚开始编写这个愚蠢的小程序作为GUI测试。它应该做的是有12个按钮,将它们全部设置为白色,连续将3个随机按钮变为黑色,再次将所有按钮设置回白色,等待一秒钟然后重复。问题是,我似乎无法让它重复。每次我尝试在使随机按钮变黑的代码部分周围放置一段时间或 for 循环,它根本不会运行。它没有给出任何错误,并且进程本身确实运行,但没有出现任何窗口。这是该类的代码(减去 import 语句):

public class testingness extends JFrame {

JButton one, two, three, four, five, six, seven, eight, nine, ten, eleven,
        twelve;
JPanel panel;

testingness(String title) {

    super(title);
    this.init();
    this.setSize(800, 800);
    this.setLocationRelativeTo(null);
    this.setVisible(true);
}

void init() {
    panel = new JPanel();
    panel.setLayout(new GridLayout(3, 4));
    one = new JButton();
    one.setBackground(Color.white);
    two = new JButton();
    two.setBackground(Color.white);
    three = new JButton();
    three.setBackground(Color.white);
    four = new JButton();
    four.setBackground(Color.white);
    five = new JButton();
    five.setBackground(Color.white);
    six = new JButton();
    six.setBackground(Color.white);
    seven = new JButton();
    seven.setBackground(Color.white);
    eight = new JButton();
    eight.setBackground(Color.white);
    nine = new JButton();
    nine.setBackground(Color.white);
    ten = new JButton();
    ten.setBackground(Color.white);
    eleven = new JButton();
    eleven.setBackground(Color.white);
    twelve = new JButton();
    twelve.setBackground(Color.white);

    panel.add(one);
    panel.add(two);
    panel.add(three);
    panel.add(four);
    panel.add(five);
    panel.add(six);
    panel.add(seven);
    panel.add(eight);
    panel.add(nine);
    panel.add(ten);
    panel.add(eleven);
    panel.add(twelve);

    this.add(panel);
    while (true) {
        randomness();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

public void randomness() {

    for (int timesdone = 0; timesdone < 4; timesdone++) {
        panel.update(panel.getGraphics());
        Random r = new Random();
        int rand = r.nextInt(12);

        if (rand == 0) {
            one.setBackground(Color.black);
        } else if (rand == 1) {
            two.setBackground(Color.black);
        } else if (rand == 2) {
            three.setBackground(Color.black);
        } else if (rand == 3) {
            four.setBackground(Color.black);
        } else if (rand == 4) {
            five.setBackground(Color.black);
        } else if (rand == 5) {
            six.setBackground(Color.black);
        } else if (rand == 6) {
            seven.setBackground(Color.black);
        } else if (rand == 7) {
            eight.setBackground(Color.black);
        } else if (rand == 8) {
            nine.setBackground(Color.black);
        } else if (rand == 9) {
            ten.setBackground(Color.black);
        } else if (rand == 10) {
            eleven.setBackground(Color.black);
        } else if (rand == 11) {
            twelve.setBackground(Color.black);
        }
        one.setBackground(Color.white);
        two.setBackground(Color.white);
        three.setBackground(Color.white);
        four.setBackground(Color.white);
        five.setBackground(Color.white);
        six.setBackground(Color.white);
        seven.setBackground(Color.white);
        eight.setBackground(Color.white);
        nine.setBackground(Color.white);
        ten.setBackground(Color.white);
        eleven.setBackground(Color.white);
        twelve.setBackground(Color.white);

    }
  }

}

我在这里做错了什么?

4

4 回答 4

4

Swing 是一个单线程环境。要求对 UI 的所有交互和修改都在事件调度线程的上下文中执行。

除其他外,EDT 负责处理重绘请求和传入事件

任何阻止 EDT 的动作或操作都会阻止它处理这些事件和更新屏幕。

在您的代码中,您正在执行此操作...

while (true) {
    randomness();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

这可能会阻止 EDT,阻止它更新屏幕。

同样,你也在这样做......

for (int timesdone = 0; timesdone < 4; timesdone++) {
   /*...*/
}

这同样会阻止 EDT,阻止它更新屏幕......

此外,这panel.update(panel.getGraphics());是一个非常糟糕的主意。在 Swing 中,您无法控制绘制过程,这取决于RepaintManager. 您可以提出更新/重绘请求,但由RepaintManager他们决定何时何地。然后将这些请求发布到 EDT……如果被阻止,它将什么也不做。

getGraphics也可以返回null,这永远不漂亮...

为了解决您的问题,您需要将“等待”时间卸载到某种后台进程,该进程准备就绪后,需要告诉 UI 相应地更改其状态......

您可以使用 a Thread,但这意味着您将负责将所有调用重新同步回 EDT,这很麻烦,而且对开销几乎没有好处。

您可以使用 a SwingWorker,但它并不真正适合您手头的任务

更好的解决方案是使用 a javax.swing.Timer,它将actionPerformed在指定的延迟后重复触发事件,就像在 EDT 的上下文中执行的那样。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Flashy01 {

    public static void main(String[] args) {
        new Flashy01();
    }

    public Flashy01() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new FlashPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class FlashPane extends JPanel {

        private final BigButton one, two, three, four, five, six, seven, eight, nine, ten, eleven,
                twelve;
        private final JPanel panel;
        private final Random random;
        private int timesDone;

        public FlashPane() {
            panel = new JPanel();
            panel.setLayout(new GridLayout(3, 4));
            one = new BigButton();
            one.setBackground(Color.white);
            two = new BigButton();
            two.setBackground(Color.white);
            three = new BigButton();
            three.setBackground(Color.white);
            four = new BigButton();
            four.setBackground(Color.white);
            five = new BigButton();
            five.setBackground(Color.white);
            six = new BigButton();
            six.setBackground(Color.white);
            seven = new BigButton();
            seven.setBackground(Color.white);
            eight = new BigButton();
            eight.setBackground(Color.white);
            nine = new BigButton();
            nine.setBackground(Color.white);
            ten = new BigButton();
            ten.setBackground(Color.white);
            eleven = new BigButton();
            eleven.setBackground(Color.white);
            twelve = new BigButton();
            twelve.setBackground(Color.white);

            panel.add(one);
            panel.add(two);
            panel.add(three);
            panel.add(four);
            panel.add(five);
            panel.add(six);
            panel.add(seven);
            panel.add(eight);
            panel.add(nine);
            panel.add(ten);
            panel.add(eleven);
            panel.add(twelve);

            this.add(panel);
            random = new Random();

            Timer timer = new Timer(1000, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    randomness();
                }
            });
            timer.start();
        }

        public void randomness() {

            int rand = random.nextInt(12);
            timesDone++;

            if (timesDone % 5 != 0) {

                if (rand == 0) {
                    one.setBackground(Color.black);
                } else if (rand == 1) {
                    two.setBackground(Color.black);
                } else if (rand == 2) {
                    three.setBackground(Color.black);
                } else if (rand == 3) {
                    four.setBackground(Color.black);
                } else if (rand == 4) {
                    five.setBackground(Color.black);
                } else if (rand == 5) {
                    six.setBackground(Color.black);
                } else if (rand == 6) {
                    seven.setBackground(Color.black);
                } else if (rand == 7) {
                    eight.setBackground(Color.black);
                } else if (rand == 8) {
                    nine.setBackground(Color.black);
                } else if (rand == 9) {
                    ten.setBackground(Color.black);
                } else if (rand == 10) {
                    eleven.setBackground(Color.black);
                } else if (rand == 11) {
                    twelve.setBackground(Color.black);
                }

            } else {

                one.setBackground(Color.white);
                two.setBackground(Color.white);
                three.setBackground(Color.white);
                four.setBackground(Color.white);
                five.setBackground(Color.white);
                six.setBackground(Color.white);
                seven.setBackground(Color.white);
                eight.setBackground(Color.white);
                nine.setBackground(Color.white);
                ten.setBackground(Color.white);
                eleven.setBackground(Color.white);
                twelve.setBackground(Color.white);
            }
        }
    }

    public class BigButton extends JButton {

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(20, 20);
        }

    }
}

看一眼...

更多细节...

于 2013-08-19T01:10:25.337 回答
2

正如 Germann Arlington 指出的那样,GUI 线程永远不会被允许运行,因为您的构造函数永远不会返回。但是,在 GUI 线程(您需要更改 GUI 组件的属性)上定期执行某些操作的更好方法是使用计时器(http://docs.oracle.com/javase/7/docs /api/javax/swing/Timer.html)。例如:

int delay = 1000; //milliseconds
ActionListener taskPerformer = new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        randomness();
    }
};
new Timer(delay, taskPerformer).start();
于 2013-08-18T23:43:31.937 回答
2

在 randomness() 函数结束时,您将所有按钮设置为白色。您应该将它移到所有 if-else 之上,而不是在它之后。

于 2013-08-18T23:37:08.410 回答
0

主要问题是您的代码运行,但是因为它永远不会结束循环,所以您永远无法绘制组件 - 尝试在循环内的方法末尾调用 repaint() 方法。

另一点:如果您有多个按钮,您最好(以编程方式)仅将它们添加到容器并循环此容器内容。

于 2013-08-18T23:39:13.820 回答