Could someone give me a hint on how to display a transparent JTextPane
that is the child of other components such as a JScrollPane
and a JPanel
, please. I've used an AlphaContainer
which is available here for transparency.
This is working:
chatTextPane = new JTextPane();
chatTextPane.setEditable(false);
chatTextPane.setHighlighter(null);
chatTextPane.setBackground(new Color(255,255,255,100));
AlphaContainer ac = new AlphaContainer(chatTextPane);
JPanel chatPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
chatPanel.setOpaque(false);
chatPanel.add(ac);
It looks like this:
However if I wrap it into a non-opaque JScrollPane
, it is not transparent anymore. And if I put the JScrollPane
in an AlphaContainer
, highlighting is enabled again (and buggy):
chatTextPane = new JTextPane();
chatTextPane.setEditable(false);
chatTextPane.setHighlighter(null);
chatTextPane.setBackground(new Color(255,255,255,100));
JScrollPane scrollPane = new JScrollPane(chatTextPane);
scrollPane.setOpaque(false);
AlphaContainer ac = new AlphaContainer(scrollPane);
JPanel chatPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
chatPanel.setOpaque(false);
chatPanel.add(ac);
It looks like this then:
Finally I originally want to add it to another panel with a JTextField
in a BoxLayout
as well. If I try this, the JTextField
is displayed twice: once correctly at the bottom, but also at the top (non-editable).
I've been trying to fix this for a couple of hours now and I'm thankful for anything.
Here's runnable code for the second example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MyClass {
public static void main(String args[]) {
new MyClass();
}
public MyClass() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(new Color(100, 0, 0, 255));
//
JTextPane chatTextPane = new JTextPane();
chatTextPane.setEditable(false);
chatTextPane.setHighlighter(null);
chatTextPane.setPreferredSize(new Dimension(300, 300));
chatTextPane.setBackground(new Color(255,255,255,100));
chatTextPane.setText("testtesttesttesttesttest");
JScrollPane scrollPane = new JScrollPane(chatTextPane);
scrollPane.setOpaque(false);
AlphaContainer ac = new AlphaContainer(scrollPane);
JPanel chatPanel = new JPanel();
chatPanel.setOpaque(false);
chatPanel.add(ac);
//
frame.add(chatPanel);
frame.pack();
frame.setVisible(true);
}
});
}
private class AlphaContainer extends JComponent {
private JComponent component;
public AlphaContainer(JComponent component) {
this.component = component;
setLayout(new BorderLayout());
setOpaque(false);
component.setOpaque(false);
add(component);
}
/**
* Paint the background using the background Color of the contained component
*/
@Override
public void paintComponent(Graphics g) {
g.setColor(component.getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
}
Swing components have a parent/child relationship. In your case it looks like:
Swing paints the parent components before the child components. So you want the content pane (which is opaque) to be painted first, then the "ChatPanel" (which will be semi-transparent) painted next and then all other child components to be non-opaque.
So a couple of changes:
AlphaContainer
needs to be used on the component being added to the content pane.You do this by using:
//frame.add(chatPanel);
frame.add( new AlphaContainer(chatPanel) );
Note: the AlphaContainer
will make the component added to it non-opaque, so you don't need to explicitly use setOpaque( false );
You need to make the JTextPane non-opaque (since is no loner added to the AlphaContainer).
You also need to make the JViewport
non-opaque.
This is done by using:
scrollPane.getViewport().setOpaque( false );
Also don't use:
chatTextPane.setPreferredSize(new Dimension(300, 300));
The scrollbars will only appear when the preferred size of the component is greater than the size of the scroll pane. If you hardcode the preferred size, then the scrollbar won't appear because the preferred size won't change as you add text to the text area.
Set the preferred size on the scroll pane.