问题
I'm writing an "image viewer" app with a central area containing the image, plus toolbars etc. around it.
I selected a GridBagLayout for the flexibility I need, but as soon as the main window is reduced, instead of having scrollbars appearing around the image, the whole scrollpane collapses to a 0x0px area.
Please find below a minimal code to illustrate this. Try leaving the dimensions at 500x500 and reducing the window by a few pixels by dragging one of its corners inwards:
import javax.swing.*;
import java.awt.*;
public class ScrollTest3 {
private static final int IMG_WIDTH = 500; // 50 or 500 or 2000
private static final int IMG_HEIGHT = 500; // 50 or 500 or 2000
private static GridBagConstraints getScrollPaneConstraints() {
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 1;
c.weightx = 1;
c.weighty = 1;
// With the next line, shrinking the window makes scrollbars appear ok,
// ... but making it larger causes the scrollpane to stick at the top left
// Without the next line, enlarging the window keeps image centered,
// ... but making it smaller causes the scrollpane to collapse
//c.fill = GridBagConstraints.BOTH;
return c;
}
public static void addComponentsToPane(Container container) {
container.setLayout(new GridBagLayout());
// Add top bar
container.add(new JLabel("This would be a top bar with information"), new GridBagConstraints());
// Prepare main image panel
JPanel imagePanel = new JPanel() {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Image replaced by a shape for demonstration purpose
g2d.drawOval(0, 0, IMG_WIDTH, IMG_HEIGHT);
}
public Dimension getMinimumSize() {
return new Dimension(IMG_WIDTH, IMG_HEIGHT);
}
public Dimension getPreferredSize() {
return new Dimension(IMG_WIDTH, IMG_HEIGHT);
}
public Dimension getMaximumSize() {
return new Dimension(IMG_WIDTH, IMG_HEIGHT);
}
};
JScrollPane scrollableImagePanel = new JScrollPane(imagePanel);
container.add(scrollableImagePanel, getScrollPaneConstraints());
}
private static void limitAppSize(JFrame frame) {
frame.pack();
Dimension preferred = frame.getSize();
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
Rectangle bounds = env.getMaximumWindowBounds();
preferred.width = Math.min(preferred.width, bounds.width);
preferred.height = Math.min(preferred.height, bounds.height);
frame.setSize(preferred);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("ScrollTest3");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addComponentsToPane(frame.getContentPane());
limitAppSize(frame);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
}
As you can see in the commented out line, it can be "fixed" by specifying GridBagConstraints.BOTH for the "fill" field, but then smaller images (try with 50x50) are not centered anymore :-(
Is there a way to specify that:
- if the image is smaller than the display area, it should be centered
- if the image is larger than the display area, the scroll pane should fill the full display area
?
回答1:
... but making it larger causes the scrollpane to stick at the top left
The weightx/y constraints tells the GridBayLayout how to allocate extra space in the frame. Since you only have a single component with non-zero values all the extra space goes to the panel. So the component is positioned at the top/left of the space available under the label.
g2d.drawOval(0, 0, IMG_WIDTH, IMG_HEIGHT);
Then your painting code always paints the oval at the top/left relative to the panels location.
If you want the oval centered, then your painting code must change:
//g2d.drawOval(0, 0, IMG_WIDTH, IMG_HEIGHT);
int x = (getWidth() - IMG_WIDTH) / 2;
int y = (getHeight() - IMG_HEIGHT) / 2;
g2d.drawOval(x, y, IMG_WIDTH, IMG_HEIGHT);
I'm writing an "image viewer" app with a central area containing the image
However, as was suggested in the comments of your last question, the easiest solution is to just use a JLabel
to display the image. The JLabel
will automatically center the image in the space available to the label.
Note, this is also why your label text is centered horizontally as you change the width of the frame.
来源:https://stackoverflow.com/questions/62021983/swing-jscollarea-in-gridbaglayout-collapses-when-resizing