Problem
I have a multi frame environment. Each JFrame
has several JComponents
, nested in each other. I need to access a global variable of the frame from within some of the embedded components. I can't use static because the static would of course apply to all frames. I can't hand over the frame or a class with the relevant information to all the components (combobox, label, etc).
Current Solution
My current solution is to use a HierarchyListener
and once the showing method fires I get access to the JFrame
using SwingUtilities.getAncestorOfClass
.
Question
Does anyone know of a better solution to get access to a JFrame's
attributes from deep inside a component hierarchy? Basically a frame context that all JComponents
have access to, but limited to the parent frame. Is there some way using e. g. the EventQueue
for that or other indicators?
Code
Here's a MCVE of the current state:
- 2 frames
- a panel embedded in a frame
- panel has a label
- label is set to the frame's title
The code:
public class MyFrame extends JFrame {
/**
* Panel with a label which accesses the parent frame's attributes
*/
public class MyPanel extends JPanel {
public MyPanel() {
// set layout and add the label
setLayout(new FlowLayout());
final JLabel label = new JLabel("Placeholder");
add(label);
// JFrame is null here, can't use this:
// JFrame frame = (JFrame) SwingUtilities.getAncestorOfClass(JFrame.class, this);
// label.setText(frame.getTitle());
// but frame can be accessed once the panel got added using a HierarchyListener
addHierarchyListener(new HierarchyListener() {
@Override
public void hierarchyChanged(HierarchyEvent e) {
long flags = e.getChangeFlags();
if ((flags & HierarchyEvent.SHOWING_CHANGED) == HierarchyEvent.SHOWING_CHANGED) {
// get frame, get title and set title in label
JFrame frame = (JFrame) SwingUtilities.getAncestorOfClass(JFrame.class, MyPanel.this);
label.setText(frame.getTitle());
}
}
});
}
}
/**
* Frame with title which will be used as example about how to access
* the frame's attributes from a child component
*/
public MyFrame(String title, int x, int y) {
// create content panel
getContentPane().setLayout(new BorderLayout());
getContentPane().add(new MyPanel(), BorderLayout.CENTER);
// frame specific code
setTitle(title);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(100, 100);
setLocation(x, y);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame1 = new MyFrame("Frame 1", 100, 100);
JFrame frame2 = new MyFrame("Frame 2", 300, 100);
}
});
}
}