【问题标题】:How to repaint GUI after a certain element was removed?删除某个元素后如何重新绘制 GUI?
【发布时间】:2013-05-04 12:54:06
【问题描述】:

我正在制作一个应用程序,用户可以在其中向屏幕添加或删除按钮(我还没有实现这些选项)。所以,现在我用 for() 循环手动填充它并手动删除其中一个按钮。我的问题是,在按钮被移除后(main() 中的移除操作),只有一个空白点。我希望在删除其中一个按钮后能够重新绘制屏幕。在这个例子中,索引 2(块#3)已被删除,留下一个空白空间,它在以前的位置......我不知道如何重新绘制它。我尝试从程序中的不同位置验证或重新绘制,但没有成功。

这是代码(PS我确定我的代码不是完成我想要的工作的最有效方法,我正在使用 setLayout(null),这不是首选方法,但现在我只是想学习某些东西,然后扩展它以改善我自己和我的代码):

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

class TestApp extends JFrame{
    JFrame frame = new JFrame("Test Program");
    ArrayList<JButton> grid = new ArrayList<JButton>();

    private int w = 14;
    private static int amount = 102;
    private static int counter = 0;

    //Default Constructor (sets up JFrame)
    TestApp(){ 
        frame.setLayout(null);
        frame.setPreferredSize(new Dimension(1186, 880));       
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.setResizable(false);
        paintGrid();
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public void newWindow()
    {
        JFrame select_win = new JFrame("Selected Frame");
        JPanel select_panel = new JPanel();
        select_panel.setPreferredSize(new Dimension(600, 800));
        select_panel.setBackground(Color.ORANGE);
        select_win.add(select_panel);
        select_win.pack();
        select_win.setResizable(false);
        select_win.setVisible(true);
        select_win.setLocationRelativeTo(null);
    }

    private void paintGrid()
    {   
        for(int i = 0, y = 4; i < ((amount / w) + (amount % w)); i++, y += 104)
        {
            for(int j = 0, x = 4; j < w && (counter < amount); j++, x += 84)
            {
                addBlock(counter, x, y);
                counter++;
            }
        }
    }

    //Adds a block
    private void addBlock(int index, int x, int y){
        int height = 100;
        int width = 80;

        grid.add(new JButton("counter: " + (counter + 1)));
        (grid.get(index)).addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                javax.swing.SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        newWindow();
                    }
                });
            }
        });
        (grid.get(index)).setBorder(new LineBorder(Color.BLACK));
        (grid.get(index)).setBackground(Color.YELLOW);
        (grid.get(index)).setVisible(true);
        (grid.get(index)).setBounds(x, y, width, height);

        frame.add(grid.get(index));
    }  

    //Removes a block
    private void removeBlock(int index){
        frame.remove(grid.get(index));
        grid.remove(index);
        amount--;
        counter--;
    }  

    public static void main(String [] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                TestApp app = new TestApp();

                //testing block removal
                app.removeBlock(2);
            }
        });
    }
}

【问题讨论】:

  • 查看A Visual Guide to Layout ManagersUsing Layout Managers 了解有关布局管理器的详细信息
  • @MadProgrammer 是的,瞄准它...仍然害怕,不知道为什么,哈哈
  • 布局管理器快速管理大量信息,一开始可能有点令人生畏,但要以终为始,不要害怕使用多种复合布局来实现自己的目标想要
  • @MadProgrammer 那么,如果我假设两个 JPanel 在 JFrame 中相互堆叠,那么每个 JPanel 都可以有自己的布局?
  • 是的,任何从Container(包括JPanel)扩展的东西都可以拥有自己的布局管理器...

标签: java swing jframe jpanel awt


【解决方案1】:

正确的方法是:revalidate()

revalidate() 方法通知布局管理器这个组件和它上面的所有父组件都被标记为需要布局。这意味着布局管理器将尝试重新对齐组件。经常在移除组件后使用。

我认为只有在实际使用 Swing 时你才会知道这一点

【讨论】:

  • 你会把它放在代码的什么地方?在我在 main 和 removeBlock 方法中尝试过之后,它对我不起作用。幸运的是,FlowLayout 很好地为我纠正了这个问题......仍然很好奇为什么没有布局管理器的帮助它不这样做。
  • 稍微更改了我的代码,我现在实际上正在使用您的建议。谢谢。
【解决方案2】:

如你所说,不好用NullLayout。要解决您的问题,您只需进行两项更改:

在构造函数上将布局更改为FlowLayout,如下所示:

 frame.setLayout(new FlowLayout());

setBounds 调用更改为setPreferredSize

(grid.get(index)).setPreferredSize(new Dimension(width, height));

现在FlowLayout 将自动对齐您的项目,您无需再担心了。

【讨论】:

  • 给出 X/Y 定位的使用,使用类似 GridBagLayout 的东西可能会更好,但可能需要小步骤。
  • 它实际上工作得非常好,而且我更喜欢这种布局,它很好地居中。 @MadProgrammer 嘿,是的,在您和其他一些人从我的另一个问题中提到 LayoutManager 之后,我正在关注 GridBagLayout。 :)
猜你喜欢
  • 2013-03-27
  • 1970-01-01
  • 1970-01-01
  • 2022-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-20
  • 2020-05-10
相关资源
最近更新 更多