Search code examples
javauser-interfaceswingtransparencytranslucency

Java Swing - Translucent Components causing Artifacts


I'm currently working on a group project for a college course, and I've hit a bit of a stumbling block. The program we have decided to implement is a Peer-to-Peer chat client with a central server for storing and sharing usernames, etc. I've been assigned to do the GUI.

A friend jokingly suggested that I include "a flaming background!" So I decided to do just that, but to have a user-chosen background image. As is, only bits and pieces of the background image would be visible with all the components over top of it, so I decided to try to implement translucency.

This is where my problem lies:

When sending information from the input box to the chat window, or when navigating the friends list, or scrolling the chat window, strange artifacts are left behind. These artifacts are sometimes translucent "ghosts" of the Send button, sometimes part of the menu, or old text. It looks to me like the whole frame is not getting redrawn properly, but I'm not sure of how that works.

For components that implement JTextComponent, I'm setting their selection color to be a translucent color. For other components, I'm setting the background to be translucent. I have a function, setTranslucency(Component com) that looks at a component, sets its translucency depending on what it is, then sees if it is a container of some sort and sets the translucency of each item recursively.

Now, the way that I've found to fix this problem is to drag the window out of sight (such as minimizing or dragging the window off-screen and back).

So,

1) Is there a way to force the entire window to update like it does when I drag it off of the screen or minimize it?

or,

2) Am I doing it wrong in the first place? If so, how would I fix it?

Here's a picture for reference:

https://i.sstatic.net/4J9GJ.png


Solution

  • You need to tell Swing that the components are translucent, so it does also paint the background when repainting the changed components. For this, your components have to return false from the isOpaque() method (this can be achieved by setOpaque(false) when no subclass overwrites isOpaque to do something else).

    With this, it should work without any manual repainting of everything, as the other answers proposed. (I already did this once.)

    Edit: The reason for this is that Swing uses an optimized repainting-algorithm, repainting only these components which really need repainting (for example, a JTextField after some input) or components in front of such ones, as long as they are opaque. When a component needing repainting is not opaque (= filling its whole space with non-translucent color), also repainting of the components behind them is necessary.