使用Java Nimbus LAF实现透明文本框

11
我有一个应用程序在多个地方使用禁用的JTextField,这些文本字段打算是透明的 - 允许背景显示而不是文本字段的正常背景。
当运行新的Nimbus LAF时,这些字段是不透明的(尽管设置了setOpaque(false)),我的UI就会崩溃。就好像LAF忽略了opaque属性一样。在几个地方明确设置背景颜色很困难,并且由于背景图像不太理想,实际上不起作用 - 它仍然在顶部绘制其默认的LAF背景,留下类似边框的外观(下面的启动画面已将背景明确设置为与图像匹配)。
有任何想法如何使Nimbus不为JTextField绘制背景?
注意:我需要JTextField而不是JLabel,因为我需要线程安全的setText()和包装功能。
注意:我的退路是继续使用系统LAF,但是Nimbus看起来更好。
请参见下面的示例图像。
结论
对此行为的“惊讶”是由于对setOpaque()的含义误解造成的 - 来自Nimbus错误报告:
这是Swing原始设计的问题,多年来一直令人困惑。问题在于setOpaque(false)在存在的LAF中具有隐藏背景的副作用,这实际上不是它的目的。它意味着该组件可能具有透明部分,Swing应该在其后面绘制父组件。
令人遗憾的是,Nimbus组件似乎也没有遵守setBackground(null),否则这将是停止背景绘制的推荐方法。对我来说,设置完全透明的背景似乎不直观。
在我看来,setOpaque()/isOpaque()是一个错误的公共API选择,本应只有:
public boolean isFullyOpaque();
我之所以这么说,是因为isOpaque() == true是与Swing的契约,即组件子类将负责绘制其整个背景,这意味着父级可以跳过绘制该区域(这是一个重要的性能增强)。外部的某些东西不能直接更改此契约(合法地),因为其履行可能已编码到组件中。
因此,组件的不透明度不应该使用setOpaque()进行设置。相反,诸如setBackground(null)之类的操作会导致许多组件“没有背景”,从而变得不完全不透明。例如,在理想情况下,大多数组件的isOpaque()应该如下所示:
public boolean isOpaque() { return (background!=null); }

示例

替代文本


你是否已经浏览过这个包了? src.zip!\com\sun\java\swing\plaf\nimbus - OscarRyz
4个回答

17
上周我遇到了同样的问题,使用JTextPane时也出现了这个问题。当使用除nimbus之外的任何外观时,setOpaque()方法按预期工作。显然,nimbus外观改变了我们对许多组件的setOpaque()方法的预期行为。从某种角度来看,这可以被视为一个错误。请查看此sun bugid上的评论: nimbus opaque bug 对我有效的解决方法是:
myPane.setOpaque(false); // added by OP
myPane.setBorder(BorderFactory.createEmptyBorder());
myPane.setBackground(new Color(0,0,0,0));

注意:我还必须为JTextField设置setOpaque(false),以便绘制父级背景 - 只是想提醒其他人,如果他们尝试过setOpaque(true),就像我一样。

这看起来很有前途;今晚会在我的应用程序中试试。谢谢。 - Lawrence Dol
@juggler555:谢谢,这个方法可行,只要组件不是不透明的(当我将其设置为不透明时,文本更新会“涂写”在之前的文本上方)。 - Lawrence Dol

0

嘿,软件猴。

嗯,安装UI的子类替换,实际上尊重setOpaque行为怎么样?

我认为它是类似于setUI之类的东西。

你可以获取nimbus的源代码,看看那里有什么问题(如果有的话),对其进行子类化并安装“修复”的版本。

你的听起来很有趣,你有任何截图我们可以看吗?


如果只有这一个选择,我想我会坚持使用系统LAF。至少在Linux、OSX和其他系统上运行时,我不太可能遇到意外情况。 - Lawrence Dol

0

我认为问题在于如何解释“opaque”和“background”。对于JTextfield,有一个问题:“什么可见部分是背景?”我会将“background”定义为组件未绘制的边界矩形的部分。例如,对于一个“圆形”按钮,这将是圆形外的角落。因此,我会说JTextfield没有可见的背景!它具有矩形形状,您所看到的不是字段的背景,而是字段的画布。


OP的反驳

这是一个足够有趣的想法,值得在回答中作出响应给未来的观众(而不是在评论中)。

我不同意。我认为组件边界外的部分不属于组件 - 它在组件的外面。带圆角的字段是必然的非透明性,因为它不能负责绘制其整个矩形区域 - 这是所有组件都具有矩形尺寸的副作用。

我认为这一点支持了现有的(被误解的)isOpaque()方法的含义。这也证实了我认为setOpaque()不应该存在,而setBackground(null)应该使组件不绘制背景的论点。

我要提出的观点是,文本字段的背景确实是其边界内部的颜色,我不认为有很多人会对此产生争议作为直观结论 - 因此,将背景应用于该区域符合API用户最少惊讶原则。


上述提到的错误似乎讲述了同样的故事。 - ordnungswidrig
@ordnungswidrig:你的回答很难理解,但我不敢编辑它,以免替你说错话 - 你想再试一次吗,为了其他人的参考? - Lawrence Dol
@Ordnungswidrig:有趣的想法 - 我对你的答案进行了反驳,因为我认为这是一个重要的观点。 - Lawrence Dol

0

来自javadoc

public void setBackground(Color bg)

设置此组件的背景颜色。只有在组件是不透明的情况下才使用背景颜色,并且只由JComponent的子类或 ComponentUI 实现使用。直接继承JComponent的子类必须重写paintComponent以遵守此属性。

外观和感觉是否遵守此属性取决于其实现,有些可能会选择忽略它。


而且,正如我所说的,Nimbus选择忽略它是一件遗憾的事情。 - Lawrence Dol
但更糟糕的是,文档说只有在 setOpaque 为 true 时才会被执行。 - Martin OConnor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接