我正在使用Nimbus Look and Feel开发应用程序。有一个表和一列包含按钮(使用Table Button Column from Rob Camick)。这确实有效,但结果并不像我预期的那样。我试图修复外观,但无济于事。
所以问题是:如何更改Nimbus按钮的“背景”(圆角矩形以外的区域)?最好以非黑客的方式: - )
使用默认的表列按钮,结果如下所示:
正如您所看到的,背景(我的意思是按钮圆角矩形之外的区域)对于奇数(白色)行是错误的。产生此输出的代码是:
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
if (isSelected) {
renderButton.setForeground(table.getSelectionForeground());
renderButton.setBackground(table.getSelectionBackground());
} else {
renderButton.setForeground(table.getForeground());
renderButton.setBackground(table.getBackground());
}
if (hasFocus) {
renderButton.setBorder( focusBorder );
} else {
renderButton.setBorder( originalBorder );
}
// <snip some code>
renderButton.setOpaque(true);
return renderButton;
}
renderButton
是默认JButton
的实例。我已经尝试搞乱了按钮的背景颜色,但这并没有像我预期的那样有效:
Color alternate = (Color)LookAndFeel.getDesktopPropertyValue("Table.alternateRowColor", Color.lightGray);
Color normal = (Color)LookAndFeel.getDesktopPropertyValue("Table.background", Color.white);
if (row % 2 == 0) {
renderButton.setBackground(normal);
} else {
renderButton.setBackground(alternate);
}
这会产生:
所以这次在第一张图片中看起来不错的按钮现在很糟糕,反之亦然。按钮的内部背景(圆角矩形内的区域)似乎根据背景颜色属性(这是使用setBackground()
调用真正修改的内容)具有正确的颜色。但外面的区域都是错的。好吧,让我们把两者结合起来:
Color alternate = table.getBackground();
Color normal = (Color)LookAndFeel.getDesktopPropertyValue("Table.background", Color.white);
if (row % 2 == 0) {
renderButton.setBackground(normal);
} else {
renderButton.setBackground(alternate);
}
结果:
所以现在“背景”看起来确实正确,但按钮看起来不再像Nimbus按钮了。如何使“背景”具有正确的颜色,同时仍然看起来像Nimbus按钮?
答案 0 :(得分:2)
下面是一个hacky方式,跟进@ Piro的建议:使用带按钮作为子组件的JPanel。鉴于我们并不真正想要触摸按钮的“内部”背景视觉效果,这本身就是一个好主意。
在强制Nimbus内部不使用 JPanel的默认背景来填充其区域但是使用给定面板实例的背景时,黑客就出现了这需要依赖于实现细节,特别是背景颜色的查找机制。这发生在SynthStyle.getColor():
// If the developer has specified a color, prefer it. Otherwise, get
// the color for the state.
Color color = null;
if (!id.isSubregion()) {
if (type == ColorType.BACKGROUND) {
color = c.getBackground();
}
....
}
if (color == null || color instanceof UIResource) {
// Then use what we've locally defined
color = getColorForState(context, type);
}
翻译:它确实查询了实例的颜色,但如果实例颜色是UIResource则用默认值覆盖它 - 如果用作渲染器,通常就是这种情况。所以诀窍(由SynthBooleanRenderer尝试失败,但这是另一个故事;-)是使实例颜色不成为UIResource。另一个怪癖是UIResource是必要的,以确保条纹颜色 - 不是UIResource类型,哈哈 - 应用...直观,不是它...
public class RendererPanel implements TableCellRenderer {
private JComponent panel;
private JButton button;
public RendererPanel() {
panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(3, 10, 2, 10));
button = new JButton();
panel.add(button);
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus, int row,
int column) {
// suggestion by Piro - use background of default
DefaultTableCellRenderer dt = (DefaultTableCellRenderer) table.getDefaultRenderer(Object.class);
dt.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
// first try: set the color as-is - doesn't work
// panel.setBackground(dt.getBackground());
// second try: set color as not ui-resource
// that's working because at this point we already have the color that will be used
// let's hinder synth background color searching to fall back to component defaults
panel.setBackground(new Color(dt.getBackground().getRGB()));
// hack: unwrap ui-resource as needed
// updateBackground(isSelected ? table.getSelectionBackground() : table.getBackground(), row);
button.setText(String.valueOf(value));
return panel;
}
private void updateBackground(Color color, int row) {
Color hack = row % 2 == 0 ? unwrap(color) : color;
panel.setBackground(hack);
}
private Color unwrap(Color c) {
if (c instanceof UIResource) {
return new Color(c.getRGB());
}
return c;
}
}
屏幕截图:with unwrap hack
屏幕截图:使用默认颜色(来自为Object.class安装的渲染器)
非hacky出路可能是(没有在这里尝试,但记得曾经做过一次)注册一个具有样式的Region,类似于NimbusDefaults在内部做的事情:
register(Region.PANEL, "Table:\"Table.cellRenderer\"");
这里的问题是没有公开的api这样做(或者可能是我对Synth的了解不够; - )
答案 1 :(得分:1)
不要将背景设置为JButton。使用JPanel包装JButton并将背景设置为JPanel。如果在一个JTable列中使用了更多按钮,这可能是显而易见的。
设置我所做的JPanel的正确背景颜色(你应该):
这样您就不必自己选择正确的颜色
此外,您必须覆盖paintComponent才能正确绘制JPanel的白色背景:
@Override
protected void paintComponent(Graphics g) {
Color background = getBackground();
setBackground(new Color(background.getRGB()));
super.paintComponent(g);
}
编辑:如@kleopatra建议您不必覆盖paintComponent,只将背景颜色设置为not-uiresource(显示在完整示例中)
这是完整的例子:
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.table.TableCellRenderer;
public class Test {
public static void main(String[] args) throws Throwable {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
String[] columnNames = new String[]{"c1"};
Object[][] data = new Object[4][1];
data[0][0] = "First";
data[1][0] = "Second";
data[2][0] = "Third";
data[3][0] = "Fourth";
JTable table = new JTable(data, columnNames){
@Override
public javax.swing.table.TableCellRenderer getCellRenderer(int row, int column) {
final TableCellRenderer ori = super.getCellRenderer(row, column);
final TableCellRenderer mine = new TableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
Component c = ori.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
JPanel p = new JPanel();
if(value == null){
value = "";
}
p.add(new JButton(value.toString()));
p.setBackground(new Color(c.getBackground().getRGB()));
return p;
}
};
return mine;
};
};
table.setRowHeight(50);
JFrame f = new JFrame();
f.add(table);
f.setVisible(true);
f.pack();
}
}
结果: