ros*_*man 4 java graphics swing jpanel repaint
问题:在运行方法之前,图形不会重新绘制.
单击按钮时会调用两个方法.每个方法内部都是代码,用于更改与此方法关联的图形的颜色(在UI中); 当方法开始时,图形从黑色变为绿色; 当方法完成时,颜色从绿色变为红色.然后调用下一个方法,其图形应变为绿色(方法正在运行),当方法完成时,其图形应填充红色(方法完成).
我创建了一个简单的状态圆图形(带有填充颜色的30像素圆圈),有3种颜色状态:黑色表示准备好; 绿色的跑步; 红色完成.
我认为这个问题与repaint()单独的线程有关并且计划在能够运行时运行?我尝试将更新图形的代码放在自己的thread-runnable中,然后使用线程.join()确保代码已经完成运行但是没有用.
编辑:删除我用于演示的代码,并根据注释替换单个可运行的代码示例.如果运行代码,您将看到的是在单击每个方法启动和停止时图形不更新的按钮后,它会等待两个方法都运行然后重新绘制图形.
package graphicsUpdateDemo;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.beans.Transient;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
* Application entry
*/
public class App{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new MainFrame();
}
});
}
}
/**
* Main frame
*/
class MainFrame extends JFrame implements SomeListener{
private AddedPanel addedPanel;
// Constructor
public MainFrame(){
// Set frame properties
setSize(500, 500);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setLayout(new FlowLayout(FlowLayout.CENTER, 5, 20));
// Create AddedPanel.
addedPanel = new AddedPanel();
add(addedPanel);
// Set AddedPanel listener to this JFrame.
addedPanel.setSomeListener(this);
}
// AddedPanel listener method
@Override
public void doStuff() {
// run simulated sort methods
sort1();
sort2();
}
// Simulated sort
// .......graphic should turn green as soon as method starts
// .......graphic should turn red as soon as method finishes.
private void sort1() {
// repaint graphic to show method is starting
addedPanel.statusOne.setStatus(SortStatus.running);
// EDIT: Make panel repaint itself.
addedPanel.paintImmediately(0, 0, getWidth(), getHeight());
// Simulate work being done.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// repaint graphic to show methid is finished
addedPanel.statusOne.setStatus(SortStatus.finished);
// EDIT: Make panel repaint itself.
addedPanel.paintImmediately(0, 0, getWidth(), getHeight());
}
// Simulated sort
// .......graphic should turn green as soon as method starts
// .......graphic should turn red as soon as method finishes.
private void sort2() {
// repaint graphic to show method is starting (green)
addedPanel.statusTwo.setStatus(SortStatus.running);
// EDIT: Make panel repaint itself.
addedPanel.paintImmediately(0, 0, getWidth(), getHeight());
// Simulate work being done.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// repaint graphic to show method is finished.
addedPanel.statusTwo.setStatus(SortStatus.finished);
// EDIT: Make panel repaint itself.
addedPanel.paintImmediately(0, 0, getWidth(), getHeight());
}
}
/**
* Panel to add to MainFrame
*/
class AddedPanel extends JPanel{
// Button listener
SomeListener listener;
// Button
private JButton aButton = new JButton("Click Me");
// Create Status Circles for showing method state.
public StatusCircles statusOne = new StatusCircles();
public StatusCircles statusTwo = new StatusCircles();
// Constructor.
public AddedPanel(){
setLayout(new BorderLayout(0, 15));
// Add button to panel.
add(aButton, BorderLayout.NORTH);
// Make panel for holding graphics and labels.
JPanel resultsPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(5, 5, 5, 5);
resultsPanel.add(statusOne, c);
c.gridx = 1;
resultsPanel.add(new JLabel("Method A"), c);
c.gridx = 0; c.gridy = 1;
resultsPanel.add(statusTwo, c);
c.gridx = 1;
resultsPanel.add(new JLabel("Method B"), c);
add(resultsPanel, BorderLayout.CENTER);
aButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if(listener != null){
listener.doStuff();
}
}
});
}
public void setSomeListener(SomeListener listener){
this.listener = listener;
}
}
/**
* Graphic for showing user state of method:
* black for ready
* green for running
* red for finished
*/
class StatusCircles extends JPanel{
private SortStatus sortStatus;
private Ellipse2D.Double statusCircle = new Ellipse2D.Double(2, 2, 25, 25);
// Constructor
public StatusCircles(){
sortStatus = SortStatus.ready;
}
@Override
protected void paintComponent(Graphics g) {
// Cast Graphics to Graphics2D
Graphics2D g2 = (Graphics2D)g;
// Turn on anti aliasing
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Set background
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, getWidth(), getHeight());
// Fill status circle with color based on status field
switch(sortStatus){
case ready:
g2.setColor(Color.BLACK);
g2.fill(statusCircle);
break;
case running:
g2.setColor(Color.GREEN);
g2.fill(statusCircle);
break;
case finished:
g2.setColor(Color.RED);
g2.fill(statusCircle);
break;
}
}
@Override
@Transient
public Dimension getPreferredSize() {
return new Dimension(30, 30);
}
// Set state method is in.
public void setStatus(SortStatus status) {
this.sortStatus = status;
repaint();
}
}
/**
* Interface
*/
interface SomeListener{
public void doStuff();
}
/**
* Enum for depicting status of graphic.
*/
enum SortStatus {
ready,
running,
finished
}
Run Code Online (Sandbox Code Playgroud)
"重绘方法提出更新查看区域的请求并立即返回.它的效果是异步的,这意味着由JVM在单独的线程上执行paintComponent方法." - Liang的Java编程简介.
我认为问题是A)在我的无知中我的程序设计正在做一些没有理智的程序员会做的事情,和/或B)我不知道如何使程序改变图形颜色然后在那之后发生,然后继续做工作在什么线程上完成工作(EDT,主线程?).
我确实遇到了一个答案,建议永远不要放慢"主线程"来等待事情的绘制; 而是为每个状态圈制作图标然后交换图标 - 我想这会强制立即重绘任何持有图标的东西?不过,这不会表明有办法迫使立即重画吗?
思考实验:你有一个运行100次的循环,每次迭代需要一秒钟.您希望通过将圆的颜色更改为一百种不同颜色中的一种来向用户显示每次迭代.你需要为此制作100个不同的图标吗?或者,我想做的是每次迭代更改圆的填充颜色....但是如何在每次迭代时强制重新绘制圆圈?
不知道它是否是"正确"的解决方案,但程序现在可以按照我的意愿运行.我addedPanel.paintImmediately(0, 0, getWidth(), getHeight());在方法调用后直接放置这些,要求更改图形颜色.我更新了上面的工作示例代码,编辑由"//编辑:制作面板重绘本身"描述.
现在我更有信心我走在正确的轨道上.我相信我已经实施了推荐给我的东西.一旦我理解它基本上像Android一样asynTask()(了解我首先学习它的地方,这就是为什么我这样说),了解SwingWorker的速度非常快.通过睡眠模拟的工作发生在自己的线程中,在EDT之外,所以现在好了(?)((不是我需要我的程序小睡))现在,这是完整的工作代码:
package graphicsUpdateDemo;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.beans.Transient;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
/**
* Application entry
*/
public class App{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new MainFrame();
}
});
}
}
/**
* Main frame
*/
class MainFrame extends JFrame implements SomeListener{
private AddedPanel addedPanel;
// Constructor
public MainFrame(){
// Set frame properties
setSize(500, 500);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout(FlowLayout.CENTER, 5, 20));
// Create AddedPanel.
addedPanel = new AddedPanel();
add(addedPanel);
// Set AddedPanel listener to this JFrame.
addedPanel.setSomeListener(this);
// Call setVisible last
setVisible(true);
}
// AddedPanel listener method
@Override
public void doStuff() {
// Call sort1(), when that finishes have it call sort2().
sort1();
}
// Simulated sort
// .......graphic should turn green as soon as method starts
// .......graphic should turn red as soon as method finishes.
private void sort1() {
// repaint graphic to show method is starting
addedPanel.statusOne.setStatus(SortStatus.running);
// Run sort in its own thread.
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>(){
@Override
protected Void doInBackground() throws Exception {
// Simulate work being done.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void done() {
// repaint graphic to show methid is finished
addedPanel.statusOne.setStatus(SortStatus.finished);
// Call sort2
sort2();
}
};
worker.execute();
}
// Simulated sort
// .......graphic should turn green as soon as method starts
// .......graphic should turn red as soon as method finishes.
private void sort2() {
// repaint graphic to show method is starting (green)
addedPanel.statusTwo.setStatus(SortStatus.running);
// Run sort in its own thread
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>(){
@Override
protected Void doInBackground() throws Exception {
// Simulate work being done.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void done() {
// repaint graphic to show method is finished.
addedPanel.statusTwo.setStatus(SortStatus.finished);
}
};
worker.execute();
}
}
/**
* Panel to add to MainFrame
*/
class AddedPanel extends JPanel{
// Button listener
SomeListener listener;
// Button
private JButton aButton = new JButton("Click Me");
// Create Status Circles for showing method state.
public StatusCircles statusOne = new StatusCircles();
public StatusCircles statusTwo = new StatusCircles();
// Constructor.
public AddedPanel(){
setLayout(new BorderLayout(0, 15));
// Add button to panel.
add(aButton, BorderLayout.NORTH);
// Make panel for holding graphics and labels.
JPanel resultsPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(5, 5, 5, 5);
resultsPanel.add(statusOne, c);
c.gridx = 1;
resultsPanel.add(new JLabel("Method A"), c);
c.gridx = 0; c.gridy = 1;
resultsPanel.add(statusTwo, c);
c.gridx = 1;
resultsPanel.add(new JLabel("Method B"), c);
add(resultsPanel, BorderLayout.CENTER);
aButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if(listener != null){
listener.doStuff();
}
}
});
}
public void setSomeListener(SomeListener listener){
this.listener = listener;
}
}
/**
* Graphic for showing user state of method:
* black for ready
* green for running
* red for finished
*/
class StatusCircles extends JPanel{
private SortStatus sortStatus;
private Ellipse2D.Double statusCircle = new Ellipse2D.Double(2, 2, 25, 25);
// Constructor
public StatusCircles(){
sortStatus = SortStatus.ready;
}
@Override
protected void paintComponent(Graphics g) {
// Cast Graphics to Graphics2D
Graphics2D g2 = (Graphics2D)g;
// Turn on anti aliasing
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Set background
g2.setColor(Color.BLACK);
g2.fillRect(0, 0, getWidth(), getHeight());
// Fill status circle with color based on status field
switch(sortStatus){
case ready:
g2.setColor(Color.BLACK);
g2.fill(statusCircle);
break;
case running:
g2.setColor(Color.GREEN);
g2.fill(statusCircle);
break;
case finished:
g2.setColor(Color.RED);
g2.fill(statusCircle);
break;
}
}
@Override
@Transient
public Dimension getPreferredSize() {
return new Dimension(30, 30);
}
// Set state method is in.
public void setStatus(SortStatus status) {
this.sortStatus = status;
repaint();
}
}
/**
* Interface
*/
interface SomeListener{
public void doStuff();
}
/**
* Enum for depicting status of graphic.
*/
enum SortStatus {
ready,
running,
finished
}
Run Code Online (Sandbox Code Playgroud)
使用此处显示的方法,让每个排序从单独的更新显示SwingWorker,而Supervisor工作人员监视a CountDownLatch以确定何时完成所有排序.

附录:我以前从未见过 Applet ,也没有 SwingWorker...我不明白为什么我需要确定何时完成所有类型...我编辑了这个问题.
这个例子也是一个混合体.
SwingWorker有助于避免阻止EDT.
确定done告诉您何时(重新)启用开始按钮.
尝试添加PropertyChangeListener,显示这里,到一个ColorIcon,看到这里,你的标签.每次你setProgress()在工人中,你都会看到相应的PropertyChangeEvent.
| 归档时间: |
|
| 查看次数: |
1314 次 |
| 最近记录: |