Transparent JList smears when selecting elements or scrolling - java

I have a transparent JList and JScrollPanel on top of a gradient JPanel the code for each of those looks like this:
JPanel midPanel = new JPanel() {
protected void paintComponent(Graphics g) {
Paint p = new GradientPaint(0.0f, 0.0f, new Color(233, 220, 0, 0),
getWidth(), getHeight(), new Color(239, 129, 91, 255), true);
Graphics2D g2d = (Graphics2D)g;
g2d.setPaint(p);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
};
List code
ArrayList<String> songs = new ArrayList<>(Arrays.asList(new String[] {elements...}));
DefaultListModel<String> model = new DefaultListModel<>();
model.addAll(songs);
JList<String> songList = new JList<String>(model);
songList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
songList.setLayoutOrientation(JList.VERTICAL);
songList.setVisibleRowCount(-1);
songList.setOpaque(false);
songList.setCellRenderer(new TransparentListCellRenderer());
JScrollPane scroller = new JScrollPane(songList);
scroller.setPreferredSize(new Dimension(400, 250));
scroller.setOpaque(false);
scroller.getViewport().setOpaque(false);
scroller.setBorder(BorderFactory.createEmptyBorder());
midPanel.add(scroller);
Before anything is touched it looks like this:
And after stuff gets selected or scrolling the elements of the list all smear and create this mess:
Does anyone know how to fix this? if I had to guess what was wrong it would be an issue with the gradient because the paintComponet() method is overridden so it's not getting redrawn properly but if that is the case I do not know how to fix it. Any help is much appreciated.

The answer is to wrap the panel in a Container that is a sort of transparent.
public 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());
}
}

Related

Event handling in Java not working as expected

I cannot get the code linked below to do exactly what I want it to do.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Gui {
static JFrame frame;
static JLabel label;
public static void main (String[] args) {
Gui gui = new Gui();
gui.go();
}
public void go () {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,300);
frame.setVisible(true);
MyDrawPanel panel = new MyDrawPanel();
frame.getContentPane().add(BorderLayout.CENTER, panel);
label = new JLabel("I'm a label");
frame.getContentPane().add(BorderLayout.WEST, label);
JButton colorButton = new JButton("Change Colors");
ColorButtonListener colorButtonListener = new ColorButtonListener();
colorButton.addActionListener(colorButtonListener);
frame.getContentPane().add(BorderLayout.SOUTH, colorButton);
JButton labelButton = new JButton("Change Label");
LabelButtonListener labelButtonListener = new LabelButtonListener();
labelButton.addActionListener(labelButtonListener);
frame.getContentPane().add(BorderLayout.EAST, labelButton);
}
}
class ColorButtonListener implements ActionListener {
JFrame frame = Gui.frame;
public void actionPerformed (ActionEvent event) {
frame.repaint();
}
}
class LabelButtonListener implements ActionListener {
JLabel label = Gui.label;
public void actionPerformed (ActionEvent event) {
if (label.getText() == "That hurt") {
label.setText("I'm a label");
} else {
label.setText("That hurt");
}
}
}
class MyDrawPanel extends JPanel {
public void paintComponent (Graphics g) {
Graphics2D g2d = (Graphics2D) g;
int red = (int) (Math.random() * 256);
int green = (int) (Math.random() * 256);
int blue = (int) (Math.random() * 256);
Color startColor = new Color(red, green, blue);
red = (int) (Math.random() * 256);
green = (int) (Math.random() * 256);
blue = (int) (Math.random() * 256);
Color endColor = new Color(red, green, blue);
GradientPaint gradient = new GradientPaint(70, 70, startColor, 150, 150, endColor);
g2d.setPaint(gradient);
g2d.fillOval(0, 0, this.getWidth(), this.getHeight());
}
}
There is a panel class used to draw a circle and then the panel is positioned in the center region of the frame.
A label is positioned in the west region of the frame, two buttons colorButton(positioned south) and labelButton(positioned east) should control the circle and the label respectively. 2 classes ColorButtonListener and LabelButtonListener implement the ActionListener interface and are registered with the colorButton and labelButton respectively. The color button when clicked should paint a circle with random colors and the label button when clicked should toggle between the text "I'm a label" and "That hurt".
Now, the issue I am having is with the label button. When clicking it, it not only changes the text(as expected), but also redraws the circle. This button should not be redrawing the circle. The color button works as expected.
The problem is you don't control when a repaint might occur. Instead of changing the color every time paintComponent is called, which you can't control, change the color only when you want to and reference from within the paintComponent method, for example
class MyDrawPanel extends JPanel {
private Color startColor;
private Color endColor;
// And setters or some other way
// to randomise the colors
public void paintComponent (Graphics g) {
Graphics2D g2d = (Graphics2D) g;
GradientPaint gradient = new GradientPaint(70, 70, startColor, 150, 150, endColor);
g2d.setPaint(gradient);
g2d.fillOval(0, 0, this.getWidth(), this.getHeight());
}
}
Check out Painting in AWT and Swing for more details
This is because setText() methods internally calls repaint() if new text is not same as old text. So results in color change whenever you click that button too.

