动态更改自定义图形的颜色 [英] dynamically change color of custom graphic

查看:195
本文介绍了动态更改自定义图形的颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:直到方法运行后才会重新绘制图形。



当点击按钮时,会调用两个方法。在每种方法中,代码应该改变与此方法相关联的图形的颜色(在UI中);当该方法启动时,图形从黑色变为绿色;当该方法完成时,颜色从绿色变为红色。然后调用下一个方法,它的图形应该变为绿色(方法正在运行),并且当方法结束时,它的图形应该用红色填充(方法已完成)。

I用3种颜色状态创建了一个简单的状态圆图形(带填充颜色的30像素圆圈):黑色表示准备就绪;绿色跑步;红色完成。



我认为这个问题与 repaint()存在于一个单独的线程中有关,并且计划在能够运行时运行?我尝试将更新图形的代码放入自己的线程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;
导入javax.swing.SwingUtilities;
$ b $ **
应用程序入口
* /
公共类应用程序{
public static void main(String [] args){
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
new MainFrame();
}
});


$ b / **
*主框架
* /
类MainFrame扩展了JFrame implements SomeListener {
private AddedPanel addedPanel;

//构造函数
public MainFrame(){
//设置框架属性
setSize(500,500);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
setLayout(new FlowLayout(FlowLayout.CENTER,5,20));

//创建AddedPanel。
addedPanel = new AddedPanel();
add(addedPanel);

//将AddedPanel监听器设置为此JFrame。
addedPanel.setSomeListener(this);
}

// AddedPanel侦听器方法
@Override
public void doStuff(){
//运行模拟排序方法
sort1 );
sort2();
}

//模拟排序
// .......一旦方法启动,图形应该变为绿色
// .....方法结束后,图形应该变为红色。
private void sort1(){
// repaint graphic to show method is starting
addedPanel.statusOne.setStatus(SortStatus.running);

//编辑:使面板重绘本身。
addedPanel.paintImmediately(0,0,getWidth(),getHeight());

//模拟正在完成的工作。
尝试{
Thread.sleep(2000);
} catch(InterruptedException e){
e.printStackTrace();
}

//重绘图形以显示方法已完成
addedPanel.statusOne.setStatus(SortStatus.finished);
//编辑:使面板重绘本身。
addedPanel.paintImmediately(0,0,getWidth(),getHeight());
}

//模拟排序
// .......一旦方法启动,图形应该变为绿色
// .....方法结束后,图形应该变为红色。
private void sort2(){
//重绘图形以显示方法开始(绿色)
addedPanel.statusTwo.setStatus(SortStatus.running);
//编辑:使面板重绘本身。
addedPanel.paintImmediately(0,0,getWidth(),getHeight());

//模拟正在完成的工作。
尝试{
Thread.sleep(2000);
} catch(InterruptedException e){
e.printStackTrace();
}

//重绘图形以显示方法完成。
addedPanel.statusTwo.setStatus(SortStatus.finished);
//编辑:使面板重绘本身。
addedPanel.paintImmediately(0,0,getWidth(),getHeight());
}
}

