2012-10-13 53 views
2

我有摆动和更新JPanel几个按钮的问题。有时我需要删除或添加甚至修改一些按钮。我创建了一个例程来做到这一点,几乎没有对话框和消息框。事实是,有时(随机)JPanel不能正确刷新(它不会按要求删除按钮,甚至不会添加它)。如果我第二次调用刷新例程(我调用对话框添加一个按钮,然后单击退出而不添加任何东西),一切顺利。我不明白为什么,我认为这是关于时间和需要每次重绘或重新验证方法有效的时间,这个考虑因素是因为我试图调试程序(使用eclipse和很少的断点),并且在调试期间它总是刷新正确。爪哇Swing重绘并重新生效并不总是工作

这里是一些代码(简化)。

// This method is used when first creating the GUI (the removeAll obviously remove nothing 
// I call the revalidate because I re-add the buttons, and I call repaint to have the 
// JPanel itself repainted. 

public static void repaintServices() { 
    //services is a JPanel 
    services.removeAll(); 
    JLabel lbl = new JLabel("SERVIZI"); 

    services.add(lbl); 
    services.add(Box.createRigidArea(new Dimension(0, 20))); 

    // ########## SERVICES BUTTONS 
    Database.connect(); 
    ArrayList<Service> s = Database.listServices(); 
    JPanel btt = new JPanel(); 
    for (int i = 0; i < s.size(); i++) { 
     JButton b = new JButton(s.get(i).getName().toUpperCase()); 
     if (i % 3 == 0) { 
      btt = new JPanel(); 
      btt.setLayout(new BoxLayout(btt, BoxLayout.LINE_AXIS)); 
      services.add(btt); 
      services.add(Box.createRigidArea(new Dimension(0, 10))); 
      btt.add(b); 
     } else { 
      btt.add(Box.createRigidArea(new Dimension(10, 0))); 
      btt.add(b); 
     } 
    } 
    Database.disconnect(); 
    // ########## END SERVICES BUTTONS 

    services.add(Box.createVerticalGlue()); 

    services.revalidate(); 
    services.repaint(); 
} 

这是我修改数据库(这样该按钮列表)

LOG.finest("User ask to add a new Service"); 

ArrayList<String> result = GUI.showServiceDialog(); 
if (result.size() > 0) { 
    if (!"".equals(result.get(0))) { 
     String name = result.get(0); 

     Database.connect(); 
     if (Database.addService(name, price, cadence)) { 
      GUI.showMessage("Servizio aggiunto correttamente"); 
     GUI.repaintServices(); 
     } 
     Database.disconnect(); 
    } else { 
     GUI.showErrorMessage("All field necessary!\nNew Service NOT added"); 
     return; 
    } 
}else { 
    return; 
} 

这是用来获取值插入用户的梅托德(使用自定义模式对话框)

public static ArrayList<String> showServiceDialog() { 
    ArrayList<String> ret = new ArrayList<String>(); 
    JTextField name = new JTextField(15); 
    JTextField price = new JTextField(5); 
    JTextField cadence = new JTextField(4); 

    // NOT USEFUL STUFF, just adding some components. JUMP DOWN TO..... 
    JPanel p = new JPanel(); 
    p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS)); 
    JPanel pp = new JPanel(); 
    pp.setLayout(new BoxLayout(pp, BoxLayout.LINE_AXIS)); 

    pp.add(new JLabel("Nome:")); 
    pp.add(Box.createHorizontalStrut(10)); 
    pp.add(name); 

    p.add(pp); 
    p.add(Box.createVerticalStrut(10)); // a spacer 

    pp = new JPanel(); 
    pp.setLayout(new BoxLayout(pp, BoxLayout.LINE_AXIS)); 
    pp.add(new JLabel("Prezzo:")); 
    pp.add(Box.createHorizontalStrut(10)); 
    pp.add(price); 
    pp.add(new JLabel("€")); 
    pp.add(Box.createHorizontalStrut(20)); 
    pp.add(new JLabel("Frequenza:")); 
    pp.add(Box.createHorizontalStrut(10)); 
    pp.add(cadence); 

    p.add(pp); 
    p.add(Box.createVerticalStrut(15)); 

    // .... HERE, following the interesting part. 

    int result = JOptionPane.showConfirmDialog(window, p, "Inserisci i dati del nuovo servizio", JOptionPane.OK_CANCEL_OPTION); 
    if (result == JOptionPane.OK_OPTION) { 
     ret.add(name.getText()); 
     ret.add(price.getText()); 
     ret.add(cadence.getText()); 
    } 
    return ret; 

} 

我有一些其他的方法,如删除,编辑等等,但问题(不刷新正确)随机与每个这种方法,我张贴我最简单的部分。

任何想法? (我有同样的问题也有,GUI启动与SwingUtilities.invokeLater像组合框或列表框的GUI的其他部分)

这里是一些SSCCE码,出现问题做: ADD,添加,删除,ADD

删除后添加不正确刷新(有时,有时是随机的,如我所说)。 (没有触及任何其他事物)。我希望代码足够清晰和足够短,我删除了似乎没有涉及的数据库。

package it.kApps; 

import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.ArrayList; 

import javax.swing.Box; 
import javax.swing.BoxLayout; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JOptionPane; 
import javax.swing.JPanel; 