How do I set contentPane without using the main method or calling other methods?

I understand that the following sets the background colour of the contentPane. How do I set a picture as its background instead?
I've tried these:
Setting background images in JFrame
JAVA: Ways to fill a Frame. add(), setContentPane(), getContentPane()
http://www.dreamincode.net/forums/topic/131439-setting-background-color-content-pane/
But none of them have worked.
JLabel lblbackground = new JLabel();
lblbackground.setBounds(20, 20, 160, 160);
lblbackground.setBorder(new LineBorder(new Color(0, 0, 0), 2));
lblbackground.setIcon (new ImageIcon (this.getClass().getResource("/boundary/background.jpg")));
lblbackground.setHorizontalAlignment (SwingConstants.CENTER);
BufferedImage img = new BufferedImage(lblbackground.getIcon().getIconWidth(), lblbackground.getIcon().getIconHeight(), BufferedImage.TYPE_INT_RGB);
Graphics g = img.createGraphics();
lblbackground.getIcon().paintIcon(null, g, 0, 0);
g.dispose();
Image newing = img.getScaledInstance(150, 150, java.awt.Image.SCALE_SMOOTH);
lblbackground.setIcon(new ImageIcon(newing));
//getContentPane().setLayout(new GridBagLayout());
contentPane = new JPanel();
//contentPane.setBackground(Color.LIGHT_GRAY);
contentPane.setBorder(null);
contentPane.setLayout(null);
contentPane.add(lblbackground);
setContentPane (contentPane);
(...)
// 1) Create your image;
final ImageIcon image = new ImageIcon("../folder/myImage.gif");
//2) Create a JPanel with a background image;
JPanel myPanel = new JPanel(){
#Override
public void paintComponent(Graphics g)
{
g.drawImage(image.getImage(), 0, 0, null);
}
};
//3) Add panel
getContentPane().add(myPanel);
(...)

Image in JPanel not appearing immediately

I am using getImage to read files and save them and then setting these images to the backgrounds of jpanels. However, when the applet is first loaded, the images aren't visible. Only, if I resize it or scroll up and down, do the images appear. What is the problem?
#Override
public void init(){
setSize(800, 600);
setLayout(new FlowLayout());
setup();
box1.setText(texts[0]);
box2.setText(texts[1]);
box3.setText(texts[2]);
box4.setText(texts[3]);
add(box1);
add(box2);
add(box3);
add(box4);
add(testPanel);
add(localPanel);
add(background2);
}
public void setup(){
box1 = new JTextArea();
box2 = new JTextArea();
box3 = new JTextArea();
box4 = new JTextArea();
box1.setText(texts[0]);
box2.setText(texts[1]);
box3.setText(texts[2]);
box4.setText(texts[3]);
//*********** this loads immediately **********//
Image back2 = getImage(getDocumentBase(), "blank_blue.png");
background2 = new JLabel(new ImageIcon(back2));
panelBack = getImage(getDocumentBase(), "CardBar.png");
localPanel = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(panelBack, 0, 0, null);
}
};
localPanel.setPreferredSize(new Dimension(100, 400));
}
The image may not be read it when the component is initially painted. Try:
//g2d.drawImage(panelBack, 0, 0, null);
g2d.drawImage(panelBack, 0, 0, this);

how to add gradient background to JTable column header?

