重绘 Swing 组件会产生糟糕的结果
Posted
技术标签:
【中文标题】重绘 Swing 组件会产生糟糕的结果【英文标题】:Repainting a Swing component produce an awful result 【发布时间】:2015-05-16 14:02:37 【问题描述】:我“绘制”了一个组件来制作一种旋钮,因为我没有找到一种方法来拥有一个“圆形 JSlider”。我使用抗锯齿来获得良好的效果。当我用鼠标按下组件时,我会修改光标位置并要求组件重新绘制。然后,问题出现了:我repain的结果很糟糕!
如果我只在释放鼠标时要求重新绘制,结果似乎保持正确。但是,如果我在设置时不“连续”重新绘制组件,那么设置旋钮值会更加复杂。
导致问题的“重绘”方法位于类末尾的 run 方法中。
有人已经遇到这个问题了吗?可以使用什么样的解决方案来解决它? 这是我正在使用的代码:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
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 angleCursorOrigin;
double angleCursorInitial;
Color backgroundColor, knobColor;
boolean mousePressed;
Thread t;
Knob ()
System.out.println("Knob");
angleCursorOrigin=0.5;
angleCursorInitial=0.5;
knobColor =new Color(0,255,0,255);
minorTick=9;
majorTick=3;
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.6);
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-angleCursorOrigin*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));
@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)
angleCursorOrigin=angleCursorInitial;
repaint();
@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;
angleCursorOrigin=angleCursorOrigin+yDeltaMouse;
yMouseOrigin=yMouse;
if (angleCursorOrigin >=1)
angleCursorOrigin=1;
else if (angleCursorOrigin <= 0)
angleCursorOrigin=0;
//This repaint is a problem if I "uncomment" it
//repaint();
/**
* @param args
*/
public static void main(String[] args)
// TODO Auto-generated method stub
JFrame frame = new JFrame();
frame.setSize(300,90);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new Knob());
frame.setVisible(true);
【问题讨论】:
让我们从您没有调用 super.paintComponent 的事实开始,然后再谈一下您的“跟踪线程”已经过时且不需要的事实。您可以改用 MouseMotionListener 【参考方案1】:让我们从在您的paintComponent
方法中执行自定义绘画之前不调用super.paintComponent
的事实开始。
见Painting in AWT and Swing 和 Performing Custom Painting了解更多详情
然后转移到这个事实,即您的“鼠标跟踪线程”是多余的,实际上并不是必需的。相反,您应该使用MouseMotionListener
,有关详细信息,请参阅How to Write a Mouse Listener。
这将使您无需在本地和屏幕上下文之间进行转换。
【讨论】:
以上是关于重绘 Swing 组件会产生糟糕的结果的主要内容,如果未能解决你的问题,请参考以下文章
swing更改组件(删除后添加)得到心得:起码得刷新一下啊,可能还得再考虑重绘
WM_PAINT消息在窗口重绘的时候产生,那什么时候窗口会重绘(异步工作方式,效率更高,灵活性更强)