Dr_Click Dr_Click - 3 months ago 16
Java Question

My knob drawn with Swing is ugly. Why?

I'm drawing a knob as a component and I'm using swing. The result seems ok but when I click on the knob and move my mouse (up or down) to change the knob position, the knob repainted is ugly, as if there were 2 layers superposed. More over, I have this result only for the "small sizes" of my knob. If I enlarge my frame, this ugly effect disappear. Does someone could explain me what happens and how to improve my knob ?

Thanks a lot for those who will help me.

Here is my code :

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Line2D;

import javax.swing.JFrame;
import javax.swing.JPanel;


public class Knob extends JPanel implements MouseListener {
int length, originX, originY, centerX, centerY, width, height, diameter, squareLength;
int minorTick, majorTick, xTick, yTick, xCursor, yCursor;
int xMouse, yMouse, xMouseOrigin, yMouseOrigin;
float yDeltaMouse;
double angleOrigin, angleRange, angle;
double cursorValue;
double initialCursorValue;
Color backgroundColor, knobColor;
boolean mousePressed;
Thread t;
private double knobValue;
private String title = new String("");
private int titleWidth;

Knob (double initialValue, Color c, int majorTick, int minorTick) {
//System.out.println("Knob");
cursorValue=initialCursorValue=initialValue;
knobColor =c;
this.majorTick=majorTick;
this.minorTick=minorTick;

this.addMouseListener(this);
}

Knob (double initialValue, Color c, int majorTick, int minorTick, String title) {
//System.out.println("Knob");
cursorValue=initialCursorValue=initialValue;
knobColor =c;
this.majorTick=majorTick;
this.minorTick=minorTick;
this.title=title;

this.addMouseListener(this);
}

public void paintComponent (Graphics g) {
width=this.getWidth()/10*10;
height=this.getHeight()/10*10;

Graphics2D g2D = (Graphics2D)g;
System.setProperty("awt.useSystemAAFontSettings", "on");
System.setProperty("swing.aatext", "true");
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

if (width>height) {
length=height;
} else {
length=width;
}
centerX=width/2;
centerY=height/2;

g.setColor(Color.BLACK);
squareLength = (int )(length*0.9);
originX=(width-squareLength)/2;
originY=(height-squareLength)/2;

/*
//-45 = (-(Math.PI)/4)
angleOrigin= -45;
// 270 = (3*(Math.PI)/2)
angleRange=270;
//g.drawRect(originX, originY, squareLength, squareLength);
//g.fillArc(originX, originY, squareLength, squareLength, (int)angleOrigin, (int)angleRange);
for (int i=0; i<minorTick ; i++) {
angle=((i*angleRange/(minorTick-1))+angleOrigin)-7;
//System.out.println(angle*360/(2*Math.PI));
xTick= (int) (centerX+Math.cos(angle)*squareLength/2);
yTick= (int) (centerY-Math.sin(angle)*squareLength/2);
//g.drawLine(centerX, centerY, xTick, yTick);
//g.fillArc(originX, originY, squareLength, squareLength, (int)angle, (int)14);
}
*/

angleOrigin=-(Math.PI)/4;
angleRange=3*(Math.PI)/2;
g2D.setStroke(new BasicStroke(length/50+1));
for (int i=0; i<minorTick ; i++) {
angle=i*angleRange/(minorTick-1)+angleOrigin;
//System.out.println(angle*360/(2*Math.PI));
xTick= (int) (centerX+Math.cos(angle)*squareLength/2);
yTick= (int) (centerY-Math.sin(angle)*squareLength/2);
//g.drawLine(centerX, centerY, xTick, yTick);
g2D.draw (new Line2D.Float(centerX, centerY, xTick, yTick));
}

backgroundColor = this.getBackground();
g.setColor(backgroundColor);
diameter=(int)(length*0.8);
originX=(width-diameter)/2;
originY=(height-diameter)/2;
g.fillOval(originX, originY, diameter, diameter);


/*
RadialGradientPaint gp;
Point2D center= new Point2D.Float(width/2, height/2);
diameter=(int)(length*0.75);
originX=(width-diameter)/2;
originY=(height-diameter)/2;
float radius=diameter/2;
float[] dist = {0.7f, 1f};
Color[] colors = {Color.BLUE, Color.GRAY};
gp=new RadialGradientPaint(center, radius, dist, colors);
g2D.setPaint(gp);
g2D.fillOval(originX,originY,diameter,diameter);
*/
diameter=(int)(length*0.75);
originX=(width-diameter)/2;
originY=(height-diameter)/2;
g.setColor(Color.GRAY);
g.fillOval(originX,originY,diameter,diameter);

diameter=(int)(length*0.7);
originX=(width-diameter)/2;
originY=(height-diameter)/2;
g.setColor(knobColor);
g.fillOval(originX,originY,diameter,diameter);


g2D.setStroke(new BasicStroke(length/50+3));
angle=(2*Math.PI)*(0.75-cursorValue*0.75)+angleOrigin;
xCursor= (int) (centerX+Math.cos(angle)*length*0.35);
yCursor= (int) (centerY-Math.sin(angle)*length*0.35);
g.setColor(Color.GRAY);
g2D.draw (new Line2D.Float(centerX, centerY, xCursor, yCursor));

g2D.rotate(Math.toRadians(270.0));
g.setFont(new Font(g.getFont().getFontName(),Font.PLAIN,this.getHeight()/3));
titleWidth=g.getFontMetrics().stringWidth(title);
g2D.drawString(title,-this.getHeight()+titleWidth/3,this.getHeight()/4);
//System.out.println(titleWidth);
//System.out.println(this.getHeight()*(-70)/100+" - "+this.getHeight());
}

@Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
//System.out.println("Bouton : "+arg0.getButton());

}

@Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub

}

@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub

}

@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
//System.out.println("Bouton : "+arg0.getButton());
PointerInfo pointer = MouseInfo.getPointerInfo();
Point mouseLocation = pointer.getLocation();
xMouseOrigin = (int) mouseLocation.getX();
yMouseOrigin = (int) mouseLocation.getY();
if (arg0.getButton()==MouseEvent.BUTTON1) {
mousePressed=true;
t= new Thread(new TrackPosition());
t.start();
} else if (arg0.getButton()==MouseEvent.BUTTON3) {
cursorValue=initialCursorValue;
repaint();
knobValue=cursorValue;
}
}

@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
mousePressed=false;
//System.out.println("Mouse released");
repaint();
}

class TrackPosition implements Runnable {

@Override
public void run() {
// TODO Auto-generated method stub
while (mousePressed==true) {
PointerInfo pointer = MouseInfo.getPointerInfo();
Point mouseLocation = pointer.getLocation();
yMouse = (int) mouseLocation.getY();
yDeltaMouse=(float)(yMouse-yMouseOrigin)/100;
cursorValue=cursorValue+yDeltaMouse;
yMouseOrigin=yMouse;
if (cursorValue >=1) {
cursorValue=1;
} else if (cursorValue <= 0) {
cursorValue=0;
}
//This repaint is a problem if I "uncomment" it
repaint();
knobValue=cursorValue;
}
}
}

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame frame = new JFrame();
frame.setSize(300,70);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new Knob(0.5, new Color(0,255,0,255), 3, 9, "Gain"));
frame.setVisible(true);
}


}

Answer

You miss to call the paintComponent(Graphics g) method from JComponent.

Changing your code as below will solve the problem.

public void paintComponent(Graphics g) {
    super.paintComponent(g);