Java Swing JLabels show in a buildGUI method but n

2019-07-17 19:43发布

问题:

I'm an amateur writing an archery score card. The programme works well but at the cost of 19 sections of identical code each of 18 lines. I'm trying to condense the code by using a method call. I'm using Java SE6 and Mig Layout

Here is the section of code in the GUI which works. The GUI is called as below

HomePage (containing the main method) -> ChoiceGUI -> buildScoresPanel

    public  void buildScoresPanelMIG(JPanel scoresPanel) {        

    for (row = 0; row<(int)numberofrows; row++){  
       scoresPanel.add(scorelabel1[row],"gapleft 0,w 35px, hmin 35px,split 18");
       scoresPanel.add(scorelabel2[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
       scoresPanel.add(scorelabel3[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
       scoresPanel.add(scorelabel4[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
       scoresPanel.add(scorelabel5[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
       scoresPanel.add(scorelabel6[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
       //another 12 Jlabels              }
    }

If, however I put the code in a method and call it as below the Jlabels won't show even though I've tried revalidate() repaint() and setVisible(true)

    public  void buildScoresPanelMIG(JPanel scoresPanel) {

           for (row = 0; row<(int)numberofrows; row++){  

              addScoreLabels();

           }
    }

    public void addScoreLabels(){

     scoresPanel.add(scorelabel1[row],"gapleft 0,w 35px, hmin 35px,split 18");
     scoresPanel.add(scorelabel2[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
     scoresPanel.add(scorelabel3[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
     scoresPanel.add(scorelabel4[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
     scoresPanel.add(scorelabel5[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
     scoresPanel.add(scorelabel6[row],"gap before 0px,gapleft 0,w 35px, hmin 35px");
    //another 12 labels
     //scoresPanel.revalidate(); 
     //scoresPanel.repaint();
     //scoresPanel.setVisible(true);
  }

I have trawled the internet for quite a while trying to solve the problem and I realise that I have a fundamental misunderstanding of how Swing components work and would be grateful if someone could explain.

回答1:

Try passing scoresPanel as an argument to your addScoreLabels() method too:

addScoreLabels(scoresPanel);

...

public void addScoreLabels(JPanel scoresPanel) { ...

As Chris Cooney points out in the comments, you probably have a different panel stored in a scoresPanel field variable, which is being hidden by a local variable in the first method, but not in the second.



回答2:

I believe your component constraints are illegal (in addition to possible other causes). These are main resources regarding the MigLayout that I have managed to find:

  • quickstart
  • cheatsheet
  • whitepaper
  • apidoc
  • demos

The cheatsheet is your best friend, though it wouldn't hurt to read the whitepaper and download and view the user-friendly demos. If you look into the cheatsheet you'll see that you've basically tried to set the same thing in a couple of different (probably non-compatible) ways.

I've made an SSCCE for dynamic add/remove of a label from a MigLayout managed JPanel. It was built with MigLayout 3.7.4.

Screenshot:

Code:

public class App extends JFrame {

public JPanel mainPanel;
public int addedCount = 1;
public final int initRowsCount = 8;
public final int columnsCount = 5;

public App() {
    super("MiGLayout test");
    initUI();       
}

private void redrawMainPanel() {        
    mainPanel.revalidate();
    mainPanel.repaint();
}

private JMenuBar initMenuBar() {
    JMenuBar menuBar = new JMenuBar();
    JMenu menu = new JMenu("test menu");
    JMenuItem removeMenuItem = new JMenuItem("remove a component");
    JMenuItem addMenuItem = new JMenuItem("add a component");
    JCheckBoxMenuItem debugMenuItem = new JCheckBoxMenuItem("debug mode");
    removeMenuItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            if (mainPanel.getComponentCount() > 0) {
                mainPanel.remove(mainPanel.getComponents()[mainPanel.getComponentCount() - 1]);
                --addedCount;
            }
            App.this.redrawMainPanel();
        }
    });
    addMenuItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            mainPanel.add(
                        initLabel(addedCount / columnsCount, addedCount % columnsCount), 
                        (addedCount % columnsCount == columnsCount - 1 ? "grow 35, wrap" : "grow 35")
                        );
            ++addedCount;
            App.this.redrawMainPanel();
        }
    });
    debugMenuItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            MigLayout migLayout = ((MigLayout)mainPanel.getLayout());
            String lc = (String)migLayout.getLayoutConstraints();
            if (lc.contains("debug")) {
                lc = lc.substring(0, lc.lastIndexOf(','));
            }
            else {
                lc += ",debug";
            }
            migLayout.setLayoutConstraints(lc);  
            App.this.redrawMainPanel();
        }
    });
    menu.add(addMenuItem);
    menu.add(removeMenuItem);
    menu.add(debugMenuItem);
    menuBar.add(menu);
    return menuBar;
}

private JLabel initLabel(int i,int j) {
    JLabel label = new JLabel("label " + i + " " + j);        
    label.setHorizontalAlignment(JLabel.CENTER);
    label.setBorder(BorderFactory.createEtchedBorder());       
    return label;
}
private JPanel initMainPanel() {
    JPanel panel = new JPanel(); 
    panel.setLayout(new MigLayout("nogrid, fill, debug"));
    JLabel label; 
    for (int i = 0; i < initRowsCount; i++) {
        for (int j = 0; j < columnsCount; j++) {                
            panel.add(initLabel(i, j), (j == columnsCount - 1 ? "grow 35, wrap" : "grow 35"));
             ++addedCount;
        }
    }  
    addedCount--;
    return panel;
}

public void initUI() {
    this.setPreferredSize(new Dimension(1024, 768));
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setJMenuBar(initMenuBar());
    this.getContentPane().add(mainPanel = initMainPanel());
    this.setLocationByPlatform(true);
    this.pack();        
}

public static void main(String[] args) {       
    // SwingUtilities.invokeLater
    // or
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            new App().setVisible(true);     ;
        }
    });
}
}

MigLayout has two or three modes of operation which are set as layout constraints - the MigLayout constructor argument. The basic modes are grid and flow-only mode (the nogrid layout constraint).

If I remember correctly, in the grid mode you need to define at least one dimension (rows, columns) and have several ways to do so at your disposal (layout, row and column constraints at least). Then there are two modes: you can add components with and without cell coordinates .

The flow-only mode is equivalent to the web browser visual formatting system: the inline elements are laid out in a row (e.g. HTML span tag), while a block element starts at the next row (e.g. a HTML div). The wrap component constraint breaks the line - places the following component in the next row.

The debug layout constraint draws the red and blue lines, which are layout and component bounds, respectively.

The fill layout constraint:

Claims all available space in the container for the columns and/or rows. At least one component need to have a "grow" constaint for it to fill the container. The space will be divided equal, though honoring "growpriority". If no columns/rows has "grow" set the grow weight of the componets in the rows/columns will migrate to that row/column.

The grow component constraint (may be used as row/column constraint also):

Sets how keen the component should be to grow in relation to other component in the same cell. The weight (defaults to 100 if not specified) is purely a relative value to other components' weight. Twice the weight will get double the extra space. If this constraint is not set the grow weight is set to 0 and the component will not grow (unless fill is set in the row/column in which case "grow 0" can be used to explicitly make it not grow). Grow weight will only be compared against the weights in the same grow priority group and for the same cell. See below.

In this manner, the resizing of the frame can't mess the layout, beacuse they all grow equally. There are many more ways of achieving very different layouts. It does seem it is "one layout manager to rule them all". If you have doubts download the demos. There is even an animation example. An excellent technology choice for an amateur ;).