setOpaque() in java
Can anyone explain why Nimbius treats the setOpaque() differently than other java LaF's. Its breaking my code because components that are normally transparent no longer are.
EDIT: The problem seems to only deal with JTextAreas (which is what I need) or similar components.
EDIT EDIT: This is a screen of the actual application. When applying trashgod's solution, the background still does not show through.
EDIT EDIT EDIT:
I tried trashgod's suggestion to override the paint(). I toiled with this for hours, and could not get it to work. I was able to get the background to show through, but the JinternalFrame was unable to be moved, resized, and have its text selected. Calling super.paint(g) failed to solve the solution. Is there an easy way to do this that I might be missing?
Ive taken a new approach to this. Inside the JInternalFrame is a JLayeredPane.
Layer 0 - JLabel
Layer 1 - JTextArea
When the JInternalFrame is moved or resized:
- Makes itself invisible
- Takes a screen shot of where it was in the container its contained in
- Paints the JLabel with the image it took
- Makes itself visible again.
Since I could not get the JInternalFrame to be transparent at all. I simulated its transpaency. The only issue is, there is a lot of overhead associated with this. Any thoughts?
package newpackage;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
/**
* Example of how to create a transparent internal frame.
* @author dvargo
*/
public class TransparentInternalFrame extends JInternalFrame {
JLayeredPane container;
/**
* Defualt constructor to set the frame up
* @param container The container for the frame
* @param opacity The opacity of the frame
*/
public TransparentInternalFrame(JLayeredPane container, int opacity) {
super("", true, true, true, true);
this.container = container;
initComponents();
setSize(200, 200);
putClientProperty("JInternalFrame.isPalette", Boolean.TRUE);
scrollPane.setBackground(new Color(0, 0, 0, opacity));
scrollPane.getViewport().setBackground(new Color(0, 0, 0, opacity));
textArea.setBackground(new Color(0, 0, 0, opacity));
setBG();
}
/**
* Builds the GUI
*/
private void initComponents() {
layeredPane = new javax.swing.JLayeredPane();
imageLabel = new javax.swing.JLabel();
scrollPane = new javax.swing.JScrollPane();
textArea = new javax.swing.JTextArea();
imageLabel.setBounds(0, 0, 360, 260);
layeredPane.add(imageLabel, javax.swing.JLayeredPane.DEFAULT_LAYER);
scrollPane.setBorder(null);
textArea.setColumns(20);
textArea.setRows(5);
textArea.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
textAreaKeyPressed(evt);
}
public void keyReleased(java.awt.event.KeyEvent evt) {
textAreaKeyReleased(evt);
}
public void keyTyped(java.awt.event.KeyEvent evt) {
textAreaKeyTyped(evt);
}
});
addComponentListener(new java.awt.event.ComponentAdapter() {
public void componentMoved(java.awt.event.ComponentEvent evt) {
frameMoved();
}
public void componentResized(java.awt.event.ComponentEvent evt) {
frameResized();
}
});
scrollPane.setViewportView(textArea);
scrollPane.setBounds(0, 0, 360, 260);
layeredPane.add(scrollPane, javax.swing.JLayeredPane.PALETTE_LAYER);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(layeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, 362, javax.swing.GroupLayout.PREFERRED_SIZE));
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(layeredPane, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE));
}
/**
* The text will be blurred with out this
* @param evt
*/
private void textAreaKeyTyped(java.awt.event.KeyEvent evt) {
repaintAll();
}
/**
* The text will be blurred with out this
* @param evt
*/
private void textAreaKeyPressed(java.awt.event.KeyEvent evt) {
repaintAll();
}
/**
* The text will be blurred with out this
* @param evt
*/
private void textAreaKeyReleased(java.awt.event.KeyEvent evt) {
repaintAll();
}
/**
* Capture whats behind the frame and paint it to the image label
*/
private void setBG() {
setVisible(false);
Rectangle location = new Rectangle(this.getX() + container.getX(),
this.getY() + container.getY(),
(int) this.getSize().getWidth() + 8 + ((javax.swing.plaf.basic.BasicInternalFrameUI) getUI()).getNorthPane().getWidth(),
(int) this.getSize().getHeight() + ((javax.swing.plaf.basic.BasicInternalFrameUI) getUI()).getNorthPane().getHeight() + 4);
ImageIcon newIcon = new ImageIcon(createImage((JComponent) container, location));
setVisible(true);
imageLabel.setIcon(newIcon);
repaint();
}
/**
* Only need to update the image label if the frame is moved or resized
*/
private void frameResized() {
setBG();
textArea.repaint();
}
/**
* Only need to update the image label if the frame is moved or resized
*/
private void frameMoved() {
setBG();
for(Component x : container.getComponents())
{
//see if its a jinternalframe
if(x.getClass().getName().equals(this.getClass().getName()))
{
//cast it
TransparentInternalFrame temp = (TransparentInternalFrame)x;
//make sure its not the same one as this
if(x.getBounds().equals(this.getBounds()))
{
return;
}
//if they intersect
if(x.getBounds().intersects(this.getBounds()))
{
this.setVisible(false);
temp.setBG();
this.setVisible(true);
}
}
}
textArea.repaint();
}
private void repaintAll() {
textArea.repaint();
imageLabel.repaint();
layeredPane.repaint();
scrollPane.repaint();
scrollPane.getViewport().repaint();
textArea.repaint();
repaint();
}
/**
* Create a BufferedImage for Swing components.
* All or part of the component can be captured to an image.
*
* @param component Swing component to create image from
* @param region The region of the component to be captured to an image
* @return image the image for the given region
*/
public static BufferedImage createImage(JComponent component, Rectangle region) {
// Make sure the component has a size and has been layed out.
// (necessary check for components not added to a realized frame)
if (!component.isDisplayable()) {
Dimension d = component.getSize();
if (d.width == 0 || d.height == 0) {
d = component.getPreferredSize();
component.setSize(d);
}
layoutComponent(component);
}
BufferedImage image = new BufferedImage(region.width, region.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
// Paint a background for non-opaque components,
// otherwise the background will be black
if (!component.isOpaque()) {
g2d.setColor(component.getBackground());
g2d.fillRect(region.x, region.y, region.width, region.height);
}
g2d.translate(-region.x, -region.y);
component.paint(g2d);
g2d.dispose();
return image;
}
public static void layoutComponent(Component component) {
synchronized (component.getTreeLock()) {
component.doLayout();
if (component instanceof Container) {
for (Component child : ((Container) component).getComponents()) {
layoutComponent(child);
}
}
}
}
private javax.swing.JLabel imageLabel;
private javax.swing.JScrollPane scrollPane;
private javax.swing.JLayeredPane layeredPane;
private javax.swing.JTextArea textArea;
public static void main(String args[])
{
try
{
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
}
catch (Exception e)
{
e.printStackTrace();
}
JFrame container = new JFrame();
container.setSize(800, 800);
JLayeredPane layerPanel = new JLayeredPane();
layerPanel.setSize(800, 800);
container.getContentPane().add(layerPanel);
layerPanel.setVisible(true);
JPanel colorPanel = new JPanel();
colorPanel.setSize(800,800);
colorPanel.setBackground(Color.red);
layerPanel.add(colorPanel);
layerPanel.setLayer(colorPanel, JLayeredPane.DEFAULT_LAYER);
TransparentInternalFrame frameA = new TransparentInternalFrame(layerPanel,0);
frameA.setVisible(true);
layerPanel.add(frameA);
layerPanel.setLayer(frameA, 1);
frameA.setSize(282,282);
TransparentInternalFrame frameB = new TransparentInternalFrame(layerPanel, 0);
frameB.setVisible(true);
layerPanel.add(frameB);
layerPanel.add(frameB,1);
frameB.setLocation(300, 300);
frameB.setSize(282,282);
container.repaint();
container.setVisible(true);
}
}
Solution 1:
You may get some insight from the section on Opacity in the article Painting in AWT and Swing. In particular, setting the opaque property does not mean, "Make the component's background transparent." An sscce that demonstrates the problem may also be fruitful.
Addendum: Simplifying your example, it looks like the text area itself can be made transparent, but the Nimbus defaults are affecting the area's borders. You might try changing them accordingly.
A few notes on your code:
- Always build you GUI on the event dispatch thread.
- Don't draw from another thread.
- Don't swallow exception.
Addendum: See changes to create()
.
Addendum: You might want to look at the isPalette
property, too
jif.putClientProperty("JInternalFrame.isPalette", Boolean.TRUE);
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import javax.swing.JInternalFrame;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.UIManager;
public class TransparentTextArea extends JTextArea {
int alpha;
public TransparentTextArea(int alpha) {
super(4, 16);
this.alpha = alpha;
this.setBackground(new Color(0, 0, 0, alpha));
this.setFont(new Font("Serif", Font.ITALIC, 24));
this.setEditable(false);
this.setText("Twas brillig and the slithy toves,\n"
+ "Did gyre and gimble in the wabe;\n"
+ "All mimsy were the borogoves,\n"
+ "And the mome raths outgrabe.");
}
private static void create() {
JFrame f = new JFrame();
f.setLayout(new FlowLayout());
f.getContentPane().setBackground(new Color(0xffffc0));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JInternalFrame jif = new JInternalFrame();
JPanel panel = new JPanel();
panel.setBackground(new Color(0xffffc0));
panel.add(new TransparentTextArea(0));
jif.add(panel);
jif.setVisible(true);
f.add(jif);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
create();
}
});
}
}
Solution 2:
As explained here, setOpaque does not do what you would think that it does, and that failure is made obvious in Nimbus. The other answer which refers to the alpha color is the correct way to accomplish what you want.