有没有办法根据JPanel中显示的顺序(左上角到右下角)获取JPanel中的组件列表,而不是它们添加到JPanel的顺序?
这似乎使组件按照它们添加到面板中的顺序
Component[] comps = myJPanel.getComponents();
答案 0 :(得分:4)
查看Container#getFocusTraversalPolicy
,它会返回一个FocusTraversalPolicy
,其中包含确定通过容器进行焦点移动的方法。
这(应该)为您提供组件的自然顺序(从布局管理器和焦点管理器的角度来看)
我从FocusTraversalPolicy#getFirstComponent(Container)
和FocusTraversalPolicy#getComponentAfter(Container, Component)
如果这不起作用,您可能需要为自己编写一个自定义Comparator
并相应地对组件数组进行排序
更新 - 焦点遍历示例
public class ComponentOrder {
public static void main(String[] args) {
new ComponentOrder();
}
public ComponentOrder() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
BodyPane body = new BodyPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(body);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Container focusRoot = body.getFocusCycleRootAncestor();
FocusTraversalPolicy ftp = focusRoot.getFocusTraversalPolicy();
Component comp = ftp.getFirstComponent(body);
Component first = comp;
while (comp != null) {
System.out.println(" - " + comp);
comp = ftp.getComponentAfter(focusRoot, comp);
if (comp.equals(first)) {
break;
}
}
}
});
}
public class BodyPane extends JPanel {
private JTextField fldFirstName;
private JTextField fldMiddleName;
private JTextField fldLastName;
private JTextField fldDateOfBirth;
private JTextField fldEMail;
private JButton okButton;
private JButton cancelButton;
public BodyPane() {
setLayout(new BorderLayout());
add(createFieldsPane());
add(createButtonsPane(), BorderLayout.SOUTH);
}
public JPanel createButtonsPane() {
JPanel panel = new JPanel(new FlowLayout());
panel.add((okButton = createButton("Ok")));
panel.add((cancelButton = createButton("Cancel")));
return panel;
}
protected JButton createButton(String text) {
return new JButton(text);
}
public JPanel createFieldsPane() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
panel.add(createLabel("First Name:"), gbc);
gbc.gridy++;
panel.add(createLabel("Middle Name:"), gbc);
gbc.gridy++;
panel.add(createLabel("Last Name:"), gbc);
gbc.gridy++;
panel.add(createLabel("Date of Birth:"), gbc);
gbc.gridy++;
panel.add(createLabel("EMail:"), gbc);
gbc.gridy = 0;
gbc.gridx++;
gbc.weightx = 1;
panel.add((fldFirstName = createField()), gbc);
gbc.gridy++;
panel.add((fldLastName = createField()), gbc);
gbc.gridy++;
panel.add((fldMiddleName = createField()), gbc);
gbc.gridy++;
panel.add((fldDateOfBirth = createField()), gbc);
gbc.gridy++;
panel.add((fldEMail = createField()), gbc);
JPanel filler = new JPanel();
filler.setOpaque(false);
gbc.gridy++;
gbc.weightx = 1;
gbc.weighty = 1;
panel.add(filler, gbc);
return panel;
}
protected JLabel createLabel(String text) {
return new JLabel(text);
}
protected JTextField createField() {
JTextField field = new JTextField(12);
return field;
}
}
}
以下示例使用比较器来确定组件的流量。此版本将父容器中的所有组件转换为容器坐标空间,因此应该可以将其与复合容器一起使用。
nb 我从javax.swing.LayoutComparator
偷走了比较器,它是受保护的(这对SwingTeam很好)并修改它以将组件坐标转换回父坐标空间
public class ComponentOrder {
public static void main(String[] args) {
new ComponentOrder();
}
public ComponentOrder() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
BodyPane body = new BodyPane();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(body);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
List<Component> components = new ArrayList<Component>(25);
getContents(body, components);
LayoutComparator lc = new LayoutComparator(body);
lc.setComponentOrientation(body.getComponentOrientation());
Collections.sort(components, lc);
for (Component comp : components) {
System.out.println(comp);
}
}
});
}
protected void getContents(Container container, List<Component> components) {
for (Component comp : container.getComponents()) {
components.add(comp);
if (comp instanceof Container) {
getContents((Container) comp, components);
}
}
}
public class BodyPane extends JPanel {
private JTextField fldFirstName;
private JTextField fldMiddleName;
private JTextField fldLastName;
private JTextField fldDateOfBirth;
private JTextField fldEMail;
private JButton okButton;
private JButton cancelButton;
public BodyPane() {
setLayout(new BorderLayout());
add(createFieldsPane());
add(createButtonsPane(), BorderLayout.SOUTH);
}
public JPanel createButtonsPane() {
JPanel panel = new JPanel(new FlowLayout());
panel.add((okButton = createButton("Ok")));
panel.add((cancelButton = createButton("Cancel")));
return panel;
}
protected JButton createButton(String text) {
return new JButton(text);
}
public JPanel createFieldsPane() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(2, 2, 2, 2);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
panel.add(createLabel("First Name:"), gbc);
gbc.gridy++;
panel.add(createLabel("Middle Name:"), gbc);
gbc.gridy++;
panel.add(createLabel("Last Name:"), gbc);
gbc.gridy++;
panel.add(createLabel("Date of Birth:"), gbc);
gbc.gridy++;
panel.add(createLabel("EMail:"), gbc);
gbc.gridy = 0;
gbc.gridx++;
gbc.weightx = 1;
panel.add((fldFirstName = createField("FirstName")), gbc);
gbc.gridy++;
panel.add((fldLastName = createField("LastName")), gbc);
gbc.gridy++;
panel.add((fldMiddleName = createField("MiddleName")), gbc);
gbc.gridy++;
panel.add((fldDateOfBirth = createField("DateOfBirth")), gbc);
gbc.gridy++;
panel.add((fldEMail = createField("EMail")), gbc);
JPanel filler = new JPanel();
filler.setOpaque(false);
gbc.gridy++;
gbc.weightx = 1;
gbc.weighty = 1;
panel.add(filler, gbc);
return panel;
}
protected JLabel createLabel(String text) {
JLabel label = new JLabel(text);
label.setName(text);
return label;
}
protected JTextField createField(String name) {
JTextField field = new JTextField(12);
field.setName("Field-" + name);
return field;
}
}
public class LayoutComparator implements Comparator<Component>, java.io.Serializable {
private static final int ROW_TOLERANCE = 10;
private boolean horizontal = true;
private boolean leftToRight = true;
private Component parent;
public LayoutComparator(Component parent) {
this.parent = parent;
}
void setComponentOrientation(ComponentOrientation orientation) {
horizontal = orientation.isHorizontal();
leftToRight = orientation.isLeftToRight();
}
public int compare(Component a, Component b) {
if (a == b) {
return 0;
}
// Row/Column algorithm only applies to siblings. If 'a' and 'b'
// aren't siblings, then we need to find their most inferior
// ancestors which share a parent. Compute the ancestory lists for
// each Component and then search from the Window down until the
// hierarchy branches.
if (a.getParent() != b.getParent()) {
LinkedList<Component> aAncestory = new LinkedList<Component>();
for (; a != null; a = a.getParent()) {
aAncestory.add(a);
if (a instanceof Window) {
break;
}
}
if (a == null) {
// 'a' is not part of a Window hierarchy. Can't cope.
throw new ClassCastException();
}
LinkedList<Component> bAncestory = new LinkedList<Component>();
for (; b != null; b = b.getParent()) {
bAncestory.add(b);
if (b instanceof Window) {
break;
}
}
if (b == null) {
// 'b' is not part of a Window hierarchy. Can't cope.
throw new ClassCastException();
}
for (ListIterator<Component> aIter = aAncestory.listIterator(aAncestory.size()),
bIter = bAncestory.listIterator(bAncestory.size());;) {
if (aIter.hasPrevious()) {
a = aIter.previous();
} else {
// a is an ancestor of b
return -1;
}
if (bIter.hasPrevious()) {
b = bIter.previous();
} else {
// b is an ancestor of a
return 1;
}
if (a != b) {
break;
}
}
}
Point pa = SwingUtilities.convertPoint(a, a.getLocation(), parent);
Point pb = SwingUtilities.convertPoint(b, b.getLocation(), parent);
int ax = pa.x, ay = pa.y, bx = pb.x, by = pb.y;
int zOrder = a.getParent().getComponentZOrder(a) - b.getParent().getComponentZOrder(b);
if (horizontal) {
if (leftToRight) {
// LT - Western Europe (optional for Japanese, Chinese, Korean)
if (Math.abs(ay - by) < ROW_TOLERANCE) {
return (ax < bx) ? -1 : ((ax > bx) ? 1 : zOrder);
} else {
return (ay < by) ? -1 : 1;
}
} else { // !leftToRight
// RT - Middle East (Arabic, Hebrew)
if (Math.abs(ay - by) < ROW_TOLERANCE) {
return (ax > bx) ? -1 : ((ax < bx) ? 1 : zOrder);
} else {
return (ay < by) ? -1 : 1;
}
}
} else { // !horizontal
if (leftToRight) {
// TL - Mongolian
if (Math.abs(ax - bx) < ROW_TOLERANCE) {
return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder);
} else {
return (ax < bx) ? -1 : 1;
}
} else { // !leftToRight
// TR - Japanese, Chinese, Korean
if (Math.abs(ax - bx) < ROW_TOLERANCE) {
return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder);
} else {
return (ax > bx) ? -1 : 1;
}
}
}
}
}
}
答案 1 :(得分:0)
虽然之前提交的解决方案非常巧妙,但(整体)满足我的大部分要求的方法相当简单,并且依赖于窗口架构在左上角具有零 - 零(根)点。 / p>
由于确切的编码取决于您选择使用哪些库,让我以启发式方式描述随后的过程:
任何一点(x,y)
与原点的距离为(x^2 + y^2)**(0.5)
。使用这个可以构造一个阴影数组,它用一个数字镜像每一对。通过简单地对这些距离中的每一个进行关系递增排序,可以得到左上角到右下角的相当好的近似值。
应该避免(或至少理解)一些病理学的例子。例如,使用指向屏幕左上角的指南针将生成与原点完全相同距离的无限数量的点。
为了解决这个问题,我们可以简单地将x
或y
值预先加倍,然后对其进行平方并将其与所述的其他单位平方相结合。这将为"y"
按比例增加值,该值高于靠近窗口左边缘的x
,反之亦然。