public class RevalidateRepaintTry { 

private static JPanel services; 
private static ArrayList<String> s; 

public RevalidateRepaintTry() { 
    s = new ArrayList<String>(); 
    s.add("btt1"); 
    s.add("btt2"); 
    JFrame main = new JFrame(); 
    main.getContentPane().setLayout(new BoxLayout(main.getContentPane(), BoxLayout.PAGE_AXIS)); 
    services = new JPanel(); 
    repaintServices(); 
    JButton b = new JButton("ADD"); 
    b.addActionListener(new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent evt) { 
      String add = JOptionPane.showInputDialog("insert new"); 
      s.add(add); 
      repaintServices(); 
     } 
    }); 
    JButton bb = new JButton("DEL"); 
    bb.addActionListener(new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent evt) { 
      s.remove(s.size() - 1); 
      repaintServices(); 
     } 
    }); 
    main.add(services); 
    main.add(b); 
    main.add(bb); 
    main.setVisible(true); 
    main.pack(); 
    main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

} 

public static void main(String arg[]) { 

    javax.swing.SwingUtilities.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      new RevalidateRepaintTry(); 
     } 
    }); 

} 

public static void repaintServices() { 
    // services is a JPanel 
    services.removeAll(); 
    JLabel lbl = new JLabel("SERVIZI"); 

    services.add(lbl); 
    services.add(Box.createRigidArea(new Dimension(0, 20))); 

    // ########## SERVICES BUTTONS 
    JPanel btt = new JPanel(); 
    for (int i = 0; i < s.size(); i++) { 
     JButton b = new JButton(s.get(i)); 
     if (i % 3 == 0) { 
      btt = new JPanel(); 
      btt.setLayout(new BoxLayout(btt, BoxLayout.LINE_AXIS)); 
      services.add(btt); 
      services.add(Box.createRigidArea(new Dimension(0, 10))); 
      btt.add(b); 
     } else { 
      btt.add(Box.createRigidArea(new Dimension(10, 0))); 
      btt.add(b); 
     } 
    } 
    // ########## END SERVICES BUTTONS 

    services.add(Box.createVerticalGlue()); 

    services.revalidate(); 
    services.repaint(); 
} 
} 
+3

*为了更好地帮助越早,张贴[SSCCE(HTTP“我贴我有最简单的一部分。”:// SSCCE .org等/)。 –

+0

谢谢你的回答,问题是我不能写简单的东西,因为如果简单,刷新没有问题。顺便说一下,我正在尝试! – Gianmarco

+0

我从来没有指示你写任何'简单'?你真的读过这个链接吗?或者你只是在猜测? –

回答

1

我有一种感觉它与布局管理器的一个问题...

就个人而言,我会用不同的布局管理器开始了。

JPanel默认情况下使用FlowLayout,它有一个令人敬畏的副作用,不会“扩展”组件扩展超出父容器的水平宽度。

虽然我知道Box可以与其他布局管理器一起使用,但它的设计目的是与BoxLayout一起使用,所以如果它不按照您的要求工作,我不会感到惊讶。

public class RevalidateRepaintTry { 

    private static JPanel services; 
    private static ArrayList<String> s; 

    public RevalidateRepaintTry() { 
     s = new ArrayList<String>(); 
     s.add("btt1"); 
     s.add("btt2"); 
     JFrame main = new JFrame(); 
     main.getContentPane().setLayout(new BoxLayout(main.getContentPane(), BoxLayout.PAGE_AXIS)); 
     services = new JPanel(); 
     repaintServices(); 
     JButton b = new JButton("ADD"); 
     b.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent evt) { 
       String add = JOptionPane.showInputDialog("insert new"); 
       s.add(add); 
       repaintServices(); 
      } 

     }); 
     JButton bb = new JButton("DEL"); 
     bb.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent evt) { 
       s.remove(s.size() - 1); 
       repaintServices(); 
      } 

     }); 
     main.add(services); 
     main.add(b); 
     main.add(bb); 
     main.setVisible(true); 
     main.pack(); 
     main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    } 

    public static void main(String arg[]) { 

     javax.swing.SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new RevalidateRepaintTry(); 
      } 

     }); 

    } 

    public static void repaintServices() { 
     // services is a JPanel 
     services.removeAll(); 
     JLabel lbl = new JLabel("SERVIZI"); 

     JPanel view = new JPanel(new GridBagLayout()); 
     JScrollPane scroll = new JScrollPane(view); 

     GridBagConstraints gbc = new GridBagConstraints(); 
     gbc.gridx = 0; 
     gbc.gridy = 0; 

     view.add(lbl, gbc); 

     // ########## SERVICES BUTTONS 
     for (int i = 0; i < s.size(); i++) { 
      JButton b = new JButton(s.get(i)); 
      if (i % 3 == 0) { 
       gbc.gridy++; 
       gbc.gridx = 0; 
      } else { 
       gbc.gridx++; 
      } 
      view.add(b, gbc); 
     } 
     // ########## END SERVICES BUTTONS 

     view.add(Box.createVerticalGlue()); 

     services.add(scroll); 

     services.revalidate(); 
     services.repaint(); 
    } 
} 

注意,我在JScrollPane扔,它可能不需要

+0

哎呀,当我看到你的答案,我差点晕了过去,我把所有的程序用的BoxLayout,可以是几乎不可能改变对网格包...所以我想你的SSCCE和幸运(或不幸,因为我们还没有的一个解决方案) 我也有同样的问题。 – Gianmarco

+0

我已经在JDK 7(更新)7下的Mac OS Lion上测试了原始代码和我的代码,没有问题。我怀疑你的复合布局中有些事情似乎没有出现在这里。尝试这个。在服务窗格中添加一个边框(行'LineBorder')和/或设置服务窗格的背景。这将允许您监视以查看面板是否布局正确。如果还是不行,请尝试调整框架,看它是否强制布局 – MadProgrammer

+0

是的,没有尝试我知道,甚至只是点击面板上或调整框架一切顺利的话,它的东西,我无法解释,我尝试了你所说的所有事情,但有时候面板似乎只是不刷新。但我知道(通过调试)方法被正确调用。你看过视频吗?想想快速录制工具,我在看到它时看不到任何错误(之后)。 – Gianmarco