gpt4 book ai didi

java - 在父容器中使用子组件的 getBaseline(int w, int h)

转载 作者:搜寻专家 更新时间:2023-11-01 03:42:08 25 4
gpt4 key购买 nike

我有一个自定义的 swing 组件,它有一些子元素,包括一个 JTextField。我想为容器提供与 JTextField 相同的基线,因此我覆盖了容器中的 getBaseline 方法。但是当为容器调用 getBaseline 时,并不总是设置 JTextField 的位置。我试图在容器的 getBaseline 方法中添加对 doLayout 的调用,但这没有帮助。我想要的是以下内容:

public int getBaseline(int w, int h) {
Dimension size = textField.getPreferredSize();
int textBaseline = textField.getBaseline(size.width, size.height);
int textY = textField.getY();
return textY + textBaseline;
}

在上面的代码中,textY 等于 0。

我写了一些代码来说明这个问题。第一次单击“添加”时,基线是错误的。第二次是正确的。

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

class CustomComponent extends JPanel {

public CustomComponent() {
setLayout(new GridBagLayout());
textField.setColumns(8);
layoutElements();
}

public void addComponent() {
JPanel comp = new JPanel();
comp.setPreferredSize(new Dimension(50, 200));
comp.setBackground(Color.red);
otherComponents.add(comp);
layoutElements();
}

public int getBaseline(int w, int h) {
Dimension size = textField.getPreferredSize();
return textField.getY() + textField.getBaseline(size.width, size.height);
}

public Component.BaselineResizeBehavior getBaselineResizeBehavior() {
return Component.BaselineResizeBehavior.CONSTANT_DESCENT;
}

private void layoutElements() {
removeAll();
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.SOUTH;
add(textField, constraints);

for (JPanel comp : otherComponents)
add(comp, new GridBagConstraints());
if (getParent() != null)
getParent().validate();
}

private JTextField textField = new JTextField();
private ArrayList<JPanel> otherComponents = new ArrayList<JPanel>();
}

public class Main {

public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
frame.getContentPane().add(panel);

JButton addComponent = new JButton("Add");
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.BASELINE;
panel.add(addComponent, constraints);

final CustomComponent customComp = new CustomComponent();
panel.add(customComp, constraints);

addComponent.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
customComp.addComponent();
}
});

frame.setSize(400, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

最佳答案

最初的评论,只是一个确认:

可以确认 GridBag(您的确切示例)或 MigLayout 的外部布局问题。如果外部布局是 FlowLayout,则可以修改。在那种情况下,在计算基线之前强制布局就足够了

@Override
public int getBaseline(int w, int h) {
// helps with simple managers like FlowLayout
// detoriates with powerful managers like GridBag or Mig
doLayout();
Dimension size = textField.getPreferredSize();
return textField.getY() + textField.getBaseline(size.width, size.height);
}

在 main 的外部面板中:

FlowLayout flow = new FlowLayout();
flow.setAlignOnBaseline(true);
panel.setLayout(flow);

不多,但也许你可以从这里深入挖掘......

编辑 暂定解决方案(?或破解)和对可能原因的思考

看起来它需要一个强制的两遍布局过程:

private void layoutElements() {
removeAll();
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.SOUTH;
add(textField, constraints);

for (JPanel comp : otherComponents)
add(comp, new GridBagConstraints());
if (getParent() != null) {
getParent().validate();
getParent().revalidate();
}
}

请注意验证与重新验证的顺序 - 由于某些原因,两者都是必需的。不知道确切的机制,只是随机猜测:

  • 布局是自上而下进行的,因此如果父级依赖于子级对所有孙级进行布局,就可以解释两次传递的必要性。与孙子相关的基线就是这样的条件
  • 第一遍发生在更广泛的上下文中,即在第一次验证结束时并非所有状态都已完全完成。然后重新验证保证第二次通过发生在所有正在进行的更改完成之后。

关于java - 在父容器中使用子组件的 getBaseline(int w, int h),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11726739/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com