Java Nimbus LAF with transparent text fields
Asked Answered
V

4

11

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

Example

alt text

Vitrics answered 5/3, 2009 at 4:48 Comment(1)
Have you skim over this package already? src.zip!\com\sun\java\swing\plaf\nimbusMalik
H
17

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:

myPane.setOpaque(false); // added by OP
myPane.setBorder(BorderFactory.createEmptyBorder());
myPane.setBackground(new Color(0,0,0,0));

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.

Hydrazine answered 5/3, 2009 at 17:25 Comment(2)
This looks promising; will try it tonight in my app. Thanks.Vitrics
@juggler555: Thanks, that works, provided the component is not opaque (when I left it opaque, text updates "scribbled" over the top of the previous).Vitrics
M
0

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?

Malik answered 5/3, 2009 at 4:56 Comment(1)
If the only choice was this, I think I would stick with the system LAF. At least then I am less likely to have surprises when running in Linux, OSX, and others.Vitrics
U
0

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.

Undershot answered 6/3, 2009 at 13:8 Comment(3)
The bug refered to above seems to tell the same story.Undershot
@ordnungswidrig: Your answer is hard to decipher, but I am hesitant to edit it and risk putting words in your mouth - do you want to make a second pass at it, for others who come along?Vitrics
@Ordnungswidrig: Interesting thought - I added a rebuttal to your answer, since I thought this was an important idea.Vitrics
T
0

From the javadoc

public void setBackground(Color bg)

Sets the background color of this component. The background color is used only if the component is opaque, and only by subclasses of JComponent or ComponentUI implementations. Direct subclasses of JComponent must override paintComponent to honor this property.

It is up to the look and feel to honor this property, some may choose to ignore it.

Torsi answered 6/3, 2009 at 13:28 Comment(2)
And, as I said, it's a shame Nimbus has chosen to ignore it.Vitrics
But its worse. The doc says that it's only honored when setOpaque is true.Torsi

© 2022 - 2024 — McMap. All rights reserved.