Java Swing 中的图形绘制仅绘制点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17536229/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Graph plotting in Java Swing only draws points
提问by user1209014
I'm currently working on a program where certain numerical variables, which evolve over time, have their value displayed on each iteration. That works well enough, but now I want to plot a graph that shows their evolution over time. So, I looked into an example of code for plotting graphs in Swing. My final code looks like this:
我目前正在开发一个程序,其中某些随时间演变的数值变量在每次迭代中都显示其值。这很有效,但现在我想绘制一个图表来显示它们随时间的演变。所以,我研究了一个在 Swing 中绘制图形的代码示例。我的最终代码如下所示:
public class Populus3 extends JPanel
{
public static void main(String[] args) throws IOException {
final Populus3 pop = new Populus3();
JFrame f = new JFrame(); //where I want to plot the graph
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new GraphingData());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
frame = new JFrame("Animation Frame"); //where I'm running animation for another element of the program
frame.add(pop, BorderLayout.CENTER);
frame.setSize(graphSize, graphSize);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//insert all sort of things
}
public void paint(Graphics g)
{
super.paint(g);
paintCell(g, 1);
Toolkit.getDefaultToolkit().sync(); // necessary for linux users to draw and animate image correctly
g.dispose();
}
public void actionPerformed(ActionEvent e) {
repaint();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i = 0; i < particleType.length; i++)
paintCell(g, i); //a method that draws a small circle for the animation panel
}
public static class GraphingData extends JPanel {
int[] data = {
21, 14, 18, 03, 86, 88, 74, 87, 54, 77,
61, 55, 48, 60, 49, 36, 38, 27, 20, 18
};
final int PAD = 20;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
// Draw ordinate.
g2.draw(new Line2D.Double(PAD, PAD, PAD, h-PAD));
// Draw abcissa.
g2.draw(new Line2D.Double(PAD, h-PAD, w-PAD, h-PAD));
double xInc = (double)(w - 2*PAD)/(data.length-1);
double scale = (double)(h - 2*PAD)/getMax();
// Mark data points.
g2.setPaint(Color.red);
for(int i = 0; i < data.length; i++) {
double x = PAD + i*xInc;
double y = h - PAD - scale*data[i];
g2.fill(new Ellipse2D.Double(x-2, y-2, 4, 4));
}
}
private int getMax() {
int max = -Integer.MAX_VALUE;
for(int i = 0; i < data.length; i++) {
if(data[i] > max)
max = data[i];
}
return max;
}
}
}
Now, the animation panel works just fine. The graph panel, on the other hand...when I run the program, it displays a bunch of red dots, without lines to connect them. What am I doing wrong?
现在,动画面板工作正常。另一方面,图形面板......当我运行程序时,它显示一堆红点,没有线来连接它们。我究竟做错了什么?
回答by trashgod
In addition to @Hovercraft's helpful suggestions, also consider these other approaches:
除了@Hovercraft 的有用建议之外,还可以考虑以下其他方法:
- Accumulate the points in a
GeneralPath
that may be rendered as required, for example.
- 累积 a
GeneralPath
中可以根据需要渲染的点,例如。
- Connect the points using repeated calls to
drawLine()
using a suitable coordinate system, outlined here.
- 使用重复调用将点连接到
drawLine()
使用合适的坐标系,此处概述。
- Look at
JFreeChart
.
- 看看
JFreeChart
。
回答by Hovercraft Full Of Eels
Your code confuses me:
你的代码让我困惑:
- You override both paint and paintComponent for your Populus3 JPanel -- why? You should only override paintComponent unless you absolutely have to have your drawing affect a component's children and borders.
- You dispose of the Graphics object passed into paint -- a verydangerous thing to do. You should never dispose of a Graphics object given to you by the JVM, only Graphics objects that you yourself create.
- You repeatedly call a method not defined here for us,
paintCell(...)
. - I've never heard of the need for
Toolkit.getDefaultToolkit().sync();
for Swing applications. Do you have a reference for this need? - You mention "animation" but I see no animation code.
- In your GraphingData class's paintComponent method you fill ellipses in your for loop, but you don't connect them with lines ever, so it shouldn't be surprising that you're only seeing dots in your graph and no lines.
- 您为 Populus3 JPanel 覆盖了paint 和paintComponent -- 为什么?您应该只覆盖paintComponent,除非您绝对必须让您的绘图影响组件的子项和边框。
- 您处理了传递给paint 的Graphics 对象——这是一件非常危险的事情。您永远不应该处理 JVM 提供给您的 Graphics 对象,只能处理您自己创建的 Graphics 对象。
- 您反复调用此处未为我们定义的方法,
paintCell(...)
。 - 我从未听说过需要
Toolkit.getDefaultToolkit().sync();
Swing 应用程序。你有这个需求的参考吗? - 你提到了“动画”,但我看不到动画代码。
- 在您的 GraphingData 类的 paintComponent 方法中,您在 for 循环中填充椭圆,但您永远不会用线将它们连接起来,因此您在图形中只看到点而没有线也就不足为奇了。
Consider isolating your problem more and posting an sscce, a minimal test program that we can compile, run, modify and correct and that shows us your problem, but has no extra code not related to the problem or required for demonstration.
考虑更多地隔离您的问题并发布sscce,这是一个我们可以编译、运行、修改和更正的最小测试程序,它向我们展示了您的问题,但没有与问题无关或演示所需的额外代码。
回答by herrtim
The following code demonstrates a real-time Java chart using XChartwhere the line is updated as the data evolves over time. Creating real-time charts is as simple as calling updateXYSeries
for one or more series objects through the XYChart
instance and triggering a redraw of the JPanel
containing the chart. This works for all chart types including XYChart
, CategoryChart
, BubbleChart
and PieChart
, for which example source code can be found here: https://github.com/timmolter/XChart/tree/develop/xchart-demo/src/main/java/org/knowm/xchart/demo/charts/realtime. Examples demonstrate using the SwingWrapper
with repaintChart()
method as well as XChartPanel
with revalidate()
and repaint()
. Disclaimer, I'm the main developer of the XChart library.
以下代码演示了一个使用XChart的实时 Java 图表,其中线条随着数据的变化而更新。创建实时图表就像updateXYSeries
通过XYChart
实例调用一个或多个系列对象并触发JPanel
包含图表的重绘一样简单。这适用于所有图表类型包括XYChart
,CategoryChart
,BubbleChart
和PieChart
,对此示例源代码可以在这里找到:https://github.com/timmolter/XChart/tree/develop/xchart-demo/src/main/java/org/knowm /xchart/demo/charts/realtime。示例演示如何使用SwingWrapper
withrepaintChart()
方法以及XChartPanel
withrevalidate()
和repaint()
。免责声明,我是 XChart 库的主要开发者。
public class SimpleRealTime {
public static void main(String[] args) throws Exception {
double phase = 0;
double[][] initdata = getSineData(phase);
// Create Chart
final XYChart chart = QuickChart.getChart("Simple XChart Real-time Demo", "Radians", "Sine", "sine", initdata[0], initdata[1]);
// Show it
final SwingWrapper<XYChart> sw = new SwingWrapper<XYChart>(chart);
sw.displayChart();
while (true) {
phase += 2 * Math.PI * 2 / 20.0;
Thread.sleep(100);
final double[][] data = getSineData(phase);
chart.updateXYSeries("sine", data[0], data[1], null);
sw.repaintChart();
}
}
private static double[][] getSineData(double phase) {
double[] xData = new double[100];
double[] yData = new double[100];
for (int i = 0; i < xData.length; i++) {
double radians = phase + (2 * Math.PI / xData.length * i);
xData[i] = radians;
yData[i] = Math.sin(radians);
}
return new double[][] { xData, yData };
}
}
This results in the following Java Swing real-time chart app: