How to change Background color of a JButton from a derived class in Java Swing

旧时模样 提交于 2019-12-25 03:39:14

问题


I have a base class mainframe and i have keeping the JButton as final static Which its BGcolor going to be changed by a extended class of mainframe namely dataframe. Initially i need to set the BGColor of the JButton to red. Then I need to change it to some other colors from the dataframe. I can able to set the BGColor from the mainframe but not from the dataframe(extended class). I've used mainframe.Button_name.setBackground(color.yellow); but still its not changing

`enter code here`

 public class mainframe {

 final static JButton Button_name = new JButton("Hi");

 public static void main(String[] args)
 {
 public void run()
  {
         Button_name.setBackground(color.Red);        //This is working  
  }
 }
}

 class dataframe extends mainframe implements Runnable
{
public void run()
{
   //doing other things
  while(some condition)
  {

     if (another_condition)
     {
        //from here i need to change that Buttons color
       // i've tried this
       mainframe.Button_name.setBackground(color.yellow);  //Not working
     }

    } 
  }
}

Kindly anyone help with this issue


回答1:


So you want to change the state of a UI component from a different thread in a different class. There are multiple ways you might be able to do this, but first, I would start by defining away for those classes to be able to only effect the change you want them to.

Exposing the entire frame, component or even button is not a good idea, people have a habit of changing things you don't want them to, so instead, we define a simple contract which states what they are allowed to do, for example...

public interface Colorable {

    public void setColor(Color color);

}

This immediately decouples your code, meaning that any code that wants to change the state of your UI (or change the color of something else) can do so, without relying on the physical implementation.

Thread

First, we're going to have a look at using a Thread to change the UI...

public class ColorChanger {

    private Colorable colorable;

    public ColorChanger(Colorable colorable) {
        this.colorable = colorable;
    }

    public void start() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int index = 0; index < 1000; index++) {
                    if (index % 100 == 0) {
                        if ((index / 100) % 2 == 0) {
                            colorable.setColor(Color.GREEN);
                        } else {
                            colorable.setColor(Color.RED);
                        }
                    }
                    try {
                        // This is so you can see the colors changing
                        Thread.sleep(5);
                    } catch (InterruptedException ex) {
                    }
                }
                System.out.println("Done");
            }
        });
        t.start();
    }

}

This is a pretty basic class, it requires an instance of Colorable and will change the state of the color for every 100 counts, based on if it's an even or odd hundred

We use a simple JPanel as our base test class, when you click the button, the ColorChanger is created and started.

public class TestPane extends JPanel implements Colorable {

    private JButton btn;
    private ColorChanger changer;

    public TestPane() {
        setLayout(new GridBagLayout());
        setBorder(new EmptyBorder(20, 20, 20, 20));
        btn = new JButton("I am your button");
        add(btn);
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (changer == null) {
                    changer = new ColorChanger(TestPane.this);
                    changer.start();
                }
            }
        });
    }

    @Override
    public void setColor(Color color) {
        if (EventQueue.isDispatchThread()) {
            btn.setBackground(color);
        } else {
            System.out.println("Not in the EDT");
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    setColor(color);
                }
            });
        }
    }

}

You will note that the setColor method has a bunch of code in it, this is to ensure that the updates to the UI are executed only from within the context of the Event Dispatching Thread.

SwingWorker

An alternative is to use a SwingWorker, which operates very similarly to a Thread, expect it has the ability to publish content to the EDT

public class ColorChangerWorker extends SwingWorker<Void, Color> {

    private Colorable colorable;

    public ColorChangerWorker(Colorable colorable) {
        this.colorable = colorable;
    }

    @Override
    protected void process(List<Color> chunks) {
        colorable.setColor(chunks.get(chunks.size() - 1));
    }

    @Override
    protected Void doInBackground() throws Exception {
        for (int index = 0; index < 1000; index++) {
            if (index % 100 == 0) {
                if ((index / 100) % 2 == 0) {
                    publish(Color.GREEN);
                } else {
                    publish(Color.RED);
                }
            }
            try {
                // This is so you can see the colors changing
                Thread.sleep(5);
            } catch (InterruptedException ex) {
            }
        }
        System.out.println("Done");
        return null;
    }

}

You will note here, that when we want to change the color we call publish. The process method is called to let us know that there is more data to be processed, but here, we're only interested in the last change.

And out TestPane...

public class TestPane extends JPanel implements Colorable {

    private JButton btn;
    private ColorChangerWorker changer;

    public TestPane() {
        setLayout(new GridBagLayout());
        setBorder(new EmptyBorder(20, 20, 20, 20));
        btn = new JButton("I am your button");
        add(btn);
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (changer == null) {
                    changer = new ColorChangerWorker(TestPane.this);
                    changer.execute();
                }
            }
        });
    }

    @Override
    public void setColor(Color color) {
        if (EventQueue.isDispatchThread()) {
            btn.setBackground(color);
        } else {
            System.out.println("Not in the EDT");
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    setColor(color);
                }
            });
        }
    }

}

You will note that the setColor method remains unchanged, this is deliberate, when you test this class, you will note that "Not in the EDT" is never printed, basically meaning we could do away with all that code and just call btn.setBackground(color);, but I want you to see the difference.

The Button...

Now, when I run this code, I get the following output...

Wait a minute, that buttons background is filled?! Actually it is, but many button implementations have a secondary "content area" filling

You can turn this off using something like...

btn.setContentAreaFilled(false);
btn.setOpaque(true);

Which will result in something like...



来源:https://stackoverflow.com/questions/32984558/how-to-change-background-color-of-a-jbutton-from-a-derived-class-in-java-swing

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!