用 Java 创建一个简单的条形图 - 读取数据并输出条形图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29873878/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:04:12  来源:igfitidea点击:

Creating a Simple Bar Chart in Java - Reads Data and Outputs Bar Graph

javaswinggraphjpaneljoptionpane

提问by smarino

Im required to create a simple bar chart for one of my projects. This program requires an input of 1 to 9 integers that are greater than zero. The program is then required to display a very simple bar graph with the integers displayed above the bars. My professor did not explain this program very well to me and this is the first time working with graphics.

我需要为我的一个项目创建一个简单的条形图。该程序需要输入 1 到 9 个大于零的整数。然后程序需要显示一个非常简单的条形图,条形上方显示整数。我的教授没有很好地向我解释这个程序,这是第一次使用图形。

The program requires:

该计划要求:

A class "SimpleBarChart" (which will extend Frame) with private variables Bar[] bars and int [] inputData among others (like private Graphics g, private int windowWid, windowHt, etc) and the following functions. It also uses an auxiliary class Bars as shown:

一个类“SimpleBarChart”(将扩展框架),具有私有变量 Bar[] bar 和 int [] inputData 等(如私有 Graphics g、私有 int windowWid、windowHt 等)和以下函数。它还使用辅助类 Bars,如图所示:

class Bar
{ public int height, width, value, nix, nwy;
  public Bar() {}
  public Bar(int height, int width, int value, int nix, int nwy)
  { this.height = height; etc }
}

Next a constructor SimpleBarChart(), which calls readData(), createBars(), and drawBars().

接下来是构造函数 SimpleBarChart(),它调用 readData()、createBars() 和 drawBars()。

A function private void readData(), which reads inputData for the bar-chart. Use the code given below, which uses JOptionPane.

一个函数 private void readData(),它读取条形图的 inputData。使用下面给出的代码,它使用 JOptionPane。

A function private void createBars() to create the bars array on assigning width, height, value (bars[i].value = inputData[i]), nix, and nwy of each bar. Requires 25 pixels of space on top and bottom of the display-window, 10 pixels between the bars, and has to allow bar-heights to be scaled to the form of inputData items.

一个函数 private void createBars() 在分配每个条的宽度、高度、值 (bars[i].value = inputData[i])、nix 和 nwy 时创建条数组。显示窗口的顶部和底部需要 25 个像素的空间,条形之间有 10 个像素,并且必须允许条形高度缩放为 inputData 项的形式。

Finally a function private void drawBars() to draw the bars, one at a time with a suitable sleep-time between bars, with two different colors. Requires the use of g.drawString("" +b.value, nix + b.width/2, nwy - 10) to label each bar in black b its value at 10 pixel above its top.

最后是一个函数 private void drawBars() 来绘制条,一次一个,条之间有合适的睡眠时间,有两种不同的颜色。需要使用 g.drawString("" +b.value, nix + b.width/2, nwy - 10) 以黑色标记每个条形 b 其顶部上方 10 像素处的值。

Ive been trying to figure this out all day and I'm lost. Any help would be greatly appreciated!

我一整天都在试图弄清楚这一点,但我迷路了。任何帮助将不胜感激!

Heres what code I have so far:

这是我到目前为止的代码:

package simplebarchart;

import java.awt.*;
import java.awt.event.*;
import java.awt.Toolkit.*;
import javax.swing.*;
import java.io.*;
import java.util.*;


public class SimpleBarchart extends JFrame
{
    private final int OUTER_MARGIN = 20;
    private static final Color BACKGROUND_COLOR = Color.white;
    private static final Color BAR_COLOR = Color.red; 
    private int SPACE_ON_LEFT_RIGHT;
    private Image fImageBuffer;
    private Insets fInsets;
    private Graphics g;
    private Bar[] bars;
    private static int SLEEP = 500;
    private int[] inputData;


class Bar
{
    private int height, value;
    public int width;
    public int nwx;
    public int nwy;
    public Color color;

