java- repaint() method is misbehaving?

55 Views Asked by At

I am working on a Music Player

I am using a JSlider as seek bar and using a JLabel to draw text on screen, such as song name.

I am new to Graphics2D

Here's the minimized code:

public class JSliderDemo extends JFrame
{
    
JLabel label;
JSlider seek = new JSlider();
int  y = 10;    

public JSliderDemo()
{
 setSize(400, 400);
 setLocationRelativeTo(null);
 setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 
 createWindow();
 setVisible(true);
 startThread();
}        
    
public void createWindow()
{
 JPanel panel = new JPanel(null);
 panel.setOpaque(true);
 panel.setBackground(Color.BLUE);
 
 label = new Component();
 label.setSize(400, 400);
 label.setLocation(0, 0);
 
 createSlider();
 
 panel.add(seek);
 panel.add(label);
 add(panel);
}        

protected void createSlider()
{
 seek.setUI(new SeekBar(seek, 300, 10, new Dimension(20, 20), 5, 
           Color.DARK_GRAY, Color.RED, Color.RED));
 seek.setOrientation(JProgressBar.HORIZONTAL);
 seek.setOpaque(false);
 seek.setLocation(10, 50);
 seek.setSize(300, 20);
 seek.setMajorTickSpacing(0);
 seek.setMinorTickSpacing(0);
 seek.setMinimum(0);
 seek.setMaximum(1000);    
}        

protected void startThread()
{
 Thread thread = new Thread(new Runnable(){
 @Override
 public void run()
 {
  try
  {
   while(true)
   {
    if(y == label.getHeight()){y = 1;}   
    label.repaint();
    y += 1;
   
    Thread.sleep(100);   
   }    
  }   
  catch(Exception ex){}
 }
 });
 
 thread.start();
}        
        
protected class Component extends JLabel
{
@Override
public void paintComponent(Graphics g)
{
 Graphics2D gr = (Graphics2D) g;
 gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 
 gr.setColor(Color.RED);
 gr.setFont(new Font("Calibri", Font.PLAIN, 16));
 gr.drawString("Slider", 50, y);
}       
}          

public static void main(String[] args) 
{
 new JSliderDemo();
}
    
}

The Custom Slider UI class prints a line each time the JSlider is repainted.

Through this, I was able to find out that, when I call repaint() for JLabel it automatically repaints JSlider with it even though JSlider is not included in JLabel.

Output :

Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted
Slider re-painted.........

Now if I remove label.repaint() from the Thread, then the JSlider is not re-painted.

Output:

Slider re-painted
Slider re-painted

Is the repaint() method supposed to work like this?

Here's the Custom Slider UI class :

package jsliderdemo;

import java.awt.*;
import javax.swing.*;
import java.awt.geom.RoundRectangle2D;
import javax.swing.plaf.basic.BasicSliderUI;

public class SeekBar extends BasicSliderUI 
{
    
private int TRACK_ARC = 5;
private int TRACK_WIDTH = 8;
private int TRACK_HEIGHT = 8;
private Color backGround = Color.GRAY;
private Color trackColor = Color.RED;
private Color thumbColor = Color.WHITE;
private Dimension THUMB_SIZE = new Dimension(20, 20);     
private final RoundRectangle2D.Float trackShape = new RoundRectangle2D.Float();

public SeekBar(final JSlider b, int width, int height, Dimension thumbSize, int arc, 
              Color backGround, Color trackColor, Color thumbColor) 
{
 super(b);
 this.TRACK_ARC = arc;  
 this.TRACK_WIDTH = width;
 this.TRACK_HEIGHT = height;
 this.THUMB_SIZE = thumbSize;
 this.backGround = backGround;
 this.trackColor = trackColor;
 this.thumbColor = thumbColor;
}

@Override
protected void calculateTrackRect() 
{
 super.calculateTrackRect();
 if (isHorizontal()) 
 {
  trackRect.y = trackRect.y + (trackRect.height - TRACK_HEIGHT) / 2;
  trackRect.height = TRACK_HEIGHT;
 } 
 else
 {
  trackRect.x = trackRect.x + (trackRect.width - TRACK_WIDTH) / 2;
  trackRect.width = TRACK_WIDTH;
 }
 trackShape.setRoundRect(trackRect.x, trackRect.y, trackRect.width, trackRect.height, TRACK_ARC, TRACK_ARC);
}

@Override
protected void calculateThumbLocation()
{
 super.calculateThumbLocation();
 if (isHorizontal()) 
 {
  thumbRect.y = trackRect.y + (trackRect.height - thumbRect.height) / 2;
 }
 else
 {
  thumbRect.x = trackRect.x + (trackRect.width - thumbRect.width) / 2;
 }
}

@Override
protected Dimension getThumbSize() 
{
 return THUMB_SIZE;
}

private boolean isHorizontal() 
{
 return slider.getOrientation() == JSlider.HORIZONTAL;
}

@Override
public void paint(final Graphics g, final JComponent c) 
{
 ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 super.paint(g, c);
}

@Override
public void paintTrack(final Graphics g) 
{
 System.out.println("Slider re-painted");
 
 Graphics2D g2 = (Graphics2D) g;
 Shape clip = g2.getClip();

 boolean horizontal = isHorizontal();
 boolean inverted = slider.getInverted();

 // Paint shadow.
 //g2.setColor(new Color(170, 170 ,170));
 //g2.fill(trackShape);

 // Paint track background.
 g2.setColor(backGround);
 g2.setClip(trackShape);
 trackShape.y += 1;
 g2.fill(trackShape);
 trackShape.y = trackRect.y;

 g2.setClip(clip);

 // Paint selected track.
 if (horizontal)
 {
  boolean ltr = slider.getComponentOrientation().isLeftToRight();
  if (ltr) inverted = !inverted;
  int thumbPos = thumbRect.x + thumbRect.width / 2;
  if (inverted) 
  {
   g2.clipRect(0, 0, thumbPos, slider.getHeight());
  }
  else
  {
   g2.clipRect(thumbPos, 0, slider.getWidth() - thumbPos, slider.getHeight());
  }
 }
 else
 {
  int thumbPos = thumbRect.y + thumbRect.height / 2;
  if (inverted) 
  {
   g2.clipRect(0, 0, slider.getHeight(), thumbPos);
  }
  else
  {
   g2.clipRect(0, thumbPos, slider.getWidth(), slider.getHeight() - thumbPos);
  }
 }
 g2.setColor(trackColor);
 g2.fill(trackShape);
 g2.setClip(clip);
}

@Override
public void paintThumb(final Graphics g)
{
 g.setColor(thumbColor);
 g.fillOval(thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height);
}

@Override
public void paintFocus(final Graphics g) {}

}
0

There are 0 best solutions below