如何在 Java Swing 中动态控制自动调整大小的组件
How to dynamically control auto-resize components in Java Swing
在 Java (1.8) Swing 中创建一个新的 GUI,我正在寻找一种方法来覆盖我所有组件的调整大小行为。
让我用一些编辑过的照片给你解释一下:
1。全屏 GUI
这是我的全屏 GUI,有 3 个面板和一个 JToolBar
。绿色的需要固定大小,其他的需要可调整大小。
目前,我只有 2 个小 GridLayout
来组织它们(绿色和青色面板一个垂直,一个水平)。
2。小水平调整大小
例如,如果我从右侧缩小框架尺寸,我希望我的蓝色和青色面板根据新的框架尺寸调整大小。但绿色面板必须固定。 (我认为这不是最困难的部分。)
3。最小水平尺寸
这对我来说是最困难的部分。一旦青色(或蓝色)面板达到最小尺寸,我希望他“将”绿色面板向左“推”,即使它从框架中消失。
当然,向右拉框,绿色面板又会出现
我该怎么做?
我想过使用 JSplitPane
或特定的侦听器来手动决定调整大小的行为,但我需要一些建议。
抱歉,如果现有 post 可以回答这个问题,我没有找到任何解释问题的答案。
提前致谢!
如果你想要更多的例子,请看"Evernote"软件,它的作用是一样的
我就是这样做的,但我不确定这是不是正确的方法:
首先将布局设置为空。
接下来为您的框架创建一个组件大小调整事件:
addComponentListener(new ComponentAdapter(){
public void componentResized(ComponentEvent e){
}
});
在这里,您可以在调整大小时手动更改组件。我已经为我的一些程序完成了此操作,以使框架左侧和右侧的滚动窗格始终保持相同的宽度,并使其他所有内容都随着调整大小而上下调整。
使用 GridBagLayout 应该很容易,只要您为绿色和青色组件设置适当的最小尺寸:
setLayout(new GridBagLayout());
green.setMnimumSize(new Dimension(0, 0));
cyan.setMinimumSize(new Dimension(100, 100)); // whatever fits
add(blue, new GridBagConstraints(0, 0, 2, 1,
1.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0);
add(green, new GridBagConstraints(0, 1, 1, 1,
0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0);
add(cyan, new GridBagConstraints(1, 1, 1, 1,
1.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0);
通过为青色和蓝色分量指定权重 x 以及设置 resize = HORIZONTAL,它们会随容器调整大小。
设置 Green
面板的 max/min/preferred 大小可以使该面板在第一种情况下保持相同的大小。要检查调整大小,您可以在其他 JPanel
之一上使用 ComponentListener
- 如果尺寸低于特定宽度,则更改 Green
的 max/min/preferred 尺寸] 控制板。
下面是一个组合在一起的例子——它在 Blue
< 600 时调整 Green
面板的大小,并且调整大小是加权调整大小(总宽度的 30%)。要获得真正的 L&F 和您想要的,您可能必须使用 layout/sizes。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
public class GridTest extends JPanel{
private boolean changeAllowed = false;
//keep reference to cyan for the height dimension
final JPanel cyan = new JPanel();
public GridTest(){
cyan.setPreferredSize(new Dimension(600, 300));//provide sizing hint
}
private Dimension getCustomDimensions(){
if ( changeAllowed ){
return new Dimension((int)(super.getParent().getBounds().width * 0.3), cyan.getBounds().height);
}else{
return new Dimension(200, cyan.getBounds().height);
}
}
@Override
public Dimension getMaximumSize(){
return getCustomDimensions();
}
@Override
public Dimension getMinimumSize(){
return getCustomDimensions();
}
@Override
public Dimension getPreferredSize(){
return getCustomDimensions();
}
public static void main(String[] args) throws Exception{
SwingUtilities.invokeAndWait(new Runnable(){
@Override
public void run() {
final int MINIMUM = 600;
JFrame frame = new JFrame();
frame.add(new JToolBar(), BorderLayout.NORTH);
final JPanel blue = new JPanel();
final GridTest green = new GridTest();
green.setBackground(Color.green);
green.setOpaque(true);
green.cyan.setBackground(Color.cyan);
green.cyan.setOpaque(true);
blue.setOpaque(true);
blue.setBackground(Color.blue);
blue.setPreferredSize(new Dimension(900, 300));//hint at size
blue.setMinimumSize(new Dimension(100, 200));//hint at size
//Nest Box Layouts
Box top = Box.createHorizontalBox();
top.add(blue);
Box bottom = Box.createHorizontalBox();
bottom.add(green);
bottom.add(green.cyan);
Box vert = Box.createVerticalBox();
vert.add(top);
vert.add(bottom);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(vert);
//listen for resizes
blue.addComponentListener(new ComponentAdapter(){
@Override
public void componentResized(ComponentEvent e) {
if ( blue.getBounds().width < MINIMUM ){//set flag
green.changeAllowed = true;
}else{
green.changeAllowed = false;
}
}
});
frame.pack();
frame.setSize(800, 600);
frame.setVisible(true);
}
});
}
}
您可以使用 BoxLayout
来包含绿色和青色面板。 A BoxLayout
遵守组件的最小和最大尺寸。因此,对于绿色面板,您设置的最大尺寸等于首选尺寸,对于青色面板,您将最小尺寸设置为首选尺寸:
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
JPanel blue = new JPanel();
blue.setBackground( Color.BLUE );
blue.setPreferredSize( new Dimension(500, 100) );
Box box = Box.createHorizontalBox();
JPanel green = new JPanel();
green.setBackground( Color.GREEN );
green.setPreferredSize( new Dimension(200, 100) );
green.setMaximumSize( green.getPreferredSize() );
box.add( green );
JPanel cyan = new JPanel();
cyan.setBackground( Color.CYAN );
cyan.setPreferredSize( new Dimension(300, 100) );
cyan.setMinimumSize( cyan.getPreferredSize() );
box.add( cyan );
setLayout( new BorderLayout() );
add(blue, BorderLayout.NORTH);
add(box, BorderLayout.CENTER);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
当然,正确的解决方案是分别覆盖每个面板的 getMaximumSize()
和 getMinimumSize()
方法,以 return 面板的首选大小。
重要的顺序是这样的:
frame.revalidate();
frame.pack();
frame.repaint();
- revalidate():在组件 hierarchy 从最近的验证根开始验证之后,使组件直到最近的根无效。
- pack():使 window 的大小适合其子组件的首选大小和布局。 window 的结果宽度和高度会自动放大..
- repaints():在所有这些重新计算之后,重绘显示了组件。
在每一系列更改之后使用此序列,您已完成代码并希望在屏幕上看到结果。
我喜欢 java.awt.GridBagLayout 与 java.awt.GridBagConstraints 的组合,我在所有容器上使用此布局从内容窗格启动。
如果将一个容器添加到另一个容器中,请在每个容器上使用一个布局,否则计算将失败,因为层次结构中缺少布局。
在 Java (1.8) Swing 中创建一个新的 GUI,我正在寻找一种方法来覆盖我所有组件的调整大小行为。
让我用一些编辑过的照片给你解释一下:
1。全屏 GUI
这是我的全屏 GUI,有 3 个面板和一个 JToolBar
。绿色的需要固定大小,其他的需要可调整大小。
目前,我只有 2 个小 GridLayout
来组织它们(绿色和青色面板一个垂直,一个水平)。
2。小水平调整大小
例如,如果我从右侧缩小框架尺寸,我希望我的蓝色和青色面板根据新的框架尺寸调整大小。但绿色面板必须固定。 (我认为这不是最困难的部分。)
3。最小水平尺寸
这对我来说是最困难的部分。一旦青色(或蓝色)面板达到最小尺寸,我希望他“将”绿色面板向左“推”,即使它从框架中消失。
当然,向右拉框,绿色面板又会出现
我该怎么做?
我想过使用 JSplitPane
或特定的侦听器来手动决定调整大小的行为,但我需要一些建议。
抱歉,如果现有 post 可以回答这个问题,我没有找到任何解释问题的答案。
提前致谢!
如果你想要更多的例子,请看"Evernote"软件,它的作用是一样的
我就是这样做的,但我不确定这是不是正确的方法:
首先将布局设置为空。
接下来为您的框架创建一个组件大小调整事件:
addComponentListener(new ComponentAdapter(){
public void componentResized(ComponentEvent e){
}
});
在这里,您可以在调整大小时手动更改组件。我已经为我的一些程序完成了此操作,以使框架左侧和右侧的滚动窗格始终保持相同的宽度,并使其他所有内容都随着调整大小而上下调整。
使用 GridBagLayout 应该很容易,只要您为绿色和青色组件设置适当的最小尺寸:
setLayout(new GridBagLayout());
green.setMnimumSize(new Dimension(0, 0));
cyan.setMinimumSize(new Dimension(100, 100)); // whatever fits
add(blue, new GridBagConstraints(0, 0, 2, 1,
1.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0);
add(green, new GridBagConstraints(0, 1, 1, 1,
0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0);
add(cyan, new GridBagConstraints(1, 1, 1, 1,
1.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0);
通过为青色和蓝色分量指定权重 x 以及设置 resize = HORIZONTAL,它们会随容器调整大小。
设置 Green
面板的 max/min/preferred 大小可以使该面板在第一种情况下保持相同的大小。要检查调整大小,您可以在其他 JPanel
之一上使用 ComponentListener
- 如果尺寸低于特定宽度,则更改 Green
的 max/min/preferred 尺寸] 控制板。
下面是一个组合在一起的例子——它在 Blue
< 600 时调整 Green
面板的大小,并且调整大小是加权调整大小(总宽度的 30%)。要获得真正的 L&F 和您想要的,您可能必须使用 layout/sizes。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
public class GridTest extends JPanel{
private boolean changeAllowed = false;
//keep reference to cyan for the height dimension
final JPanel cyan = new JPanel();
public GridTest(){
cyan.setPreferredSize(new Dimension(600, 300));//provide sizing hint
}
private Dimension getCustomDimensions(){
if ( changeAllowed ){
return new Dimension((int)(super.getParent().getBounds().width * 0.3), cyan.getBounds().height);
}else{
return new Dimension(200, cyan.getBounds().height);
}
}
@Override
public Dimension getMaximumSize(){
return getCustomDimensions();
}
@Override
public Dimension getMinimumSize(){
return getCustomDimensions();
}
@Override
public Dimension getPreferredSize(){
return getCustomDimensions();
}
public static void main(String[] args) throws Exception{
SwingUtilities.invokeAndWait(new Runnable(){
@Override
public void run() {
final int MINIMUM = 600;
JFrame frame = new JFrame();
frame.add(new JToolBar(), BorderLayout.NORTH);
final JPanel blue = new JPanel();
final GridTest green = new GridTest();
green.setBackground(Color.green);
green.setOpaque(true);
green.cyan.setBackground(Color.cyan);
green.cyan.setOpaque(true);
blue.setOpaque(true);
blue.setBackground(Color.blue);
blue.setPreferredSize(new Dimension(900, 300));//hint at size
blue.setMinimumSize(new Dimension(100, 200));//hint at size
//Nest Box Layouts
Box top = Box.createHorizontalBox();
top.add(blue);
Box bottom = Box.createHorizontalBox();
bottom.add(green);
bottom.add(green.cyan);
Box vert = Box.createVerticalBox();
vert.add(top);
vert.add(bottom);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(vert);
//listen for resizes
blue.addComponentListener(new ComponentAdapter(){
@Override
public void componentResized(ComponentEvent e) {
if ( blue.getBounds().width < MINIMUM ){//set flag
green.changeAllowed = true;
}else{
green.changeAllowed = false;
}
}
});
frame.pack();
frame.setSize(800, 600);
frame.setVisible(true);
}
});
}
}
您可以使用 BoxLayout
来包含绿色和青色面板。 A BoxLayout
遵守组件的最小和最大尺寸。因此,对于绿色面板,您设置的最大尺寸等于首选尺寸,对于青色面板,您将最小尺寸设置为首选尺寸:
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
JPanel blue = new JPanel();
blue.setBackground( Color.BLUE );
blue.setPreferredSize( new Dimension(500, 100) );
Box box = Box.createHorizontalBox();
JPanel green = new JPanel();
green.setBackground( Color.GREEN );
green.setPreferredSize( new Dimension(200, 100) );
green.setMaximumSize( green.getPreferredSize() );
box.add( green );
JPanel cyan = new JPanel();
cyan.setBackground( Color.CYAN );
cyan.setPreferredSize( new Dimension(300, 100) );
cyan.setMinimumSize( cyan.getPreferredSize() );
box.add( cyan );
setLayout( new BorderLayout() );
add(blue, BorderLayout.NORTH);
add(box, BorderLayout.CENTER);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
当然,正确的解决方案是分别覆盖每个面板的 getMaximumSize()
和 getMinimumSize()
方法,以 return 面板的首选大小。
重要的顺序是这样的:
frame.revalidate();
frame.pack();
frame.repaint();
- revalidate():在组件 hierarchy 从最近的验证根开始验证之后,使组件直到最近的根无效。
- pack():使 window 的大小适合其子组件的首选大小和布局。 window 的结果宽度和高度会自动放大..
- repaints():在所有这些重新计算之后,重绘显示了组件。
在每一系列更改之后使用此序列,您已完成代码并希望在屏幕上看到结果。
我喜欢 java.awt.GridBagLayout 与 java.awt.GridBagConstraints 的组合,我在所有容器上使用此布局从内容窗格启动。
如果将一个容器添加到另一个容器中,请在每个容器上使用一个布局,否则计算将失败,因为层次结构中缺少布局。