    public Bar() {}
    public Bar(int height, int width, int value, int nwx, int nwy)
    {
        this.height = height;
        this.width = width; 
        this.value = value; 
        this.nwx = nwx;
        this.nwy = nwy;
    }

}


public SimpleBarchart(final int[] inputData)
{
    this.inputData = inputData;
    addWindowListener(new WindowCloser());
    fInsets = getInsets();
    setSize(WIDTH + fInsets.left + fInsets.right, HEIGHT + fInsets.top + fInsets.bottom);
    setTitle("Bar Chart");
    if (((fImageBuffer = createImage(WIDTH, HEIGHT)) == null) ||
            ((g = fImageBuffer.getGraphics()) == null))
            System.exit(1);
    readData();
    createBars();
    getContentPane().add(new SimpleBarchart(inputData), BorderLayout.CENTER);
    setVisible(true);
}

/**
 *
 * @param g
 */
protected void paintComponent(final Graphics g) {
    g.drawImage(fImageBuffer, fInsets.left, fInsets.top, null);
}

class WindowCloser extends WindowAdapter
{
    @Override
    public void windowClosing(WindowEvent e)
    {
        System.exit(0);
    }
}

private void readData()
{
    String[] inputItems = JOptionPane.showInputDialog("Enter 1 to 9 integers > 0").trim().split(" +");
    int numData = inputItems.length;
    inputData = new int[numData];

    for (int itemIndex = 0; itemIndex < inputItems.length; itemIndex++)
        inputData[itemIndex] = numData;


}

private void createBars()
{

//Im confused on how to create the bars for this program. 
//This function requires 25 pixels of space on top and bottom of the display-    window, 10 pixels between the bars, and has to allow bar-heights to be **scaled to the form of inputData items.** 

    Bar[] bars = new Bar[];
    int pixelBetweenBars = 25;
    int width = 800 + 2*OUTER_MARGIN;
    int height = 600 + 2*OUTER_MARGIN;

}

private void drawBars(final Graphics g)
{
            int OUTER_MARGIN = 20,
            WIDTH = 800 + 2 * OUTER_MARGIN,
            HEIGHT = 600 + 2 * OUTER_MARGIN;


    g.setColor(BACKGROUND_COLOR);
    g.fillRect(0, 0, WIDTH, HEIGHT);

    g.setColor(BAR_COLOR);
    final int barWidth = 20;
    for (int itemIndex = 0; itemIndex < inputData.length; itemIndex++) {
        final int x = OUTER_MARGIN + 25 * itemIndex;
        final int barHeight = 10 * inputData[itemIndex];
        final int y = barHeight;
        g.fillRect(x, y, barWidth, barHeight);
    }
}


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

回答by Freek de Bruijn

I agree with Uttesh Kumarthat JFreeChartis an excellent chart library and it really pays off to invest time into learning it. But since you are doing this project to learn more about graphics, it is probably better to code the drawing yourself.

我同意Uttesh Kumar 的观点,即JFreeChart是一个出色的图表库,花时间学习它确实值得。但是由于您正在做这个项目是为了了解更多关于图形的知识,最好自己编写绘图代码。

First a few general remarks:

首先是一些一般性的评论:

  • the Barclass is defined two times and both implementations are not used yet;
  • the createImage([...], [...]).getGraphics()construction looks rather exotic;
  • the readDatamethod reads a space separated list of numbers, allocates memory, but does not store the numbers (you could use the Barclass here);
  • the createBarsmethod currently declares three local variables that are not used yet (and does nothing else).
  • 这个Bar类被定义了两次,但两个实现都没有使用;
  • createImage([...], [...]).getGraphics()建筑看上去颇为奇特的;
  • readData方法读取以空格分隔的数字列表,分配内存,但不存储数字(您可以在Bar此处使用该类);
  • createBars方法当前声明了三个尚未使用的局部变量(并且不执行任何其他操作)。

As shown in the Performing Custom Paintingtutorial that was already recommended by MadProgrammer, a common approach to custom painting is by subclassing the JPanelclass and overriding the paintComponentmethod. Studying this short tutorial will get you up to speed pretty quickly, so I really agree with this recommendation!

MadProgrammer推荐的执行自定义绘画教程中所示,自定义绘画的常用方法是将类子类化并覆盖方法。学习这个简短的教程会让你很快上手,所以我真的同意这个建议!JPanelpaintComponent

In the readDatamethod, you could add a few lines to store the numbers (and switch to using the Barclass later):

在该readData方法中,您可以添加几行来存储数字(Bar稍后切换到使用该类):

for (int itemIndex = 0; itemIndex < inputItems.length; itemIndex++)
    inputData[itemIndex] = [...get a number from the inputItems string here...];

After the call to readDatain the constructor, you could add:

readData构造函数中调用后,您可以添加:

getContentPane().add(new SimpleBarPanel(inputData), BorderLayout.CENTER);
setVisible(true);

This uses a new SimpleBarPanelclass that takes care of the custom painting. (The call to setVisibleshould go last if you want the SimpleBarPanelpainting to be shown.)

这使用了一个SimpleBarPanel负责自定义绘画的新类。(setVisible如果你想展示这SimpleBarPanel幅画,应该最后调用。)

The SimpleBarPanelclass could look like this:

SimpleBarPanel类看起来是这样的:

import java.awt.*;
import javax.swing.*;

public class SimpleBarPanel extends JPanel {
    private static final Color BACKGROUND_COLOR = Color.white;
    private static final Color BAR_COLOR = Color.red;

    private int[] inputData;

    public SimpleBarPanel(final int[] inputData) {
        this.inputData = inputData;
    }

    @Override
    protected void paintComponent(final Graphics g) {
        super.paintComponent(g);

        drawBars(g);
    }

    private void drawBars(final Graphics g) {
        int /*i,*/ OUTER_MARGIN = 20,
                WIDTH = 800 + 2 * OUTER_MARGIN,
                HEIGHT = 600 + 2 * OUTER_MARGIN;
                /*SPACE_BETWEEN_BARS = 10, SPACE_ON_TOP_BOTTOM = 25;*/

        g.setColor(BACKGROUND_COLOR);
        g.fillRect(0, 0, WIDTH, HEIGHT);

        g.setColor(BAR_COLOR);
        final int barWidth = 20;
        for (int itemIndex = 0; itemIndex < inputData.length; itemIndex++) {
            final int x = OUTER_MARGIN + 25 * itemIndex;
            final int barHeight = 10 * inputData[itemIndex];
            final int y = [...y is calculated using barHeight; the higher the bar, the lower y should be...];
            g.fillRect(x, y, barWidth, barHeight);
        }
    }
}

Good luck with your project.

祝你的项目好运。