问题描述
我从开始学习计划。我尝试以实时模式编辑点。我将MouseMotionListener添加到构造函数中,然后编写一些基本函数以获取指向鼠标的点并编辑此点。当我在构造函数中得到(x,y)点时, repaint()
很奇怪。当我得到(x,y)点在 paintComponent
时, repaint()
根本不起作用。所以,这是在构造函数中获取(x,y)的图像,并且在 paintComponent
中。我的错误在哪里?
package simplegrapher2;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import static java.lang.Math.sqrt;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
导入javax.swing.SwingUtilities;
public class SimpleGrapher2 extends JPanel {
private int width = 800;
private int heigth = 400;
private int padding = 25;
private int labelPadding = 25;
private color lineColor = new Color(44,102,230,180);
private color pointColor = new Color(100,100,100,180);
private color gridColor = new Color(200,200,200,200);
private static final Stroke GRAPH_STROKE = new BasicStroke(2f);
private int pointWidth = 4;
private int numberYDivisions = 10;
私人列表< Double>分数;
private static double serieX = 0;
public List< Point2D.Double> graphPoints;
public SimpleGrapher2(列表< Double>分数){
this.scores = scores;
addMouseMotionListener(new MouseMotionListener(){
@Override
public void mouseDragged(MouseEvent me){
double x = me.getX();
double y = me .getY();
findNearPoint(x,y);
editSerie(x,y);
revalidate();
repaint();
}
@Override
public void mouseMoved(MouseEvent me){}
});
double xScale =((double)getWidth() - (2 * padding) - labelPadding)/(scores.size() - 1);
double yScale =((double)getHeight() - 2 * padding - labelPadding)/(getMaxScore() - getMinScore());
graphPoints = new ArrayList<>();
for(int i = 0; i< scores.size(); i ++){
double x1 =(double)(i * xScale + padding + labelPadding);
double y1 =(double)((getMaxScore() - scores.get(i))* yScale + padding);
graphPoints.add(new Point2D.Double(x1,y1));
}
}
@Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 =(Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
/ * double xScale =((double)getWidth() - (2 * padding) - labelPadding)/(scores.size() - 1);
double yScale =((double)getHeight() - 2 * padding - labelPadding)/(getMaxScore() - getMinScore());
graphPoints = new ArrayList<>();
for(int i = 0; i< scores.size(); i ++){
double x1 =(double)(i * xScale + padding + labelPadding);
double y1 =(double)((getMaxScore() - scores.get(i))* yScale + padding);
graphPoints.add(new Point2D.Double(x1,y1));
} * /
//绘制白色背景
g2.setColor(Color.WHITE);
g2.fillRect(padding + labelPadding,padding,getWidth() - (2 * padding) - labelPadding,getHeight() - 2 * padding - labelPadding);
g2.setColor(Color.BLACK);
//为y轴创建孵化标记和网格线。
for(int i = 0; i< numberYDivisions + 1; i ++){
int x0 = padding + labelPadding;
int x1 = pointWidth + padding + labelPadding;
int y0 = getHeight() - ((i *(getHeight() - padding * 2 - labelPadding))/ numberYDivisions + padding + labelPadding);
int y1 = y0;
if(scores.size()> 0){
g2.setColor(gridColor);
g2.drawLine(padding + labelPadding + 1 + pointWidth,y0,getWidth() - padding,y1);
g2.setColor(Color.BLACK);
String yLabel =((int)((getMinScore()+(getMaxScore() - getMinScore())*((i * 1.0)/ numberYDivisions))* 100))/ 100.0 +;
FontMetrics指标= g2.getFontMetrics();
int labelWidth = metrics.stringWidth(yLabel);
g2.drawString(yLabel,x0 - labelWidth - 5,y0 +(metrics.getHeight()/ 2) - 3);
}
g2.drawLine(x0,y0,x1,y1);
}
//和x轴
(int i = 0; i< scores.size(); i ++){
if(scores) size()> 1){
int x0 = i *(getWidth() - padding * 2 - labelPadding)/(scores.size() - 1)+ padding + labelPadding;
int x1 = x0;
int y0 = getHeight() - padding - labelPadding;
int y1 = y0 - pointWidth;
if((i%((int)((scores.size()/ 20.0))+ 1))== 0){
g2.setColor(gridColor);
g2.drawLine(x0,getHeight() - padding - labelPadding - 1 - pointWidth,x1,padding);
g2.setColor(Color.BLACK);
String xLabel = i +;
FontMetrics指标= g2.getFontMetrics();
int labelWidth = metrics.stringWidth(xLabel);
g2.drawString(xLabel,x0 - labelWidth / 2,y0 + metrics.getHeight()+ 3);
}
g2.drawLine(x0,y0,x1,y1);
//创建x和y轴
g2.drawLine(padding + labelPadding,getHeight() - padding - labelPadding,padding + labelPadding,padding );
g2.drawLine(padding + labelPadding,getHeight() - padding - labelPadding,getWidth() - padding,getHeight() - padding - labelPadding);
笔划oldStroke = g2.getStroke();
g2.setColor(lineColor);
g2.setStroke(GRAPH_STROKE);
for(int i = 0; i< graphPoints.size() - 1; i ++){
double x1 = graphPoints.get(i).x;
double y1 = graphPoints.get(i).y;
double x2 = graphPoints.get(i + 1).x;
double y2 = graphPoints.get(i + 1).y;
g2.draw(new Line2D.Double(x1,y1,x2,y2));
}
g2.setStroke(oldStroke);
g2.setColor(pointColor);
for(int i = 0; i< graphPoints.size(); i ++){
double x = graphPoints.get(i).x - pointWidth / 2;
double y = graphPoints.get(i).y - pointWidth / 2;
int ovalW = pointWidth;
int ovalH = pointWidth;
//g2.fillOval(x,y,ovalW,ovalH);
public void findNearPoint(double x,double y){
double delta = 0;
for(int j = 0; j< graphPoints.size(); j ++){
double sx = graphPoints.get(j).x;
double sy = graphPoints.get(j).y;
double root = sqrt((x-sx)*(x-sx)+(y-sy)*(y-sy));
if(j == 0){
delta = root;
serieX = sx;
}
else if(root< delta){
serieX = sx;
delta = root;
$ b public void editSerie(double x,double y){
double tmpSerieX = serieX;
int ind = 0;
for(int i = 0; i< graphPoints.size(); i ++){
if(graphPoints.get(i).x == tmpSerieX){
ind = i;
}
}
graphPoints.remove(ind);
graphPoints.add(ind,new Point2D.Double(x,y));
serieX = x;
}
private double getMinScore(){
double minScore = Double.MAX_VALUE; (双分:分数)
{
minScore = Math.min(minScore,分数);
}
返回minScore;
}
private double getMaxScore(){
double maxScore = Double.MIN_VALUE;
for(Double score:分数){
maxScore = Math.max(maxScore,分数);
}
返回maxScore;
}
public void setScores(List< Double> scores){
this.scores = scores;
invalidate();
this.repaint();
}
公共列表< Double> getScores(){
返回分数;
}
private static void createAndShowGui(){
List< Double> scores = new ArrayList<>();
Random random = new Random();
int maxDataPoints = 40;
int maxScore = 10; (int i = 0; i scores.add((double)random.nextDouble()* maxScore)的
;
}
SimpleGrapher2 mainPanel = new SimpleGrapher2(scores);
mainPanel.setPreferredSize(new Dimension(800,600));
JFrame frame = new JFrame(DrawGraph);
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();
}
});
}
}
x / yScale $ 时, c code $ ...
$ b $ pre $ public SimpleGrapher2(List< Double> scores){
// ...
double xScale =((double)getWidth() - (2 * padding) - labelPadding)/(scores.size() - 1);
double yScale =((double)getHeight() - 2 * padding - labelPadding)/(getMaxScore() - getMinScore());
// ...
}
在构建组件的时候,组件大小为 0x0
。您需要等到组件在计算点之前以某种有意义的方式调整大小...
这也是有问题的,因为组件可能会重新调整大小,它在第一次在屏幕上实现。
过去我所做的是使用Swing Timer
Timer
将会触发,您可以执行所需的操作,例如... public SimpleGrapher2(List< Double> scores){
// ...
addComponentListener(new ComponentAdapter(){
$ b $ private Timer initTimer = new Timer(200,new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
initTimer.stop();
double xScale =((double )getWidth() - (2 * padding) - labelPadding)/(scores.size() - 1);
double yScale =((double)getHeight() - 2 * padding - labelPadding)/(getMaxScore() - getMinScore());
graphPoints = new ArrayList<>();
for(int i = 0; i< scores.size(); i ++){
double x1 =(double)(i * xScale + padding + labelPadding);
double y1 =(double)((getMaxScore() - scores.get(i))* yScale + padding);
graphPoints.add(new Point2D.Double(x1,y1));
}
repaint();
}
});
$ b $ @Override
public void componentResized(ComponentEvent e){
if(graphPoints == null){
initTimer.restart();
}
}
});
$ b所有这些都会等到定时器
compoentResized
事件超过200毫秒(你可以使用这个值来使它更接近你想要的,但我发现大约250毫秒是一个合理的延迟) p>
您需要更正
paintComponent
以允许graphPoints
一直是null
。I take program from this topic. I try to edit points in real-time mode. I add MouseMotionListener to the constructor and write some basic functions to get near point to mouse and edit this point. When I get (x,y) points in the constructor,
repaint()
works strange. When I get (x,y) points inpaintComponent
,repaint()
doesn't work at all. So, this are images with getting (x,y) in the constructor and inpaintComponent
. Where is my mistake?package simplegrapher2; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Stroke; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import static java.lang.Math.sqrt; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class SimpleGrapher2 extends JPanel { private int width = 800; private int heigth = 400; private int padding = 25; private int labelPadding = 25; private Color lineColor = new Color(44, 102, 230, 180); private Color pointColor = new Color(100, 100, 100, 180); private Color gridColor = new Color(200, 200, 200, 200); private static final Stroke GRAPH_STROKE = new BasicStroke(2f); private int pointWidth = 4; private int numberYDivisions = 10; private List<Double> scores; private static double serieX = 0; public List<Point2D.Double> graphPoints; public SimpleGrapher2(List<Double> scores) { this.scores = scores; addMouseMotionListener(new MouseMotionListener() { @Override public void mouseDragged(MouseEvent me) { double x = me.getX(); double y = me.getY(); findNearPoint(x, y); editSerie(x, y); revalidate(); repaint(); } @Override public void mouseMoved(MouseEvent me) {} }); double xScale = ((double) getWidth() - (2 * padding) - labelPadding) / (scores.size() - 1); double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore()); graphPoints = new ArrayList<>(); for (int i = 0; i < scores.size(); i++) { double x1 = (double) (i * xScale + padding + labelPadding); double y1 = (double) ((getMaxScore() - scores.get(i)) * yScale + padding); graphPoints.add(new Point2D.Double(x1, y1)); } } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); /*double xScale = ((double) getWidth() - (2 * padding) - labelPadding) / (scores.size() - 1); double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore()); graphPoints = new ArrayList<>(); for (int i = 0; i < scores.size(); i++) { double x1 = (double) (i * xScale + padding + labelPadding); double y1 = (double) ((getMaxScore() - scores.get(i)) * yScale + padding); graphPoints.add(new Point2D.Double(x1, y1)); }*/ // draw white background g2.setColor(Color.WHITE); g2.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding - labelPadding); g2.setColor(Color.BLACK); // create hatch marks and grid lines for y axis. for (int i = 0; i < numberYDivisions + 1; i++) { int x0 = padding + labelPadding; int x1 = pointWidth + padding + labelPadding; int y0 = getHeight() - ((i * (getHeight() - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding); int y1 = y0; if (scores.size() > 0) { g2.setColor(gridColor); g2.drawLine(padding + labelPadding + 1 + pointWidth, y0, getWidth() - padding, y1); g2.setColor(Color.BLACK); String yLabel = ((int) ((getMinScore() + (getMaxScore() - getMinScore()) * ((i * 1.0) / numberYDivisions)) * 100)) / 100.0 + ""; FontMetrics metrics = g2.getFontMetrics(); int labelWidth = metrics.stringWidth(yLabel); g2.drawString(yLabel, x0 - labelWidth - 5, y0 + (metrics.getHeight() / 2) - 3); } g2.drawLine(x0, y0, x1, y1); } // and for x axis for (int i = 0; i < scores.size(); i++) { if (scores.size() > 1) { int x0 = i * (getWidth() - padding * 2 - labelPadding) / (scores.size() - 1) + padding + labelPadding; int x1 = x0; int y0 = getHeight() - padding - labelPadding; int y1 = y0 - pointWidth; if ((i % ((int) ((scores.size() / 20.0)) + 1)) == 0) { g2.setColor(gridColor); g2.drawLine(x0, getHeight() - padding - labelPadding - 1 - pointWidth, x1, padding); g2.setColor(Color.BLACK); String xLabel = i + ""; FontMetrics metrics = g2.getFontMetrics(); int labelWidth = metrics.stringWidth(xLabel); g2.drawString(xLabel, x0 - labelWidth / 2, y0 + metrics.getHeight() + 3); } g2.drawLine(x0, y0, x1, y1); } } // create x and y axes g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, padding + labelPadding, padding); g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, getWidth() - padding, getHeight() - padding - labelPadding); Stroke oldStroke = g2.getStroke(); g2.setColor(lineColor); g2.setStroke(GRAPH_STROKE); for (int i = 0; i < graphPoints.size() - 1; i++) { double x1 = graphPoints.get(i).x; double y1 = graphPoints.get(i).y; double x2 = graphPoints.get(i + 1).x; double y2 = graphPoints.get(i + 1).y; g2.draw(new Line2D.Double(x1, y1, x2, y2)); } g2.setStroke(oldStroke); g2.setColor(pointColor); for (int i = 0; i < graphPoints.size(); i++) { double x = graphPoints.get(i).x - pointWidth / 2; double y = graphPoints.get(i).y - pointWidth / 2; int ovalW = pointWidth; int ovalH = pointWidth; //g2.fillOval(x, y, ovalW, ovalH); } } public void findNearPoint(double x, double y) { double delta = 0; for (int j = 0; j < graphPoints.size(); j++) { double sx = graphPoints.get(j).x; double sy = graphPoints.get(j).y; double root = sqrt((x-sx)*(x-sx) + (y-sy)*(y-sy)); if (j == 0) { delta = root; serieX = sx; } else if (root < delta) { serieX = sx; delta = root; } } } public void editSerie(double x, double y) { double tmpSerieX = serieX; int ind = 0; for (int i = 0; i < graphPoints.size(); i++) { if (graphPoints.get(i).x == tmpSerieX) { ind = i; } } graphPoints.remove(ind); graphPoints.add(ind, new Point2D.Double(x, y)); serieX = x; } private double getMinScore() { double minScore = Double.MAX_VALUE; for (Double score : scores) { minScore = Math.min(minScore, score); } return minScore; } private double getMaxScore() { double maxScore = Double.MIN_VALUE; for (Double score : scores) { maxScore = Math.max(maxScore, score); } return maxScore; } public void setScores(List<Double> scores) { this.scores = scores; invalidate(); this.repaint(); } public List<Double> getScores() { return scores; } private static void createAndShowGui() { List<Double> scores = new ArrayList<>(); Random random = new Random(); int maxDataPoints = 40; int maxScore = 10; for (int i = 0; i < maxDataPoints; i++) { scores.add((double) random.nextDouble() * maxScore); } SimpleGrapher2 mainPanel = new SimpleGrapher2(scores); mainPanel.setPreferredSize(new Dimension(800, 600)); JFrame frame = new JFrame("DrawGraph"); 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(); } }); } }
解决方案The problem is in your constructor when you calculate the
x/yScale
...public SimpleGrapher2(List<Double> scores) { //... double xScale = ((double) getWidth() - (2 * padding) - labelPadding) / (scores.size() - 1); double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore()); //... }
At the point the component is constructed, the components size is
0x0
. You need to wait until the component is resized in some meaningful way before calculating the points...This is also problematic, as the component may be resized a number of times, in quick succession, when it is first realised onto the screen.
What I've done in the past is used a Swing
Timer
set to a smallish delay to allow the component to be resized a number of times over a small time scale. Once it's all settled down, theTimer
will trigger and you can perform you required operations, for example...public SimpleGrapher2(List<Double> scores) { //... addComponentListener(new ComponentAdapter() { private Timer initTimer = new Timer(200, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { initTimer.stop(); double xScale = ((double) getWidth() - (2 * padding) - labelPadding) / (scores.size() - 1); double yScale = ((double) getHeight() - 2 * padding - labelPadding) / (getMaxScore() - getMinScore()); graphPoints = new ArrayList<>(); for (int i = 0; i < scores.size(); i++) { double x1 = (double) (i * xScale + padding + labelPadding); double y1 = (double) ((getMaxScore() - scores.get(i)) * yScale + padding); graphPoints.add(new Point2D.Double(x1, y1)); } repaint(); } }); @Override public void componentResized(ComponentEvent e) { if (graphPoints == null) { initTimer.restart(); } } }); }
All this does is waits until the timer between the
compoentResized
event is more then 200 milliseconds (you can play with this value to get it closer to what you want, but I've found roughly 250 milliseconds to be a reasonable delay)You will need to correct the
paintComponent
to allow forgraphPoints
beennull
as well.这篇关于Java Swing - 重绘()无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!