如果调整窗口大小,JLabel将复制自身

时间:2018-11-05 09:25:20

标签: 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,但未做任何更改。

1 个答案:

答案 0 :(得分:2)

paintComponent()几乎可以通过Swing调用(无论何时需要重新绘制组件;例如,在调整大小时)。因此,通常应无副作用。但是,您使用paintComponentadd()标签作为面板的子级,但从未删除。因此,每次重新绘制面板时,都会向其子级添加两个标签。 super.paintComponent()然后将它们全部绘制。

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