问题
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