【问题标题】:How to change Background color of a JButton from a derived class in Java Swing如何从 Java Swing 中的派生类更改 JButton 的背景颜色
【发布时间】:2015-10-07 14:34:47
【问题描述】:

我有一个基类大型机,我将 JButton 保持为最终静态,它的 BGcolor 将被大型机的扩展类即数据帧更改。最初我需要将 JButton 的 BGColor 设置为红色。然后我需要将它更改为数据框中的其他颜色。我可以从大型机设置 BGColor,但不能从数据框(扩展类)设置。我用过 mainframe.Button_name.setBackground(color.yellow);但它仍然没有改变

`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
     }

    } 
  }
}

请大家帮忙解决这个问题

【问题讨论】:

  • 您的while-loop 看起来很可疑,可能是您阻塞了事件调度线程和/或违反了 Swing 的单线程特性。考虑提供一个runnable example 来证明您的问题。这不是代码转储,而是您正在做的事情的一个例子,它突出了您遇到的问题。这将减少混乱并获得更好的响应
  • 数据框是独立于主机创建的线程!
  • Swing 不是线程安全的,您不应该从 EDT 的上下文之外修改 UI
  • 好的,我是新的 Jswing!有没有其他方法可以做到这一点?
  • 可能有数千个,但我不是你想要达到的目标(是的,我知道你想改变按钮的背景颜色,但是在什么条件下,这些条件会在哪里出现等)

标签: java swing jbutton


【解决方案1】:

因此,您想从不同类中的不同线程更改 UI 组件的状态。您可能有多种方法可以做到这一点,但首先,我将首先定义这些类,使其只能影响您希望它们进行的更改。

暴露整个框架、组件甚至按钮都不是一个好主意,人们有改变你不希望他们做的事情的习惯,所以我们定义了一个简单的合同来说明他们可以做什么,比如……

public interface Colorable {

    public void setColor(Color color);

}

这会立即解耦您的代码,这意味着任何想要更改 UI 状态(或更改其他颜色)的代码都可以这样做,而无需依赖物理实现。

Thread

首先,我们将看看使用Thread 来更改用户界面...

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();
    }

}

这是一个非常基本的类,它需要一个 Colorable 的实例,并且会根据每一个 100 计数改变颜色的状态,这取决于它是偶数还是奇数

我们使用一个简单的JPanel 作为我们的基础测试类,当您单击按钮时,ColorChanger 将被创建并启动。

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);
                }
            });
        }
    }

}

您会注意到setColor 方法中有一堆代码,这是为了确保对 UI 的更新仅在事件调度线程的上下文中执行。

SwingWorker

另一种方法是使用SwingWorker,它的操作方式与Thread 非常相似,希望它能够将publish 内容发送到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;
    }

}

您会注意到,当我们想要更改颜色时,我们调用publish。调用process方法是为了让我们知道还有更多的数据需要处理,但是这里,我们只关心最后的变化。

然后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);
                }
            });
        }
    }

}

你会注意到 setColor 方法保持不变,这是故意的,当你测试这个类时,你会注意到 "Not in the EDT" 从未被打印出来,基本上意味着我们可以取消所有这些代码,只需调用 @ 987654346@,但我想让你看看有什么不同。

按钮...

现在,当我运行此代码时,我得到以下输出...

等一下,按钮背景已填满?!实际上是这样,但是很多按钮实现都有一个次要的“内容区域”填充

您可以使用类似...的方式关闭它

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

这将导致类似...

【讨论】:

    猜你喜欢
    • 2014-05-11
    • 2011-03-12
    • 1970-01-01
    • 2011-01-28
    • 2014-05-28
    • 2016-05-08
    • 2010-12-11
    • 1970-01-01
    • 2020-12-06
    相关资源
    最近更新 更多