Java 从控制器方法更新面板
我想从我的控制器更新主框架(类GUI)上的面板。基本上,每个模拟步骤都应该更新面板Java 从控制器方法更新面板,java,swing,jpanel,Java,Swing,Jpanel,我想从我的控制器更新主框架(类GUI)上的面板。基本上,每个模拟步骤都应该更新面板 for (int step = 0; step < simSteps; step++){ this.gui.updateGUI(this.stats, step); } 我的BarPanel类覆盖了paintComponent方法,在这里我只使用一个图形对象来绘制一些东西。 启动模拟时,面板仅在最后一个模拟步骤后更新,尽管我已经知道在每个模拟步骤中都会调用updateGU
for (int step = 0; step < simSteps; step++){
this.gui.updateGUI(this.stats, step);
}
我的BarPanel类覆盖了paintComponent方法,在这里我只使用一个图形对象来绘制一些东西。
启动模拟时,面板仅在最后一个模拟步骤后更新,尽管我已经知道在每个模拟步骤中都会调用updateGUI()方法(我做了一些调试输出)
有人知道为什么会这样吗 如果您非常快地更新GUI,您将看不到中间的更改,因此在循环中的每个步骤之间添加一些暂停,如:
new Thread() {
public void run() {
for (int step = 0; step < simSteps; step++){
this.gui.updateGUI(this.stats, step);
try {
Thread.currentThread().sleep(1000); // wait 1s before each step
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
public void updateGUI(final Stats stats, final int step){
// the declaration of stats in this class should be marked as volatile like:
// private volatile Stats;
this.stats = stats;
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
getContentPane().remove(pollutionPanel);
pollutionPanel = new BarPanel(settings, stats, possibleColors);
getContentPane().add(pollutionPanel);
validate();
repaint();
}
});
}
新线程(){
公开募捐{
对于(int step=0;step
还要记住,上面的循环不应该由
EventThread
运行,因此您不应该直接在ActionListener
中运行此代码(例如,在按下JButton
之后),而应该在ActionListener.actionPerformed()
创建新线程中运行此代码,该线程包含run()中的上述代码
方法,然后使用yourThread.start()启动此类线程。您也可以使用其他方式在单独的线程中运行它,但这是一个太宽泛的主题,不适合您的问题范围。如果您很快更新GUI,您看不到中间的更改,因此在循环中的每个步骤之间添加一些暂停,如:
new Thread() {
public void run() {
for (int step = 0; step < simSteps; step++){
this.gui.updateGUI(this.stats, step);
try {
Thread.currentThread().sleep(1000); // wait 1s before each step
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
public void updateGUI(final Stats stats, final int step){
// the declaration of stats in this class should be marked as volatile like:
// private volatile Stats;
this.stats = stats;
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
getContentPane().remove(pollutionPanel);
pollutionPanel = new BarPanel(settings, stats, possibleColors);
getContentPane().add(pollutionPanel);
validate();
repaint();
}
});
}
新线程(){
公开募捐{
对于(int step=0;step
还要记住,上面的循环不应该由EventThread
运行,因此您不应该直接在ActionListener
中运行此代码(例如,在按下JButton
之后),而应该在ActionListener.actionPerformed()
创建新线程中运行此代码,该线程包含run()中的上述代码
方法,然后使用yourThread.start()启动此类线程。您也可以使用其他方式在单独的线程中运行它,但这是一个太宽泛的主题,不适合您的问题范围。所以,基本概念是,您希望生成一些动画,用户界面会在一段时间内更新这些动画。这不是一个罕见的请求,有很多例子
要记住的事情:
- Swing是单线程的
- 不要做任何可能会阻止事件调度线程的事情,这将阻止用户界面被更新,直到控件被传递回它为止
- 不要从EDT上下文之外更新UI
好吧,这听起来有点矛盾,但是Swing提供了一些工具让你的生活更轻松
你可以
使用SwingWorker
您将根据问题的复杂程度使用哪种方法,SwingWorker
使用自己的Thread
调用doInBackground
,允许您处理耗时的任务,但提供安全更新UI的能力
定时器
在EDT上下文中触发其更新,使其保存以更新UI,但不执行中耗时的任务。因此,基本概念是,您希望生成一些动画,其中UI会在一段时间内更新。这不是一个罕见的请求,有很多例子
要记住的事情:
- Swing是单线程的
- 不要做任何可能会阻止事件调度线程的事情,这将阻止用户界面被更新,直到控件被传递回它为止
- 不要从EDT上下文之外更新UI
好吧,这听起来有点矛盾,但是Swing提供了一些工具让你的生活更轻松
你可以
使用SwingWorker
您将根据问题的复杂程度使用哪种方法,SwingWorker
使用自己的Thread
调用doInBackground
,允许您处理耗时的任务,但提供安全更新UI的能力
Timer
在EDT上下文中触发其更新,使其保存以从更新UI,但不执行耗时的任务。请提供一个可运行的示例,使用SwingWorker
或Swing计时器
在更新之间注入某种延迟欢迎来到这里。请以使用SwingWorker
或Swingimport java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface StepContainer {
public void addStep(int index);
}
public class TestPane extends JPanel implements StepContainer {
private int step = 0;
public TestPane() {
setLayout(new GridBagLayout());
PopulateWorker worker = new PopulateWorker(10, this);
worker.execute();
}
@Override
public void addStep(int step) {
JButton btn = new JButton(Integer.toString(step));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(btn, gbc);
revalidate();
repaint();
}
}
public class PopulateWorker extends SwingWorker<Void, Integer> {
private int steps;
private StepContainer parent;
public PopulateWorker(int steps, StepContainer parent) {
this.steps = steps;
this.parent = parent;
}
@Override
protected Void doInBackground() throws Exception {
Thread.sleep(1000);
for (int index = 0; index < steps; index++) {
publish(index);
Thread.sleep(1000);
}
return null;
}
@Override
protected void process(List<Integer> chunks) {
for (int step : chunks) {
parent.addStep(step);
}
}
}
}
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface StepContainer {
public void addStep(int index);
}
public class TestPane extends JPanel implements StepContainer {
private int step = 0;
public TestPane() {
setLayout(new GridBagLayout());
Timer timer = new Timer(1000, new PopulateAction(10, this));
timer.start();
}
@Override
public void addStep(int step) {
JButton btn = new JButton(Integer.toString(step));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(btn, gbc);
revalidate();
repaint();
}
}
public class PopulateAction implements ActionListener {
private int steps;
private StepContainer parent;
private int step;
public PopulateAction(int steps, StepContainer parent) {
this.steps = steps;
this.parent = parent;
}
@Override
public void actionPerformed(ActionEvent e) {
parent.addStep(step);
if (step == steps - 1) {
((Timer) e.getSource()).stop();
step = 0;
}
step++;
}
}
}