I'm trying to create a JPanel that has a picture as the background, this I'm able to do but as seen in the GIF there seems to be some kind of painting issue when selecting different entries from the JList. The JList has nothing special about it except that it has an alpha value of 65, meaning it is mostly transparent. I would like to know how to fix the weird visual glitch.
The code for my custom JPanel...
package com.css.aor.graphics;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
/**
* @author Asmicor
*/
public class JImagePanel extends JPanel {
private static final long serialVersionUID = 248015296776870365L;
private Image img;
private boolean autoScale;
/**
* A JPanel that draws an image as the background in the center of the panel
*
* @param img Image that will be drawn as the background
* @param autoScale Should the image be scaled to fit the whole space of the panel
*/
public JImagePanel(Image img, boolean autoScale) {
this.img = img;
this.autoScale = autoScale;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (autoScale) {
int h = img.getHeight(null);
int w = img.getWidth(null);
// Scale Horizontally:
if (w > this.getWidth()) {
img = img.getScaledInstance(getWidth(), -1, Image.SCALE_SMOOTH);
h = img.getHeight(null);
}
// Scale Vertically:
if (h > this.getHeight()) {
img = img.getScaledInstance(-1, getHeight(), Image.SCALE_SMOOTH);
}
}
// Center Images
int x = (getWidth() - img.getWidth(null)) / 2;
int y = (getHeight() - img.getHeight(null)) / 2;
g.drawImage(img, x, y, this);
}
}
When I add a repaint() after g.drawImage the problem seems to be solved but as far as I know this is not a good thing to do.
EDIT: I noticed that when I add a listener to the JList for when the selected value is changed and then call repaint on the whole frame this issue also seems to be solved, so I'm thinking that something is going wrong with the order of the repainting of the components.
Example runnable code...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.AbstractListModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
public class Test {
private class JImagePanel extends JPanel {
private static final long serialVersionUID = 248015296776870365L;
private Image img;
private boolean autoScale = false;
/**
* A JPanel that draws an image as the background in the center of the panel
*
* @param img Image that will be drawn as the background
* @param autoScale Should the image be scaled to fit the whole space of the panel
*/
public JImagePanel(Image img, boolean autoScale) {
this.img = img;
this.autoScale = autoScale;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
if (autoScale) {
int h = img.getHeight(null);
int w = img.getWidth(null);
// Scale Horizontally:
if (w > this.getWidth()) {
img = img.getScaledInstance(getWidth(), -1, Image.SCALE_SMOOTH);
h = img.getHeight(null);
}
// Scale Vertically:
if (h > this.getHeight()) {
img = img.getScaledInstance(-1, getHeight(), Image.SCALE_SMOOTH);
}
}
// Center Images
int x = (getWidth() - img.getWidth(null)) / 2;
int y = (getHeight() - img.getHeight(null)) / 2;
g.drawImage(img, x, y, this);
}
}
}
private JFrame frame;
private JImagePanel panel;
private JList list;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Test window = new Test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Test() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JImagePanel(Toolkit.getDefaultToolkit().getImage("C:\\Users\\Asmicor\\Desktop\\lh8vuSc.png"), true); // <-------- Just change this to a viable path
frame.getContentPane().add(panel, BorderLayout.CENTER);
list = new JList();
list.setModel(new AbstractListModel() {
String[] values = new String[] {"ghgfhgfhgfhgfhgfh", "gfhgfhgfhgfhgfhgfh", "gfhgfhgfhgfhgfhgfh", "gfhgfhgfhgfhdshs", "hgdfgdsfgsgdsfgdsfg", "dfhgfhdgfhdfhgfdhdgh"};
public int getSize() {
return values.length;
}
public Object getElementAt(int index) {
return values[index];
}
});
list.setBackground(new Color(0, 125, 50, 65));
GroupLayout gl_panel = new GroupLayout(panel);
gl_panel.setHorizontalGroup(
gl_panel.createParallelGroup(Alignment.LEADING)
.addGroup(Alignment.TRAILING, gl_panel.createSequentialGroup()
.addContainerGap(41, Short.MAX_VALUE)
.addComponent(list, GroupLayout.PREFERRED_SIZE, 359, GroupLayout.PREFERRED_SIZE)
.addGap(34))
);
gl_panel.setVerticalGroup(
gl_panel.createParallelGroup(Alignment.LEADING)
.addGroup(gl_panel.createSequentialGroup()
.addGap(19)
.addComponent(list, GroupLayout.PREFERRED_SIZE, 208, GroupLayout.PREFERRED_SIZE)
.addContainerGap(34, Short.MAX_VALUE))
);
panel.setLayout(gl_panel);
}
}
EDIT2: From what I can gather it happens to any component that has a transparent background that is drawn over the image. I tested it on a JLabel as well as a JTable, both have similar visual glitches. The only real fix is to add repaint() to my paintComponent of JImagePanel, but my CPU usage is really high then.