/ **
*添加到MainFrame的面板
* /
class AddedPanel扩展JPanel {
// Button监听器
SomeListener监听器;
// Button
private JButton aButton = new JButton(Click Me);

//创建状态显示方法状态的圆圈。
public StatusCircles statusOne = new StatusCircles();
public StatusCircles statusTwo = new StatusCircles();

//构造函数。
public AddedPanel(){
setLayout(new BorderLayout(0,15));

//将按钮添加到面板。
add(aButton,BorderLayout.NORTH);

//使面板保持图形和标签。
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;


$ b $ **
*用于显示方法用户状态的图形:
* black准备就绪
* green用于运行
*红色表示完成
* /
class StatusCircles扩展JPanel {
private SortStatus sortStatus;
private Ellipse2D.Double statusCircle = new Ellipse2D.Double(2,2,25,25);

//构造函数
public StatusCircles(){
sortStatus = SortStatus.ready;

$ b @Override
protected void paintComponent(Graphics g){
//将图形转换为Graphics2D
Graphics2D g2 =(Graphics2D)g;

//打开反锯齿
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

//设置背景
g2.setColor(Color.BLACK);
g2.fillRect(0,0,getWidth(),getHeight());

//使用基于状态字段的颜色填充状态圆
switch(sortStatus){
已准备就绪:
g2.setColor(Color.BLACK);
g2.fill(statusCircle);
休息;
case running:
g2.setColor(Color.GREEN);
g2.fill(statusCircle);
休息;
案例完成:
g2.setColor(Color.RED);
g2.fill(statusCircle);
休息;
}
}

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

//设置状态方法在。
public void setStatus(SortStatus status){
this.sortStatus = status;
repaint();


$ b / **
*接口
* /
接口SomeListener {
public void doStuff();
}

/ **
*用于描述图形状态的枚举。
* /
enum SortStatus {
ready,
running,
finished
}
$ b $ h $
$ b $ p
$ b

repaint方法提出更新查看区域并立即返回的请求,其效果是异步的,这意味着由JVM在单独的线程上执行paintComponent方法。 - 由Liang介绍Java编程。



我认为问题在于:A)在我的无知中,我的程序设计正在做一些不合理的程序员会做的事情,和/或B )我不知道如何让程序改变图形颜色,然后发生,然后继续在任何正在完成的工作线程上工作(EDT,主线程?)。

我遇到了一个答案,建议不要放慢主线程等待绘制的东西;并改为为每个状态圈设置图标,然后交换图标 - 我想这会强制立即重绘任何图标?但是,这不会,这表明有办法强制立即重绘吗?



思想实验:您有一个循环运行100次,每次迭代需要一秒钟。您想通过将圆圈的颜色更改为上百种不同颜色之一来向用户显示每次迭代。你需要为此制作100个不同的图标吗?或者,我想要做的是每次迭代改变圆圈的填充颜色。 ...但是如何在每次迭代时强制重新绘制圆圈?



编辑



不知道它是否是正确的解决方案,但程序现在按照我的需要运行。我在方法调用后直接调用了这些 addedPanel.paintImmediately(0,0,getWidth(),getHeight()); ,要求改变图形颜色。我更新了上面的工作示例代码,编辑内容由//编辑:使面板重新绘制本身描述。



编辑



现在我更有信心,我正走在正确的轨道上。我相信我已经实施了推荐给我的东西。理解SwingWorker的速度非常快,一旦我明白它基本上就像Android的 asynTask()(这是我首先学习它的地方,这就是为什么我这样说)。通过睡眠模拟工作发生在自己的线程中,离开美国东部时间,现在好了(?)((不是我需要我的程序小睡一下))现在,这是完整的工作代码:

  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;
导入javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
$ b $ **
应用程序入口
* /
公共类应用程序{
public static void main(String [] args){
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
new MainFrame();
}
});


$ b / **
*主框架
* /
类MainFrame扩展了JFrame implements SomeListener {
private AddedPanel addedPanel;

//构造函数
public MainFrame(){
//设置框架属性
setSize(500,500);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

setLayout(new FlowLayout(FlowLayout.CENTER,5,20));

//创建AddedPanel。
addedPanel = new AddedPanel();
add(addedPanel);

//将AddedPanel监听器设置为此JFrame。
addedPanel.setSomeListener(this);

//最后调用setVisible
setVisible(true);
}

// AddedPanel侦听器方法
@Override
public void doStuff(){
//调用sort1(),当它完成时调用sort2()。
sort1();

}

//模拟排序
// .......一旦方法启动,图形应该变为绿色
//。 ......方法结束后,图形应该变为红色。
private void sort1(){
// repaint graphic to show method is starting
addedPanel.statusOne.setStatus(SortStatus.running);

//在自己的线程中运行排序。
SwingWorker< Void,Void> worker = new SwingWorker< Void,Void>(){

@Override
protected void doInBackground()抛出异常{
//模拟正在完成的工作。
尝试{
Thread.sleep(2000);
} catch(InterruptedException e){
e.printStackTrace();
}
返回null;

$ b @Override
protected void done(){
//重绘图形以显示方法已完成
addedPanel.statusOne.setStatus(SortStatus。已完成);

//调用sort2
sort2();
}

};
worker.execute();
}

//模拟排序
// .......一旦方法启动,图形应该变为绿色
// .....方法结束后,图形应该变为红色。
private void sort2(){
//重绘图形以显示方法开始(绿色)
addedPanel.statusTwo.setStatus(SortStatus.running);

//在自己的线程中运行排序
SwingWorker< Void,Void> worker = new SwingWorker< Void,Void>(){

@Override
protected void doInBackground()抛出异常{
//模拟正在完成的工作。
尝试{
Thread.sleep(2000);
} catch(InterruptedException e){
e.printStackTrace();
}
返回null;
}

@Override
保护void done(){
//重绘图形以显示方法完成。
addedPanel.statusTwo.setStatus(SortStatus.finished);
}

};
worker.execute();
}
}

/ **
*添加到MainFrame的面板
* /
class AddedPanel扩展JPanel {
// Button监听器
SomeListener监听器;
// Button
private JButton aButton = new JButton(Click Me);

//创建状态显示方法状态的圆圈。
public StatusCircles statusOne = new StatusCircles();
public StatusCircles statusTwo = new StatusCircles();

//构造函数。
public AddedPanel(){
setLayout(new BorderLayout(0,15));

//将按钮添加到面板。
add(aButton,BorderLayout.NORTH);

//使面板保持图形和标签。
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;


$ b $ **
*用于显示方法用户状态的图形:
* black准备就绪
* green用于运行
*红色表示完成
* /
class StatusCircles扩展JPanel {
private SortStatus sortStatus;
private Ellipse2D.Double statusCircle = new Ellipse2D.Double(2,2,25,25);

//构造函数
public StatusCircles(){
sortStatus = SortStatus.ready;

$ b @Override
protected void paintComponent(Graphics g){
//将图形转换为Graphics2D
Graphics2D g2 =(Graphics2D)g;

//打开反锯齿
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

//设置背景
g2.setColor(Color.BLACK);
g2.fillRect(0,0,getWidth(),getHeight());

//使用基于状态字段的颜色填充状态圆
switch(sortStatus){
已准备就绪:
g2.setColor(Color.BLACK);
g2.fill(statusCircle);
休息;
case running:
g2.setColor(Color.GREEN);
g2.fill(statusCircle);
休息;
案例完成:
g2.setColor(Color.RED);
g2.fill(statusCircle);
休息;
}
}

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

//设置状态方法在。
public void setStatus(SortStatus status){
this.sortStatus = status;
repaint();


$ b / **
*接口
* /
接口SomeListener {
public void doStuff();
}

/ **
*用于描述图形状态的枚举。
* /
enum SortStatus {
ready,
running,
finished
}


解决方案

使用。

  • SwingWorker 有助于避免阻止 EDT 确定 done 告诉你何时(重新)启动按钮。

  • 尝试添加 PropertyChangeListener ,如图所示此处,转换为 ColorIcon ,见这里,在您的标签。每当您在worker中 setProgress()时,您会看到相应的 PropertyChangeEvent

    Problem: graphics aren't repainted until after methods are run.

    When button clicked two methods are called. Inside each method is code that is supposed to change the color of the graphic associated with this method (in the UI); when the method starts the graphic is changed from black to green; when the method finishes the color is changed from green to red. Then the next method is called and its graphic should turn green (method is running) and when the method finishes its graphic should be filled with red (method finished).

    I created a simple status circle graphic (a 30 px circle with fill color) with 3 color states: black for ready; green for running; red for finished.

    I believe the problem has to do with repaint() being on a separate thread and scheduled to run when able? I tried putting the code that updates the graphic inside its own thread-runnable and then using thread.join() to make sure the code had finished running but that didn't work.

    EDIT

    Edit: removing the code I had used for demonstration and replacing with a single, runnable code sample as per comments. What you'll see if you run the code is after you click the button the graphics don't update when each method is started and stopped, it waits until both methods have run and then repaints the graphics.

        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
    }
    

    EDIT

    "The repaint method lodges a request to update the viewing area and returns immediately. Its effect is asynchronous, meaning that it is up to the JVM to execute the paintComponent method on a separate thread." - Introduction to Java programming by Liang.

    I think the problem is either A) in my ignorance my program design is doing something no sane programmer would do, and/or B) I don't know how to make the program change graphics colors then after that happens, then continue doing work on whatever thread the work is being done on (EDT, main thread?).

    I did run into an answer that suggested never to slow down the "main thread" to wait for things to be drawn; and to instead make icons for each status circle and then swap icons - which I guess would force an immediate redraw of whatever is holding the icon? Wouldn't this, though, suggest there is a way to force an immediate repaint?

    Thought experiment: you have a loop that runs 100 times, each iteration takes a second. You want to show the user each iteration by changing the color of a circle to one of a hundred different colors. Would you have to make 100 different icons for this? Or, and what I want to do, is change the fill color of the circle each iteration. ...but how to force the repainting of the circle with each iteration?

    EDIT

    Don't know if it is the "right" solution but the program now functions as I want it to. I placed these addedPanel.paintImmediately(0, 0, getWidth(), getHeight()); directly after the method calls asking for the graphic color to change. I updated the working example code above, the edits are depicted by "//EDIT: Make panel repaint itself".

    EDIT

    Now I have more confidence that I am on the right track. I believe I have implemented the things recommended to me. Understanding SwingWorker came really fast once I understood it was basically like Android's asynTask() (that's where I learned it first, that's why I say it like that). And the simulated work via sleeping is occurring in its own thread, off the EDT, so's okay now (?) ((not that I need my program to take a nap)) Here, now, is the full working code:

    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
    }
    

    解决方案

    Using the approach shown here, let each sort update its display from a separate SwingWorker, while a Supervisor worker monitors a CountDownLatch to determine when all sorts are done.

    Addendum: I have never seen an Applet before, nor a SwingWorker…I don't understand why I would need to determine when all the sorts are done…I have edited the question.

    • The example is also a hybrid.

    • SwingWorker helps avoid blocking the EDT.

    • Determining done tells you when to (re-)enable the start button.

    • Try adding a PropertyChangeListener, shown here, to a ColorIcon, seen here, in your label. Each time you setProgress() in the worker, you'll see a corresponding PropertyChangeEvent.

    这篇关于动态更改自定义图形的颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