I would like my jframe to change its size and contents depending on the x coordinate.
Initially the jframe appears in the 'primary zone' (x <= 1400) witn a panel sized 500x500 added to the jframe's content pane.
Desired: When it is dragged and leaves the 'primary zone' and enters the 'secondary zone' everything is removed from the content pane, the panel gets wrapped into a jscrollpane sized 200x200, and the jscrollpane is added the content pane. When the jframe leaves the 'secondary zone' the jscrollpane is removed from the content pane and the panel is added back.
Actual: Results are not stable. When the jframe leaves the primary zone I can see some flipping. Scrollbars appear but and the frame changes its size but then immediately resized back to the previous size. Stopping at breakpoints inside runnables in the changeSizeAndContent invokeLater codeblocks (not a good practice actually) brings the desired result and so does a conditional breakpoint.
There is some Swing multithreading taking place which I do not understand. I can see the EDT calling EventQueue's dispatchEvent and the COMPONENT_RESIZED (new, correct size) events triggered by runnables in the changeSizeAndContent are followed by COMPONENT_MOVED (old, now incorrect size) events which reference the component with its old size.
Tried with Java 8 and 11.
package Jna;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
/* 0------------------1200-1400--------->
* +---------------+
* | SECONDARY |
* +--------------------+---+ |
* | PRIMARY | B | x: 1200- |
* | x: 0-1400 | U | |
* | | F | |
* | | F | |
* | | E | |
* | | R | |
* | +---+-----------+
* | |
* +------------------------+
*/
public class FrameDemo3 {
static final JPanel panel;
static final JScrollPane jsp;
static {
panel = getInitializedPanel();
jsp = getInitilalizedJScrollPane();
}
static boolean isPrimaryZone = true;
static boolean isCurrentPrimaryZone = true;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("FrameDemo");
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentMoved(ComponentEvent e) {
int x = frame.getX();
if (x > 1400) {
isCurrentPrimaryZone = false;
} else if (x < 1200) {
isCurrentPrimaryZone = true;
}
if (isPrimaryZone != isCurrentPrimaryZone) {
isPrimaryZone = isCurrentPrimaryZone;
changeSizeAndContent(frame);
}
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
public static void changeSizeAndContent(JFrame frame) {
if (isPrimaryZone) {
SwingUtilities.invokeLater(() -> {
frame.getContentPane().removeAll();
frame.getContentPane().add(panel);
frame.pack();
});
} else {
SwingUtilities.invokeLater(() -> {
frame.getContentPane().removeAll();
frame.getContentPane().add(jsp);
frame.pack();
});
}
}
private static JPanel getInitializedPanel() {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(Color.WHITE);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
panel.add(new JLabel(getLabelText(i, j)), getConstraints(i, j));
}
}
panel.setPreferredSize(new Dimension(500, 500));
return panel;
}
private static JScrollPane getInitilalizedJScrollPane() {
JScrollPane jsp = new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
jsp.setPreferredSize(new Dimension(200, 200));
return jsp;
}
static GridBagConstraints getConstraints(int gridX, int gridY) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = gridX;
gbc.gridx = gridY;
gbc.ipady = 40;
gbc.ipadx = 40;
return gbc;
}
static String getLabelText(int gridX, int gridY) {
StringBuilder sb = new StringBuilder("EXAMPLE ")
.append(gridX)
.append(',')
.append(gridY);
return sb.toString();
}
}