为啥我的组件一遍又一遍地重新绘制而没有发生任何变化?

Posted

技术标签:

【中文标题】为啥我的组件一遍又一遍地重新绘制而没有发生任何变化?【英文标题】:Why is my Component repainted over and over without any changes happening?为什么我的组件一遍又一遍地重新绘制而没有发生任何变化? 【发布时间】:2018-07-01 10:02:42 【问题描述】:

我有一个初学 Swing/AWT 问题要问你。

我正在对扩展 JPanelBoxPanel 对象进行自定义绘制。 我有这些BoxPanels 中的n,然后使用FlowLayout 在称为FormSolutionViewerJFrame 中绘制。 现在我遇到的问题是,在创建 JFrame 并使其可见后,它会在无限循环中重新绘制,组件不会发生任何变化。有人可以向我解释这是为什么以及如何解决它,以便仅在调整窗口大小或某些数据实际更改时才重新绘制?

public class BoxPanel extends JPanel 

    private Box box;
    private int scaleFactor;

    public BoxPanel(Box box, int scaleFactor) 
        super();
        this.box = box;
        this.scaleFactor = scaleFactor;
        this.setLayout(null);   // Use null layout for absolute positioning
    

    /**
     * Need to override getPreferredSize() when using a FlowLayout
     */
    @Override
    public Dimension getPreferredSize() 
        return new Dimension(this.box.getLength() * this.scaleFactor, this.box.getLength() * this.scaleFactor);
    

    /**
     * Paint the box border, background and its rectangles
     * @param g
     */
    public void paintComponent(Graphics g)
    
        super.paintComponent(g);
        this.setBackground(Color.white);

        // Display no. of rectangles contained in tooltip
        this.setToolTipText("Box contains " + this.box.getRectangles().size() + " rectangles");

        // Draw border of box
        this.setBorder(BorderFactory.createLineBorder(Color.black));

        /* Draw rectangles contained in box */
        int i = 1;
        for (Rectangle rect : box.getRectangles()) 
            System.out.println("Rectangle " + i + ": " + rect.toString());

            g.setColor(Color.BLACK); // Set color for border
            g.drawRect(rect.getPos().getX() * this.scaleFactor, rect.getPos().getY() * this.scaleFactor, 
                    rect.getWidth() * this.scaleFactor, rect.getHeight() * this.scaleFactor);               
            i++;
        

    



public class FormSolutionViewer extends JFrame 

    private JPanel contentPane;
    private FeasibleSolution solution;

    int scaleFactor = 40;
    int spacing = 5;

    /**
     * Create the frame.
     */
    public FormSolutionViewer(FeasibleSolution solution, int x, int y, int dpi) 
        this.solution = solution;

        this.scaleFactor = (int) Math.round(dpi / 2.4);

        setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        setBounds(x, y, 800, 600);
        setTitle("Initialized Solution of " + solution.getInstance().toString());
        this.setBackground(new Color(250, 250, 250));

        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(spacing, spacing, spacing, spacing));

        FlowLayout layout = new FlowLayout(FlowLayout.LEADING, 5, 5);
        contentPane.setLayout(layout);
        this.setContentPane(contentPane);

        /* Place the boxes */
        int boxNo = 0;
        int rowCount = 0;
        for (Box box : solution.getBoxes()) 
            boxNo++;

            BoxPanel boxPanel = new BoxPanel(box, scaleFactor);
            contentPane.add(boxPanel);
            contentPane.setSize(this.getWidth(), 500); 
            boxPanel.setVisible(true);
        
    

【问题讨论】:

什么“无限循环”在哪里?您的代码仅显示两个非无限 for 循环。这个未显示的无限循环是否尊重 Swing 线程规则? 抱歉,我的措辞可能不太好。没有无限循环,我的意思是框架会不断重新绘制。对于小问题,每秒数百次。这是否使它更清晰? 为什么 JFrame 会不断重绘?是什么代码推动了这一点——再次我在上面的代码中没有看到这一点。你在哪里创建 JFrame?请创建并发布有效的minimal reproducible example。 【参考方案1】:
this.setBackground(Color.white);
...
this.setToolTipText("Box contains " + this.box.getRectangles().size() + " rectangles");
...
this.setBorder(BorderFactory.createLineBorder(Color.black));

不要在绘画方法中设置组件的属性。当组件的属性发生变化时,Swing 会在组件上调用 revalidate()/repaint() 以反映组件的新状态。

绘制方法的重点是将组件绘制为当前状态,而不是改变其状态。

【讨论】:

好的,谢谢!我应该自己想出来的。现在按预期工作,我学到了重要的一课。 :)

以上是关于为啥我的组件一遍又一遍地重新绘制而没有发生任何变化?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 OnPreRender 被一遍又一遍地调用?

为啥这不会一遍又一遍地返回一个新值?爪哇

为啥我的 axios 使用 React.useEffect 一遍又一遍地从 Rails 后端获取调用?

为啥在反应的“useState”钩子中一遍又一遍地设置初始状态

Google Cloud Run 一遍又一遍地错误运行

Listview一遍又一遍地只显示最后一项