java - 如果窗口大小调整,JLabel 会复制自身

标签 java swing user-interface jlabel

我正在编写一个简单的图表,您可以使用它来显示 x、y 轴上的一些点。

public class GraphPlotter extends JPanel {

    private static final long serialVersionUID = 1L;

    /** Default frame size X for frame in pixels */
    private final int DEFAULT_FRAME_SIZE_X = 800;
    /** Default frame size Y for frame in pixels */
    private final int DEFAULT_FRAME_SIZE_Y = 600;
    /** Padding to Frame */
    private final int PAD = 30;
    /** Radius of dot */
    private final int DOT_RADIUS = 3;
    /** Padding of label */
    private final int LABEL_PAD = 10;
    /** Height of label */
    private final int LABEL_HEIGHT = 10;
    /** Width of label */
    private final int LABEL_WIDTH = 100;

    /** Max value for x to print */
    private int maxValueForX;
    /** Scale factor depending to y*/
    private int maxValueForY;
    /** Label for the x axis */
    private String labelForX = "time";
    /** Label for the y axis */
    private String labelForY;

    /**
     * List with points to draw. It holds the y coordinates of points. x
     * coordinates are spaced
     */
    private List<Integer> dataPoints = new ArrayList<>();

    /**
     * 
     * Constructor of this class
     * 
     */
    public GraphPlotter(ArrayList<Integer> dataPoints, String labelForY) {
        this.dataPoints = dataPoints;
        this.maxValueForX = dataPoints.size();
        this.maxValueForY = Collections.max(dataPoints);
        this.labelForY = labelForY;

        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().add(this);
        f.setSize(this.DEFAULT_FRAME_SIZE_X + PAD, this.DEFAULT_FRAME_SIZE_Y + PAD);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    /** method that draws the points and lines between the points */
    @Override
    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();

        // add labels
        JLabel jLabelY = new JLabel(labelForY);
        JLabel jLabelX = new JLabel(labelForX);

        jLabelY.setSize(LABEL_WIDTH, LABEL_HEIGHT);
        jLabelY.setLocation(LABEL_PAD, LABEL_PAD);
        add(jLabelY);

        jLabelX.setSize(LABEL_WIDTH, LABEL_HEIGHT);
        jLabelX.setLocation(w - LABEL_WIDTH - LABEL_PAD, h - LABEL_HEIGHT - LABEL_PAD);
        jLabelX.setHorizontalAlignment(SwingConstants.RIGHT);
        add(jLabelX);

        // add axis
        g2.drawLine(PAD, PAD, PAD, h - PAD);
        g2.drawLine(PAD, h - PAD, w - PAD, h - PAD);

        double xScale = (w - 2 * PAD) / (dataPoints.size() + 1);
        double yScale = (h - 2 * PAD) / this.maxValueForY;

        int x0 = PAD;
        int y0 = h - PAD;

        // draw the points as small circles
        g2.setPaint(Color.blue);
        for (int i = 0; i < dataPoints.size(); i++) {
            int x = x0 + (int) (xScale * (i + 1));
            int y = y0 - (int) (yScale * dataPoints.get(i));
            g2.fillOval(x - DOT_RADIUS, y - DOT_RADIUS, 2 * DOT_RADIUS,
                    2 * DOT_RADIUS);
        }
    }


    /** Size of List */
    private int getSizeOfDataPoints() {
        return dataPoints.size();
    }

    /** Deletes last DataPoint in List */
    private void deleteLastDataPoint() {
        dataPoints.remove(0);
    }

    /**
     * Ad point and repaint graph.
     * 
     * @param point to draw (y-coord)
     */
    public void add(int point) {
        if (getSizeOfDataPoints() > this.maxValueForX) {
            deleteLastDataPoint();
        }
        dataPoints.add(point);
        this.repaint();
    }

    public static void main(String[] args) {
        ArrayList<Integer> scores = new ArrayList<>();
        Random random = new Random();

        for (int i = 0; i < 50; i++) {
            scores.add(random.nextInt(10));
        }

        String labelForY = "throughput";

        GraphPlotter graphPlotter = new GraphPlotter(scores, labelForY);
        graphPlotter.add(5);
    }

标签在应用程序启动时显示。如果我调整应用程序窗口的大小,标签将显示在整个窗口上。 (见截图)

before resizing

after resizing

如何避免标签重复? 我假设,在重新绘制窗口后,程序在面板中添加相同的标签。如果我写

add(jLabelY);
repaint();

paintComponent() 方法中,此错误在应用程序启动时发生。 我还尝试将面板放入 FlowLayout 中,但没有进行任何更改。

最佳答案

Swing 几乎可以在任意时间调用

paintComponent()(每当需要重新绘制组件时;例如调整大小时)。因此,它通常应该是无副作用的。但是,您可以使用 paintComponentadd() 标签作为面板的子项,而永远不会删除它。因此,每次重新绘制面板时,都会向其子面板添加两个标签。然后 super.paintComponent() 将把它们全部绘制出来。

对此的一种解决方案是将两个标签保留为面板的字段,并且仅更新它们在 paintComponent 中的位置(在调用 super.paintComponent() 之前)

关于java - 如果窗口大小调整,JLabel 会复制自身,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53151520/

相关文章:

java - 如何查找字符串的所有子词

java - 400 错误请求 - 将 JSON 数据发布到使用 Spring MVC 实现的 RESTful Controller 时

java - 如何将一个数组设置为另一个数组的相同排序?

java - 使用 JTextField 从用户获取正则表达式。如何让它显示为选项卡而不是后跟 t

java - 这个关键字如何访问类的私有(private)成员,而类本身的对象却不能

java - 设置drawString,使(0,0)位于绘图区域内

java - 最小化除我自己的程序以外的所有其他应用程序

javascript - 如何在鼠标悬停期间反转黑色以使其可见?

Java 图形用户界面计算器

javascript - Chrome 移动设备上 FB.ui 提要对话框中的空白页面