Java Swing事件触发后如何重绘JPanel?repaint与revalidate无效求助
revalidate与repaint的作用说明
revalidate():触发组件的布局管理器重新计算布局,一般在添加/删除组件、修改组件大小位置后调用,会标记组件为需要重新布局,然后触发逐层校验更新。repaint():触发组件的重绘操作,只是向事件队列提交一个重绘请求,EDT线程会在合适的时机执行重绘,只会更新组件的外观,不会修改布局。
只有当组件的属性/布局确实发生了变化,调用这两个方法才会有肉眼可见的变化,如果组件本身内容没有变,调用这两个方法不会有任何效果。
你代码不生效的根因
- 时序逻辑错误:你使用普通
JFrame作为子窗口,默认是非模态的,创建ChildFrame的代码不会阻塞当前线程,你刚弹出子窗口就立刻执行了revalidate()+repaint(),此时用户还没输入内容点击OK,ArrayList还没被修改,自然看不到变化。 - 数据未同步到组件:你只修改了
ArrayList里存储的字符串,但是已经添加到big面板中的JLabel文本没有同步更新,Swing组件不会自动和你自定义的集合做数据绑定,集合内容变更不会自动触发组件属性更新,所以重绘还是展示旧内容。
修复方案
1. 修改ChildFrame为模态对话框
把ChildFrame的父类从JFrame改成JDialog,设置模态属性,这样会阻塞父窗口的代码执行,直到用户关闭子窗口后再执行后续逻辑。
2. 集合修改后同步更新JLabel内容
修改完集合后,清空面板原有组件后重新按照最新集合内容创建JLabel添加,或者遍历已有的JLabel更新对应文本。
修改后代码参考
ParentFrame.java
public class ParentFrame extends JFrame { private ArrayList<String> list = new ArrayList<>(){{add("test1"); add("test2");}}; JPanel big; public ParentFrame() { super("parent"); super.setSize(200,200); super.setLayout(new BorderLayout()); big = new JPanel(); // 单独抽成刷新方法,方便后续复用 refreshContent(); super.add(big, BorderLayout.CENTER); JButton edit = new JButton("EDIT"); edit.addActionListener(new EditListener()); super.add(edit, BorderLayout.SOUTH); setVisible(true); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void refreshContent() { // 先清空原有所有组件 big.removeAll(); for(int i=0; i<list.size(); i++) { JLabel content = new JLabel(); content.setText(list.get(i)); big.add(content); } } public ArrayList<String> getParentList() { return list; } public void setParentList(int i, String b) { this.list.set(i,b); } public class EditListener implements ActionListener { public void actionPerformed(ActionEvent e) { // 模态对话框会阻塞到用户关闭子窗口再往下执行 ChildDialog child = new ChildDialog(ParentFrame.this); // 子窗口关闭后再刷新内容 refreshContent(); big.revalidate(); big.repaint(); } } }
ChildDialog.java(原ChildFrame改名调整)
// 改为继承JDialog实现模态效果 public class ChildDialog extends JDialog { ArrayList<String> newList; // 构造方法第二个参数设为true代表模态 public ChildDialog(ParentFrame pF) { super(pF, true); super.setTitle("child"); super.setSize(100,100); super.setLayout(new BorderLayout()); newList = pF.getParentList(); JTextField edit = new JTextField(pF.getParentList().get(0)); add(edit, BorderLayout.CENTER); JButton ok = new JButton("OK"); ok.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { newList.set(0, edit.getText()); dispose(); } }); add(ok, BorderLayout.SOUTH); setVisible(true); setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); } }
Test.java无修改
public class Test { public static void main(String[] args) { ParentFrame pF = new ParentFrame(); } }
内容的提问来源于stack exchange,提问作者Flash-KIM142
相关产品推荐
相关产品推荐

