I might be misreading the question, but I've done something like this in the past. Here's the code I've written. It's a Singleton, Duplicatable JFrame (I extend a JPanel
for reasons specific to my design).
How this works:
If you try to open a new window and it is already open, it receives focuse. If it is not, it opens a new window. It uses an identifier
variable (which could be anything) to keep track.
How to use it:
Use the static showPanel
method so that the class determines whether you need a new panel or not, like this:
SingletonDuplicatableFramePanel.showPanel(new SingletonDuplicatableFramePanel(identifier));
(remember, SingletonDuplicatableFramePanel
is abstract, so you'll need to make another class that extends it).
You pass showPanel()
a new instance of your class.
- If it needs the new instance, it uses it.
- If it doesn't need the new instance, it throws it away (NOTE: constructors of the new instances should do practically nothing because they might not be needed).
The abstract method init()
is only executed if the new instance is actually created. This is where you initialize whatever you need for the new window. At the end of your init()
method, you call setVisible()
.
As mentioned earlier, to make it duplicatable, it keeps track of a unique identifier
which it uses to determine if you already have an instance open or not. It should be clear when you run the demo.
Here's the code for the SingletonDuplicatableFramePanel
:
public abstract class SingletonDuplicatableFramePanel extends JPanel {
public SingletonDuplicatableFramePanel(String name) {
this.name = name;
}
static LinkedHashMap<Class, LinkedHashMap<Object, SingletonDuplicatableFramePanel>> self_panel_map;
JFrame self_jf;
protected SingletonDuplicatableFramePanel self_panel;
boolean loading;
boolean showing;
LinkedList<SingletonDuplicatableFramePanel> vpanel_children;
LinkedList<JDialog> dialog_children;
public final String name;
public abstract void init();
private boolean searchablePanel;
public boolean isSearchablePanel() {
return searchablePanel;
}
public void setSearchablePanel(boolean searchablePanel) {
this.searchablePanel = searchablePanel;
}
public void toFront() {
self_jf.toFront();
}
protected Object identifier;
public static SingletonDuplicatableFramePanel showPanel(Object identifier, SingletonDuplicatableFramePanel newInstance) {
if(self_panel_map == null)
self_panel_map = new LinkedHashMap<>();
Class newInstanceClass = newInstance.getClass();
if(self_panel_map.containsKey(newInstanceClass) && self_panel_map.get(newInstanceClass).containsKey(identifier)) {
SingletonDuplicatableFramePanel oldInstance = self_panel_map.get(newInstanceClass).get(identifier);
oldInstance.showing = oldInstance.self_jf.isVisible();
if(!oldInstance.loading && !oldInstance.showing) {
newInstance.loading = true;
newInstance.self_panel = newInstance;
newInstance.self_jf = new JFrame(newInstance.name);
newInstance.identifier = identifier;
newInstance.self_panel.init();
self_panel_map.get(newInstanceClass).put(identifier, newInstance);
return newInstance;
} else if(oldInstance.showing) {
oldInstance.self_jf.toFront();
}
return oldInstance;
} else {
if(!self_panel_map.containsKey(newInstanceClass))
self_panel_map.put(newInstanceClass, new LinkedHashMap<Object, SingletonDuplicatableFramePanel>());
newInstance.loading = true;
newInstance.self_panel = newInstance;
newInstance.self_jf = new JFrame(newInstance.name);
newInstance.identifier = identifier;
newInstance.self_panel.init();
self_panel_map.get(newInstanceClass).put(identifier, newInstance);
return newInstance;
}
}
public void addChild(SingletonDuplicatableFramePanel panel) {
if(vpanel_children == null)
vpanel_children = new LinkedList<>();
vpanel_children.add(panel);
}
public void dispose() {
loading = false;
showing = false;
self_jf.dispose();
}
boolean packed;
public void pack() {
self_jf.add(self_panel);
self_jf.pack();
self_jf.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
if(vpanel_children != null)
for(SingletonDuplicatableFramePanel vpanel : vpanel_children)
vpanel.dispose();
if(dialog_children != null)
for(JDialog dialog : dialog_children)
dialog.dispose();
}
});
setLocationByPlatform(true);
self_jf.toFront();
self_jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
packed = true;
}
public void setVisible() {
if(!packed) {
pack();
}
self_jf.setVisible(true);
loading = false;
}
public void setTitle(String title) {
self_jf.setTitle(title);
}
public void centerJF() {
self_jf.setLocationRelativeTo(null);
}
public void setLocationByPlatform(boolean bool) {
self_jf.setLocationByPlatform(bool);
}
}
And here's a sample of it in use:
static class My_SDFP extends SingletonDuplicatableFramePanel {
String customer_number;
public My_SDFP(String customer_number) {
super("My SDFP");
this.customer_number = customer_number;
}
@Override
public void init() {
JLabel label = new JLabel("Customer Number = " + customer_number);
add(label);
setVisible();
}
}
public static void main(String[] args) {
JFrame baseFrame = new JFrame();
baseFrame.setLayout(new GridBagLayout());
JButton button = new JButton("Open customer #");
final JTextField identifier_field = new JTextField();
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
String identifier = identifier_field.getText();
My_SDFP.showPanel(identifier, new My_SDFP(identifier));
}
});
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridy = 1;
baseFrame.add(new JLabel("Customer #:"), gbc);
baseFrame.add(identifier_field, gbc);
gbc.gridwidth = 2;
gbc.gridy = 2;
baseFrame.add(button, gbc);
baseFrame.pack();
baseFrame.setLocationByPlatform(true);
baseFrame.setVisible(true);
baseFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
Type a number in the Customer # field and click the button. You'll notice that you can't open two instances of the same customer number. If you try, it only refocuses the frame you're trying to re-open (but can't because it's already open).
