使用 GridBagLayout 将跨列居中
Centering Spanned Columns with GridBagLayout
我有一个 JDialog,其中有一系列列,我想在这些列上居中放置一个 JLabel。我似乎无法找到任何关于如何做到这一点的信息。我可以将它置于一个单元格的中心,但不能置于一组跨列中。此图像中的标签 "Target" 和 "Change" 需要居中。
这是生成此 JDialog 的 SSCCE。
package stokerMonitor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Dialog.ModalityType;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
public class test {
static JDialog timeLineDialog;
static int row=0;
public static void main(String[] args) {
timeLineDialog = new JDialog();
timeLineDialog.setLayout(new GridBagLayout());
timeLineDialog.setModalityType(ModalityType.MODELESS);
timeLineDialog.setTitle("Time Line Settings");
timeLineDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
JLabel timeLabel = new JLabel("Time");
JLabel actionLabel = new JLabel("Action");
JLabel probeTempLabel=null;
JLabel pitTempLabel=null;
JLabel targetHeader=new JLabel("Target");
Font boldFont=targetHeader.getFont().deriveFont(Font.BOLD, (float) 14);
targetHeader.setFont(boldFont);
JLabel changeHeader=new JLabel("Change");
changeHeader.setFont(boldFont);
if (Configuration.getInstance().celsius) {
probeTempLabel = new JLabel("Temp (\u00B0 C)");
pitTempLabel = new JLabel("Temp (\u00B0 C)");
}
else {
probeTempLabel = new JLabel("Temp (\u00B0 F)");
pitTempLabel = new JLabel("Temp (\u00B0 F)");
}
JLabel meatLabel=new JLabel("Meat");
JLabel cookTimeLabel=new JLabel("Est. Time");
JLabel weightLabel=new JLabel("Weight");
JLabel probeLabel=new JLabel("Probe");
JLabel pitLabel=new JLabel("Pit");
setNewSeparator(1,row);
GridBagConstraints gbc=makeGbc(2, row);
gbc.gridwidth=7;
gbc.fill=GridBagConstraints.HORIZONTAL;
gbc.anchor=GridBagConstraints.CENTER;
timeLineDialog.add(targetHeader,gbc);
setNewSeparator(9,row);
timeLineDialog.add(changeHeader,makeGbc(10, row));
setNewSeparator(12,row++);
setNewSeparator(1,row);
timeLineDialog.add(timeLabel, makeGbc(2, row));
timeLineDialog.add(probeTempLabel,makeGbc(3, row));
timeLineDialog.add(meatLabel,makeGbc(4, row));
timeLineDialog.add(weightLabel,makeGbc(5, row));
timeLineDialog.add(cookTimeLabel,makeGbc(6, row));
timeLineDialog.add(probeLabel,makeGbc(7, row));
timeLineDialog.add(actionLabel, makeGbc(8, row));
setNewSeparator(9,row);
timeLineDialog.add(pitLabel,makeGbc(10, row));
timeLineDialog.add(pitTempLabel, makeGbc(11, row++));
setNewSeparator(12,row);
timeLineDialog.pack();
timeLineDialog.setLocationRelativeTo(GUI.getInstance().getFrame());
timeLineDialog.setVisible(true);
}
static void setNewSeparator(int column_,int row_) {
JSeparator sep=new JSeparator(SwingConstants.VERTICAL);
sep.setPreferredSize(new Dimension(1,1));
GridBagConstraints gbc=makeGbc(column_, row_);
gbc.fill=GridBagConstraints.VERTICAL;
gbc.weighty=1.;
timeLineDialog.add(sep,gbc);
}
static GridBagConstraints makeGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
Insets WEST_INSETS=new Insets(5,0,5,5);
Insets EAST_INSETS=new Insets(5,5,5,0);
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.anchor = (x == 0) ? GridBagConstraints.WEST : GridBagConstraints.EAST;
gbc.fill = (x == 0) ? GridBagConstraints.BOTH
: GridBagConstraints.HORIZONTAL;
gbc.insets = (x == 0) ? WEST_INSETS : EAST_INSETS;
gbc.weightx = (x == 0) ? 0.1 : 1.0;
gbc.weighty = 1.0;
return gbc;
}
}
有人可以解释我需要做什么才能使那些 headers 居中吗? TIA.
正如 VGR 在他的评论中所说,您应该在约束中设置网格宽度,以使 GridBagLayout 更容易理解如何处理两个顶部标签。
我会将目标标签的网格宽度设置为 7,将更改标签的网格宽度设置为 2。下面的所有标签都应设置为 1。
然后当您设置 GridBagConstraints.anchor = GridBagConstants.CENTER; 时,它应该会执行您正在寻找的行为。
编辑:我说目标标签为 5,但我的意思是 7。
提示:调试布局时,我发现将每个组件设置为不同的背景颜色很有用。然后我可以看到分配给该特定组件/由该特定组件填充的区域。大多数组件默认为透明背景,这意味着它们的边界是不可见的。 (例如targetHeader.setOpaque(true); targetHeader.setBackground(Color.RED);
)
您的布局情况是 JLabel 填充了您指定的 7 列。但是,标签本身会在其填充的 space 的最左侧绘制它包含的文本。
有两种替代解决方案:
告诉标签您希望它在标签内将文本居中:
targetHeader.setHorizontalAlignment(JLabel.CENTER);
或者,您可以告诉布局 而不是 填充 space。
gbc.fill=GridBagConstraints.NONE;
我有一个 JDialog,其中有一系列列,我想在这些列上居中放置一个 JLabel。我似乎无法找到任何关于如何做到这一点的信息。我可以将它置于一个单元格的中心,但不能置于一组跨列中。此图像中的标签 "Target" 和 "Change" 需要居中。
这是生成此 JDialog 的 SSCCE。
package stokerMonitor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Dialog.ModalityType;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JSeparator;
import javax.swing.SwingConstants;
public class test {
static JDialog timeLineDialog;
static int row=0;
public static void main(String[] args) {
timeLineDialog = new JDialog();
timeLineDialog.setLayout(new GridBagLayout());
timeLineDialog.setModalityType(ModalityType.MODELESS);
timeLineDialog.setTitle("Time Line Settings");
timeLineDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
JLabel timeLabel = new JLabel("Time");
JLabel actionLabel = new JLabel("Action");
JLabel probeTempLabel=null;
JLabel pitTempLabel=null;
JLabel targetHeader=new JLabel("Target");
Font boldFont=targetHeader.getFont().deriveFont(Font.BOLD, (float) 14);
targetHeader.setFont(boldFont);
JLabel changeHeader=new JLabel("Change");
changeHeader.setFont(boldFont);
if (Configuration.getInstance().celsius) {
probeTempLabel = new JLabel("Temp (\u00B0 C)");
pitTempLabel = new JLabel("Temp (\u00B0 C)");
}
else {
probeTempLabel = new JLabel("Temp (\u00B0 F)");
pitTempLabel = new JLabel("Temp (\u00B0 F)");
}
JLabel meatLabel=new JLabel("Meat");
JLabel cookTimeLabel=new JLabel("Est. Time");
JLabel weightLabel=new JLabel("Weight");
JLabel probeLabel=new JLabel("Probe");
JLabel pitLabel=new JLabel("Pit");
setNewSeparator(1,row);
GridBagConstraints gbc=makeGbc(2, row);
gbc.gridwidth=7;
gbc.fill=GridBagConstraints.HORIZONTAL;
gbc.anchor=GridBagConstraints.CENTER;
timeLineDialog.add(targetHeader,gbc);
setNewSeparator(9,row);
timeLineDialog.add(changeHeader,makeGbc(10, row));
setNewSeparator(12,row++);
setNewSeparator(1,row);
timeLineDialog.add(timeLabel, makeGbc(2, row));
timeLineDialog.add(probeTempLabel,makeGbc(3, row));
timeLineDialog.add(meatLabel,makeGbc(4, row));
timeLineDialog.add(weightLabel,makeGbc(5, row));
timeLineDialog.add(cookTimeLabel,makeGbc(6, row));
timeLineDialog.add(probeLabel,makeGbc(7, row));
timeLineDialog.add(actionLabel, makeGbc(8, row));
setNewSeparator(9,row);
timeLineDialog.add(pitLabel,makeGbc(10, row));
timeLineDialog.add(pitTempLabel, makeGbc(11, row++));
setNewSeparator(12,row);
timeLineDialog.pack();
timeLineDialog.setLocationRelativeTo(GUI.getInstance().getFrame());
timeLineDialog.setVisible(true);
}
static void setNewSeparator(int column_,int row_) {
JSeparator sep=new JSeparator(SwingConstants.VERTICAL);
sep.setPreferredSize(new Dimension(1,1));
GridBagConstraints gbc=makeGbc(column_, row_);
gbc.fill=GridBagConstraints.VERTICAL;
gbc.weighty=1.;
timeLineDialog.add(sep,gbc);
}
static GridBagConstraints makeGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
Insets WEST_INSETS=new Insets(5,0,5,5);
Insets EAST_INSETS=new Insets(5,5,5,0);
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.anchor = (x == 0) ? GridBagConstraints.WEST : GridBagConstraints.EAST;
gbc.fill = (x == 0) ? GridBagConstraints.BOTH
: GridBagConstraints.HORIZONTAL;
gbc.insets = (x == 0) ? WEST_INSETS : EAST_INSETS;
gbc.weightx = (x == 0) ? 0.1 : 1.0;
gbc.weighty = 1.0;
return gbc;
}
}
有人可以解释我需要做什么才能使那些 headers 居中吗? TIA.
正如 VGR 在他的评论中所说,您应该在约束中设置网格宽度,以使 GridBagLayout 更容易理解如何处理两个顶部标签。
我会将目标标签的网格宽度设置为 7,将更改标签的网格宽度设置为 2。下面的所有标签都应设置为 1。
然后当您设置 GridBagConstraints.anchor = GridBagConstants.CENTER; 时,它应该会执行您正在寻找的行为。
编辑:我说目标标签为 5,但我的意思是 7。
提示:调试布局时,我发现将每个组件设置为不同的背景颜色很有用。然后我可以看到分配给该特定组件/由该特定组件填充的区域。大多数组件默认为透明背景,这意味着它们的边界是不可见的。 (例如targetHeader.setOpaque(true); targetHeader.setBackground(Color.RED);
)
您的布局情况是 JLabel 填充了您指定的 7 列。但是,标签本身会在其填充的 space 的最左侧绘制它包含的文本。
有两种替代解决方案:
告诉标签您希望它在标签内将文本居中:
targetHeader.setHorizontalAlignment(JLabel.CENTER);
或者,您可以告诉布局 而不是 填充 space。
gbc.fill=GridBagConstraints.NONE;