HovercraftFullOfEeel, человек после моего собственного сердца, говорит, что не использовать шаблон Singleton, и я собираюсь не согласиться. Синглтон может быть очень мощным способом упростить работу и избежать кода шаблона, сохраняя при этом систему сильной и простой в обслуживании. Кроме того, его предложение о том, что вы просто показываете уже открытый JInternalFrame
, имеет два недостатка: 1) это сложно управлять на уровне кода и оставляет вашу систему хрупкой и трудно обновляемой в будущем и 2) Когда конечные пользователи закрываются и снова открыть экран, они ожидают нового экземпляра с обновленными данными и новыми компонентами. Не ожидается, что закрытие и повторное открытие будут одинаковыми.
Другой ответчик говорит, что использует Singleton, но не дает конкретного примера. Итак, я дам вам код, который я разработал для своего приложения:
Это класс для Singleton JInternalFrame
(примечание: причина, по которой он распространяется JPanel
, заключается в том, что я могу легко использовать его в графическом интерфейсе Builder):
public abstract class VPanel extends JPanel {
public static JDesktopPane desktopPane;
public static void installDesktopPane(JDesktopPane desktopPane) {
VPanel.desktopPane = desktopPane;
}
public VPanel(String name) {
this.name = name;
if(desktopPane == null)
throw new IllegalStateException("VPanel is being used with a null desktop pane.");
}
static LinkedHashMap<Class, VPanel> self_panel_map;
JInternalFrame self_jif;
protected VPanel self_panel;
boolean loading;
boolean showing;
public final String name;
public abstract void init();
public static VPanel showPanel(VPanel newInstance) {
if(self_panel_map == null)
self_panel_map = new LinkedHashMap<>();
Class newInstanceClass = newInstance.getClass();
if(self_panel_map.containsKey(newInstanceClass)) {
VPanel oldInstance = self_panel_map.get(newInstanceClass);
oldInstance.showing = oldInstance.self_jif.isVisible();
if(!oldInstance.loading && !oldInstance.showing) {
newInstance.loading = true;
newInstance.self_panel = newInstance;
newInstance.self_jif = new JInternalFrame(newInstance.name, true, true, true, true);
newInstance.self_panel.init();
self_panel_map.put(newInstanceClass, newInstance);
return newInstance;
} else if(oldInstance.showing) {
try {
oldInstance.self_jif.setSelected(true);
} catch (PropertyVetoException e) {
handleError(e);
}
}
return oldInstance;
} else {
newInstance.loading = true;
newInstance.self_panel = newInstance;
newInstance.self_jif = new JInternalFrame(newInstance.name, true, true, true, true);
newInstance.self_panel.init();
self_panel_map.put(newInstanceClass, newInstance);
return newInstance;
}
}
public void setVisible() {
self_jif.add(self_panel);
self_jif.pack();
self_jif.setVisible(true);
desktopPane.add(self_jif);
centerJIF();
try {
self_jif.setSelected(true);
} catch (PropertyVetoException e) {
handleError(e);
}
loading = false;
}
private static void handleError(Exception e) {
e.printStackTrace();
}
public void centerJIF() {
Dimension desktopSize = desktopPane.getSize();
Dimension JInternalFrameSize = self_jif.getSize();
int width = (desktopSize.width - JInternalFrameSize.width)/2;
int height = (desktopSize.height - JInternalFrameSize.height)/2;
self_jif.setLocation(width, height);
}
}
Вот пример кода, который будет осуществлять его:
public static void main(String[] args) {
JFrame jf = new JFrame("MainFrame");
JDesktopPane jdp = new JDesktopPane();
jf.setExtendedState(jf.getExtendedState()|JFrame.MAXIMIZED_BOTH);
VPanel.installDesktopPane(jdp); // This only needs to happen once throughout the entire application lifecycle.
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Panels");
JMenuItem menuItem = new JMenuItem("Open Test Panel");
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Test_VPanel.showPanel(new Test_VPanel()); // Every time you show the panel, you create a new instance.
// But this new instance is only used if it is needed. The init() method is only called if it is going
// To show a new instance.
}
});
menu.add(menuItem);
menuBar.add(menu);
jf.setJMenuBar(menuBar);
jf.setContentPane(jdp);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
static class Test_VPanel extends VPanel {
public Test_VPanel() {
super("Test Panel");
}
@Override
public void init() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
JLabel label = new JLabel("JLabel");
JTextField textField = new JTextField();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.gridwidth = 1;
gbc.gridy = 0;
gbc.insets = new Insets(4,4,4,4);
add(label, gbc);
gbc.gridy = 1;
add(textField, gbc);
setVisible(); // This needs to be called at the end of init()
}
}
Я никогда не нужен метод вызова, чтобы сделать что-нибудь с новым экземпляром, но только упаковывают, showPanel
возвращает экземпляр используется , будь то o ld или новый экземпляр.Так что, если вам нужно что-то делать с этим экземпляром, вы могли бы сделать это:
Test_VPanel panel = Test_VPanel.showPanel(new Test_VPanel());
panel.something();
...
Жизнь была намного легче для меня, когда я решил пойти по этому пути с Singleton JIFs. Настоятельно рекомендуется.
OP, возможно, создает много случаев одного и того же класса беззаботно. и ваш ответ указывает на проблему очень хорошо. так что +1 от меня. но в моем ответе ему будет запрещено создавать случаи беззаботно =) в любом случае, оба применимы. – Juvanis
@deporter: спасибо и согласитесь, и 1+ назад у вас. Хотя я ненавижу * singleton, особенно там, где он не нужен. –
@ekompu: Добро пожаловать! –