How to Integrate Multi-page Java Desktop Applicati

2019-02-19 05:00发布

问题:

I am working on a Java Swing desktop application project. The application has about 15 GUI pages. I can use Layered Panes and Tabbed Panes to put all the GUI components in one class. But that class will be huge. It would be idea if I can divide the project into several smaller sub-projects and let each have one or a few GUI pages. I can work on each sub-project individually and integrate them back into one application when all sub-projects are finished. My question is that how I can integrate all GUI pages from different classes so I can navigate back and force among different pages on button clicks? Since the sub-projects contain GUI pages each needs to have a JFrame. How I can switch back and force between JFrame 1 to JFrame 2 and make one visible and the other invisible? This question shows how to create new JFrames. But did not show how switch back and forth among the JFrames.

回答1:

... The application has about 15 GUI pages. I can use Layered Panes and Tabbed Panes to put all the GUI components in one class. But that class will be huge.

Not necessarily. The GUI could be quite simple, and could have a method that would allow other classes to add a page, say something called registerPage(...):

public void registerPage(JComponent page, String name) {
  pageHolder.add(page, name);
  nameComboModel.addElement(name);
}

Then give the class methods to allow one to go to the next or previous page or to a random page. For example a class as small as this could work:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class LotsOfPagesPanel extends JPanel {
   private CardLayout cardlayout = new CardLayout();
   private JPanel pageHolder = new JPanel(cardlayout);
   private DefaultComboBoxModel<String> nameComboModel = new DefaultComboBoxModel<String>();
   private JComboBox<String> nameCombo = new JComboBox<String>(nameComboModel);

   public LotsOfPagesPanel() {
      JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0));
      btnPanel.add(new JButton(new PrevAction(this, "Previous", KeyEvent.VK_P)));
      btnPanel.add(new JButton(new NextAction(this, "Next", KeyEvent.VK_N)));
      JPanel bottomPanel = new JPanel();
      bottomPanel.add(btnPanel);
      bottomPanel.add(nameCombo);

      nameCombo.addActionListener(new NameComboListener());
      pageHolder.setBorder(BorderFactory.createEtchedBorder());

      setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
      setLayout(new BorderLayout(5, 5));
      add(pageHolder, BorderLayout.CENTER);
      add(bottomPanel, BorderLayout.PAGE_END);
   }

   public void previousPage() {
      cardlayout.previous(pageHolder);
   }

   public void nextPage() {
      cardlayout.next(pageHolder);
   }

   public void show(String name) {
      cardlayout.show(pageHolder, name);
   }

   public void registerPage(JComponent page, String name) {
      pageHolder.add(page, name);
      nameComboModel.addElement(name);
   }

   private class NameComboListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         String selection = nameCombo.getSelectedItem().toString();
         show(selection);
      }
   }
}

All this class really does is act as a repository for your "pages" and has the logic to allow flipping through pages either contiguously or randomly, and not much else, but that's all it really needs to do, and by limiting it so, we limit the class's size. If other functionality is needed, create other classes for these

... such as our Action classes including the PrevAction class:

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;

public class PrevAction extends AbstractAction {
   private LotsOfPagesPanel lotsOfPages;

   public PrevAction(LotsOfPagesPanel lotsOfPages, String name, Integer keyCode) {
      super(name);
      this.lotsOfPages = lotsOfPages;
      putValue(MNEMONIC_KEY, keyCode);
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      lotsOfPages.previousPage();
   }
}

and NextAction.java

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;

public class NextAction extends AbstractAction {
   private LotsOfPagesPanel lotsOfPages;

   public NextAction(LotsOfPagesPanel lotsOfPages, String name, Integer keyCode) {
      super(name);
      this.lotsOfPages = lotsOfPages;
      putValue(MNEMONIC_KEY, keyCode);
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      lotsOfPages.nextPage();
   }
}

And you would need to have a main method of course:

import java.awt.Color;
import java.awt.Dimension;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;

public class LotsOfPagesMain {
   private static final String[] LABELS = { "One", "Two", "Three", "Four",
         "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve",
         "Thirteen", "Fourteen", "Fifteen" };
   private static final Dimension LABEL_SIZE = new Dimension(400, 300);

   private static void createAndShowGui() {
      LotsOfPagesPanel lotsOfPages = new LotsOfPagesPanel();
      Random random = new Random();

      // I'm using JLabels as a simple substitute for your complex JPanel GUI "pages"
      for (String labelText : LABELS) {
         JLabel label = new JLabel(labelText, SwingConstants.CENTER);
         label.setPreferredSize(LABEL_SIZE);
         label.setOpaque(true);
         label.setBackground(new Color(random.nextInt(170) + 85, random
               .nextInt(170) + 85, random.nextInt(170) + 85));
         lotsOfPages.registerPage(label, labelText);
      }

      JFrame frame = new JFrame("LotsOfPages");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(lotsOfPages);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

But it wouldn't be a huge class by any means, and you wouldn't have to worry about flipping multiple JFrames at the user.



回答2:

Your idea of a centralised controller isn't a bad one.

Personally, my first thoughts would be to try a group these separate pages into domain groups (or groups of responsibility). This would give me my first level of control. I'd decide how I would like these domains to be used by the user.

Once you have that working, you can move to the next level, which groups work with each other (if any) & how would you like the user to interact with these

And so forth.

I agree with HovercraftFullOfEels, you don't want to throw lots of windows at users, this just frustrates them, you also don't want them to have to flick between related pages, where the information on one is useful on another.

You might find that you end up with a combination of both. That is, you might need to provide the user with the flexibility to open some pages in frames. This would allow them the ability to decide what information they always need & what information they can flip through.

IMHO



回答3:

You have a couple of options:

  1. You can hide the old JFrame with setVisible(false)
  2. You can get rid of the old JFrame with dispose()

You can get some more information on these methods and how they should be called here: http://docs.oracle.com/javase/6/docs/api/javax/swing/JFrame.html

Hope this helps!