具有透明文本字段的 Java Nimbus LAF
我有一个应用程序在几个地方使用禁用的 JTextFields,这些地方旨在透明 - 允许背景显示而不是文本字段的正常背景。
当运行新的 Nimbus LAF 时,这些字段是不透明的(尽管设置了 setOpaque(false)),并且我的 UI 被破坏了。 就好像 LAF 忽略了不透明属性。 显式设置背景颜色在多个地方都很困难,而且由于背景图像而不太理想实际上不起作用 - 它仍然在顶部绘制 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); }
I have an application that uses disabled JTextFields in several places which are intended to be transparent - allowing the background to show through instead of the text field's normal background.
When running the new Nimbus LAF these fields are opaque (despite setting setOpaque(false)), and my UI is broken. It's as if the LAF is ignoring the opaque property. Setting a background color explicitly is both difficult in several places, and less than optimal due to background images actually doesn't work - it still paints it's LAF default background over the top, leaving a border-like appearance (the splash screen below has the background explicitly set to match the image).
Any ideas on how I can get Nimbus to not paint the background for a JTextField?
Note: I need a JTextField, rather than a JLabel, because I need the thread-safe setText(), and wrapping capability.
Note: My fallback position is to continue using the system LAF, but Nimbus does look substantially better.
See example images below.
Conclusions
The surprise at this behavior is due to a misinterpretation of what setOpaque() is meant to do - from the Nimbus bug report:
This is a problem the the orginal design of Swing and how it has been confusing for years. The issue is setOpaque(false) has had a side effect in exiting LAFs which is that of hiding the background which is not really what it is ment for. It is ment to say that the component my have transparent parts and swing should paint the parent component behind it.
It's unfortunate that the Nimbus components also appear not to honor setBackground(null) which would otherwise be the recommended way to stop the background painting. Setting a fully transparent background seems unintuitive to me.
In my opinion, setOpaque()/isOpaque() is a faulty public API choice which should have been only:
public boolean isFullyOpaque();
I say this, because isOpaque()==true is a contract with Swing that the component subclass will take responsibility for painting it's entire background - which means the parent can skip painting that region if it wants (which is an important performance enhancement). Something external cannot directly change this contract (legitimately), whose fulfillment may be coded into the component.
So the opacity of the component should not have been settable using setOpaque(). Instead something like setBackground(null) should cause many components to "not have a background" and therefore become not fully opaque. By way of example, in an ideal world most components should have an isOpaque() that looks like this:
public boolean isOpaque() { return (background!=null); }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
上周我使用 JTextPane 遇到了同样的问题。 当使用 nimbus 以外的任何外观和感觉时,setOpaque() 方法会按预期工作。 显然,nimbus 的外观和感觉改变了我们对许多组件的 setOpaque() 的期望行为。 根据你如何看待它,它可以被视为一个错误。 检查此 Sun bugid 上的评论:
nimbus opaque bug
有效的解决方法我是:
OP 的注释:我还必须确保 JTextField 的 setOpaque(false) ,以便绘制父背景 - 只是想向其他关注者提及这一点,以防他们像我一样尝试过 setOpaque(true) 。
I ran into this same issue last week using JTextPane. The setOpaque() method works as expected when using any look and feel other than nimbus. Apparently, the nimbus look and feel changes the behaviour we have come to expect with setOpaque() for many Components. Depending on how you look at it, it can be considered a bug. Check the comments on this sun bugid:
nimbus opaque bug
The workaround that worked for me was:
Note from OP: I also had to ensure setOpaque(false) for JTextField so that the parent background was painted - just wanted to mention this for others who follow in case they had experimented with setOpaque(true), as I had.
嘿,软件猴子。
嗯,安装实际上尊重 setOpaque 行为的 UI 子类替换怎么样?
我认为它类似于 setUI 之类的东西。
您可以获取 nimbus 的源代码,看看那里有什么问题(如果有的话),将其子类化并安装“已修复”的代码。
你的听起来很有趣,你有我们可以看到的截图吗?
Hey there Software Monkey.
mmhh what about installing UI's subclasses replacement that actually respect the setOpaque behavior.
I think it is something like setUI or something like that.
You could grab the source code of the nimbus and see what's broken there ( if it is there ) , subclass it and install the "fixed" one.
Yours sound quite intersting, do you have any screenshot we can see?
来自javadoc
From the javadoc
我认为问题是如何解释“不透明”和“背景”。
对于 JTextfield 存在一个问题:“哪些可见部分是背景?”。 我将“背景”定义为边界矩形的部分,这些部分不是由组件绘制的。
例如,对于“圆形”按钮,这将是圆外的角。
因此我想说 JTextfield 没有可见的背景! 它有一个矩形形状,您作为背景的不是字段的背景,而是字段的画布。
来自OP的反驳
这是一个足够有趣的想法,值得在未来观众的答案中做出回应(而不是在评论中)。
我必须不同意。 我认为组件在边框之外的部分不是组件的一部分 - 它在组件的外部。 具有圆角的字段必然是非不透明的,因为它不能负责绘制整个矩形区域 - 这是所有尺寸均为矩形的组件的副作用。
我认为这种考虑为 isOpaque() 的现有(和误解)含义提供了论据。 它还使我认为 setOpaque() 不应该存在,并且 setBackground(null) 应该导致组件不绘制背景。
我认为文本字段的背景确实是其边框内区域的颜色,并且我认为您不会发现很多人对这一直观结论提出异议 - 因此将背景应用于该区域遵循API 用户最不意外的规则。
I think the question is how to interpret "opaque" and "background".
For a JTextfield there is the question: "what visible parts are the background?". I'd define "background" as the parts of the bounding rectangle, that are not drawn by the component.
For a "round" button, e.g., this will be the corners outside the circle.
Therefor I'd say a JTextfield has no visible background! It has a rectangular shape and what you are the taking as background is not the field's background but the field's canvas.
Rebuttal from OP
This is an interesting enough idea to be worth responding to in the answer for future viewers (as opposed to in comments).
I have to disagree. I would argue that the part of the component outside the border is not part of the component - it's outside the component. A field with rounded corners is, of necessity, non-opaque, in that it cannot be responsible for painting it's entire rectangular region - this is a side-effect of all components being rectangular in dimensions.
I think this consideration makes the argument for the existing (and misunderstood) meaning of isOpaque(). It also makes my argument that setOpaque() should not exist and that setBackground(null) should cause the component to not paint a background.
I would put forth that the background of a text field is indeed the color of the region inside it's borders, and I don't think you will find very many people to dispute that as an intuitive conclusion - therefore having background apply to that region obeys the rule of least surprise for the API user.