【问题标题】:JPanel removing component and adding a new one offsets the new componentJPanel 删除组件并添加新组件会抵消新组件
【发布时间】:2022-01-11 19:01:19
【问题描述】:

我正在开发一个求解器,通过生成地形图来说明 Nelder Mead 算法。该地图由 JPanel 组件直观地表示(我知道该地图没有像我想要的那样清晰地生成,但这是另一个问题)。我拥有的一个按钮应该通过从容器 JPanel 中删除旧组件并添加新组件来生成新地图;然而,虽然它确实绘制了一个新地图,但它显示它偏移了组件高度的一半。以下是 Regenerate 被击中之前和之后的图像。

初始地图图片

点击重新生成按钮后,新地图会显示在 y 偏移处

这是我的主要代码(画布对象扩展了 JPanel):

public void init() {
        frame = new JFrame("Nelder Mead");
        container = new JPanel();

        solveButton = new JButton("Solve");
        solveButton.setToolTipText("Solves the given Height Map using the Nelder Mead algorithm.");
        resetButton = new JButton("Reset");
        resetButton.setToolTipText("Resets the simplex to its initial position.");
        reconfigureButton = new JButton("Reconfigure");
        reconfigureButton.setToolTipText("Reconfigures the simplex's initial position.");
        regenerateButton = new JButton("Regenerate");
        regenerateButton.setToolTipText("Generates a new Height Map and a new simplex.");

        buttonPanel = new JPanel();
        buttonPanel.setBackground(Color.WHITE);
        buttonPanel.setPreferredSize(BUTTON_SIZE);
        buttonPanel.add(solveButton);
        buttonPanel.add(resetButton);
        buttonPanel.add(reconfigureButton);
        buttonPanel.add(regenerateButton);

        canvas = new Canvas(new HeightMap(CANVAS_WIDTH, CANVAS_HEIGHT, TILE_WIDTH, TILE_HEIGHT, ELEVATION_MAX, ELEVATION_MIN));
        canvas.setPreferredSize(CANVAS_SIZE);

        container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
        container.add(buttonPanel);
        container.add(canvas);

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.add(container);
        frame.pack();
        frame.setVisible(true);
    }

    public void run() {
        init();

        regenerateButton.addActionListener(event -> {
            running = false;
            container.remove(canvas);
            canvas = new Canvas(new HeightMap(CANVAS_WIDTH, CANVAS_HEIGHT, TILE_WIDTH, TILE_HEIGHT, ELEVATION_MAX, ELEVATION_MIN));
            container.add(canvas);
            frame.revalidate();
        });
    }

如果有人能指出我正确的方向,不胜感激,谢谢。

【问题讨论】:

  • 不要一直在面板中添加/删除组件。相反,您可以创建一个 reset() 方法来重置面板的所有属性并重新绘制。
  • 我会考虑使用BorderLayout 而不是BoxLayoutrevalidaterepaint container 而不是 frame。小心使用setPreferredSize,尤其是在使用文本的组件上
  • @camickr 非常感谢您的建议,完美解决了问题!

标签: java swing graphics jpanel graphics2d


【解决方案1】:

我能够将 camickr 关于 reset() 方法的提示应用到我的代码中,从而解决了我的问题。建议是在组件类中进行所有组件编辑,而不是尝试修改组件在 JPanel 中的存在方式。我还更改了画布对象以扩展 JComponent。对于将来遇到此问题的任何人,这里是解决方案:

regenerateButton.addActionListener(event -> {
            running = false;
            canvas.regenerate(CANVAS_WIDTH, CANVAS_HEIGHT, TILE_WIDTH, TILE_HEIGHT, ELEVATION_MAX, ELEVATION_MIN);
        });

[编辑]regenerate()修改画布的HeightMap对象并调用this.repaint()

【讨论】:

  • repaint() 方法应该是regenerate(....) 方法的一部分。也就是说,当属性发生变化时,组件应该重新绘制自己。就像在 JLabel 上使用 setText(....),你不需要调用 repaint()。
  • @camickr,明白了,再次感谢!
猜你喜欢
  • 1970-01-01
  • 2011-12-23
  • 1970-01-01
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-08
  • 1970-01-01
  • 2018-11-19
相关资源
最近更新 更多