2012-03-11 4 views
2

Я создал приложение Swing с несколькими JInternalFrames, которое добавляется в JDesktopPane при событии щелчка мыши. Я хочу только один экземпляртакой же внутренний фрейм, который будет присутствовать на DesktopPane. Я не хочу, чтобы один и тот же кадр отображался дважды, когда пользователь открывает рамку. Если рамка уже открыта, должно появиться сообщение об ошибке!Разрешить только один экземпляр JInternalFrame

спасибо :)

ответ

5

Не беспокойтесь об однотонном анти-шаблоне. Вместо этого просто дайте вашему классу поле JInternalFrame и создайте один экземпляр вашего JInternalFrame в конструкторе вашего класса или в объявлении переменной и не создавайте новый при щелчке мыши, а скорее показывайте тот, который уже был создан. Например, в методе mousePressed просто вызовите myInternalFrame.setVisible(true). Таким образом, если он был невидимым, теперь он виден, и если он уже виден, то он все еще остается видимым и неизменным. Простой и понятный.

+0

OP, возможно, создает много случаев одного и того же класса беззаботно. и ваш ответ указывает на проблему очень хорошо. так что +1 от меня. но в моем ответе ему будет запрещено создавать случаи беззаботно =) в любом случае, оба применимы. – Juvanis

+0

@deporter: спасибо и согласитесь, и 1+ назад у вас. Хотя я ненавижу * singleton, особенно там, где он не нужен. –

+0

@ekompu: Добро пожаловать! –

6

Я создал приложение Свинг с несколькими JInternalFrames ...

и

Я хочу, чтобы только один экземпляр того же внутреннего рамы ...

Так что примените Singleton Pattern для каждого из ваших дочерних классов JInternalFrame. Вы сможете использовать только один экземпляр класса, если класс соответствует шаблону singleton.

+0

и как это сделать? спасибо :) – wishman

+0

Я дал ссылку на очень короткую и полезную статью. прочитайте его. предположим, что ваши классы таковы: x расширяет jinternal frame ..., y extends jinternalframe ..., применяет singleton к x, y, .. и в любое время вы будете иметь только один объект x, только один объект y и т. д. , – Juvanis

1

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. Настоятельно рекомендуется.

Смежные вопросы