采用以下示例代码。如果组件包含HTML,则Swing中存在一些错误,它不会将禁用的组件呈现为禁用。除了报告我希望同事已经处理过的问题之外,还有一些解决问题的好方法吗?
无论我采取什么解决方案,我都希望它能够成为一个全局解决方案,而不是需要被应用到应用程序中每个复选框的内容。
我尝试为绘制前后调用setForeground
的复选框创建自定义UI,但事实证明,通过调用setForeground
,它会触发一个事件,最终导致调用{ {1}},它调用渲染器,...
repaint()
答案 0 :(得分:1)
您可以将复选框和标签分隔到自己的组件中,只需创建一个没有标签的复选框。您也可以将它们添加到自己的面板中,并覆盖面板的setEnabled()
方法,只需启用/禁用复选框并更改标签的颜色即可。以此代码段为例:
final JCheckBox checkbox = new JCheckBox();
final JLabel label = new JLabel();
JPanel panel = new JPanel() {
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
checkbox.setEnabled(enabled);
if (enabled)
label.setForeground(Color.BLACK);
else
label.setForeground(Color.GRAY);
}
};
panel.add(checkbox);
panel.add(label);
请注意,checkbox
和label必须是最终的才能在我们的面板的setEnabled()方法中使用它们。根据您将HTML插入复选框的频率,您始终可以创建自己的组件类来执行此操作。
public class HTMLCheckBox extends JPanel {
private JCheckBox checkbox = new JCheckBox();
private JLabel label = new JLabel();
private Color disabledColor = Color.GRAY;
private Color enabledColor = Color.BLACK;
public HTMLCheckBox(String text) {
label.setText(text);
add(checkbox);
add(label);
}
public boolean isSelected() {
return checkbox.isSelected();
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
checkbox.setEnabled(enabled);
if (enabled)
label.setForeground(enabledColor);
else
label.setForeground(disabledColor);
}
}
然后根据需要添加自己的构造函数和方法。例如,覆盖setBackground()
以使其设置面板,复选框和标签的背景。更改标签文本的setText()
方法可能也很方便。无论你想要它做什么。甚至可能是enabledColor
和disabledColor
的设置者,允许您随意更改这些内容。
答案 1 :(得分:0)
我建议开始使用渲染器而不是那个。您可以在渲染器中使用HTML(例如JLabel),您的问题将自行消失:)
更多信息位于http://java.sun.com/docs/books/tutorial/uiswing/components/combobox.html#renderer
答案 2 :(得分:0)
我必须停止回答我自己的问题......必须与时区有关,并有时间在睡觉时考虑它。
应用程序中的其他位置......
UIManager.put("CheckBoxUI", "package.for.CustomisedWindowsCheckBoxUI");
然后这是实现,但这仍然非常hacky并且它使用实用程序方法来生成HTML颜色字符串,这对于在此处发布来说不太好。
请注意,这仅适用于Windows L& F.金属L& F也见证了有问题,但解决方案是相同的,只是子类BasicCheckBoxUI而已。
import java.awt.Graphics;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View;
import com.sun.java.swing.plaf.windows.WindowsCheckBoxUI;
import com.blah.util.ColourUtils;
/**
* Customisation of Windows check box UI to fix bugs.
*/
public class CustomisedWindowsCheckBoxUI extends WindowsCheckBoxUI {
/**
* Factory method called from Swing.
*
* @param b the check box.
* @return the UI.
*/
public static ComponentUI createUI(JComponent b) {
// TODO: Sun have an AppContext they use to store these once per app.
// Might be more sociable to use something like that.
return new CustomisedWindowsCheckBoxUI();
}
@Override
public void paint(Graphics g, JComponent c) {
AbstractButton b = (AbstractButton) c;
// Works around a bug in BasicButtonUI where a disabled button with HTML markup in the text will
// not appear to be disabled.
// TODO: Find a way to fix this globally for HTML rendering. It seems odd that it isn't working.
// I can see the code in BasicHTML.createHTMLView which uses the foreground colour, which is
// obviously why setForeground() works as a workaround.
if (b.getForeground() instanceof ColorUIResource) {
View view = (View) c.getClientProperty(BasicHTML.propertyKey);
if (view != null) {
// Ensure that we don't update the renderer if the value hasn't changed.
String cachedHtmlFor = (String) c.getClientProperty("cachedHtmlFor");
String key = String.format("%s:%s", c.isEnabled(), b.getText());
if (!key.equals(cachedHtmlFor)) {
c.putClientProperty("cachedHtmlFor", key);
if (c.isEnabled()) {
BasicHTML.updateRenderer(c, b.getText());
} else {
BasicHTML.updateRenderer(c, String.format("<html><div style='color: %s'>%s",
ColourUtils.toHtmlColour(b.getBackground().darker()),
b.getText()));
}
}
}
}
super.paint(g, c);
}
}