Hi how to set gradient background to column header ? I have Jtable:
JTable table = new JTable(4, 5);
and try to setColor: table.getTableHeader().setBackground(Color.blue);
but with no succes color of column header is still same and these is just one color and I need gradient
thx for help
Are you coding this with NetBean's code generation or are you coding your Swing by hand?
Have you tried creating a class that extends the JTableHeader and overrides its paintComponent method? Give it a try and in that method create a GradientPaint object or one of its variants use it to set the Graphics2D paint's property and then call fillRect using the current dimensions of the component to fill it with gradient color.
For example here are two ways to do this, one with a custom JTableHeader and one with a custom cell renderer that is used by the table header:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class GradientHeader {
private static void createAndShowGui() {
JTable table1 = new JTable();
GradientTableHeader gradientTableHeader = new GradientTableHeader();
gradientTableHeader.setColumnModel(table1.getColumnModel());
table1.setTableHeader(gradientTableHeader);
DefaultTableModel model = new DefaultTableModel(new Integer[][] {
{ 1, 2 }, { 3, 4 } }, new String[] { "A", "B" });
table1.setModel(model);
JTable table2 = new JTable(model);
table2.getTableHeader().setDefaultRenderer(new MyCellRenderer());
JPanel mainPanel = new JPanel(new GridLayout(1, 0));
mainPanel.add(new JScrollPane(table1));
mainPanel.add(new JScrollPane(table2));
JFrame frame = new JFrame("GradientHeader");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class GradientTableHeader extends JTableHeader {
private static final Color COLOR_1 = new Color(255, 0, 0, 240);
private static final Color COLOR_2 = new Color(0, 0, 255, 120);
private static final float SIDE = 50;
private GradientPaint gradientPaint = new GradientPaint(0, 0, COLOR_1, SIDE,
SIDE, COLOR_2, true);
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(gradientPaint);
g2.fillRect(0, 0, getWidth(), getHeight());
}
}
class MyCellRenderer extends JPanel implements TableCellRenderer {
private static final Color COLOR_1 = new Color(255, 0, 0, 200);
private static final Color COLOR_2 = new Color(0, 0, 255, 200);
private static final float SIDE = 50;
private GradientPaint gradientPaint = new GradientPaint(0, 0, COLOR_1, SIDE,
SIDE, COLOR_2, true);
private JLabel label = new JLabel();
public MyCellRenderer() {
setOpaque(true);
setLayout(new BorderLayout());
add(label, BorderLayout.CENTER);
label.setHorizontalAlignment(SwingConstants.CENTER);
}
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocused, int arg4, int arg5) {
label.setText(value.toString());
return this;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(gradientPaint);
g2.fillRect(0, 0, getWidth(), getHeight());
}
}

Custom UI painting problem

I have a JInternalFrame that I am applying a custom UI to. The UI paints the component, but when I add a JPanel to the JInternalFrame it doesn't show up. I think the UI is paining over the whole component, but how do I paint the UI THEN paint the components?
But if anyone has a better way of doing this, please let me know! Thanks!
public class ClassInternalFrame extends JInternalFrame {
public static Color currentColor;
public static final Color CLASS_TYPE = new Color(148, 227, 251);
public ClassInternalFrame(String title, Color classType) {
super(title, true, true, false, true);
currentColor = classType;
super.setUI(new ClassFrameUI());
Container pane = super.getContentPane();
pane.setLayout(new BorderLayout());
JPanel titlePanel = new JPanel();
titlePanel.setPreferredSize(new Dimension(0, 20));
pane.add(titlePanel, BorderLayout.NORTH);
titlePanel.setBorder(new MatteBorder(1, 1, 1, 1, Color.yellow));
}
}
class ClassFrameUI extends InternalFrameUI {
private final static ClassFrameUI frmUI = new ClassFrameUI();
public static ComponentUI createUI(JComponent c) {
return frmUI;
}
#Override
public void paint(Graphics g, JComponent c)
{
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.LIGHT_GRAY);
g2d.fillRect(0, 0, c.getWidth(), c.getHeight());
g2d.setColor(ClassInternalFrame.currentColor);
g2d.fillRect(0, 0, c.getWidth(), 20);
g2d.setColor(Color.DARK_GRAY);
g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] { 1, 0 }, 0));
g2d.drawRect(0, 0, c.getWidth()-1, c.getHeight()-1);
g2d.drawLine(0, 20, c.getWidth(), 20);
}
}
The problem is not that you're painting over anything, but that InternalFrameUI does absolutely nothing (if it did, you would also need to call super.paint(g, c);). Normally, painting of the components is done by a subclass such as BasicInternalFrameUI. It looks like you're trying to paint a custom title bar, a task that BasicInternalFrameUI delegates to BasicInternalFrameTitleBar.

Categories