次批评我建议使用以下方法:
对于布局,答案始终是相同的:使用合适的LayoutManager
我在网上搜索了一下,但是没有找到对该主题的任何全面分析。所以我有以下问题:
我应该完全避免使用那些方法吗?
是,表示应用程序代码。
出于某种原因定义了这些方法。那么我什么时候应该使用它们呢?在哪种情况下?出于什么目的?
我不知道,我个人认为这是API设计事故。复合组件稍微强加了对子项大小有特殊想法的组件。“轻微”,因为他们应该已经使用自定义LayoutManager实现了他们的需求。
使用这些方法的负面后果到底是什么?(我只能考虑在具有不同屏幕分辨率的系统之间增加可移植性。)
某些技术原因(不完整,不幸的是,由于SwingLabs迁移到java.net而导致链接断开),例如,在“规则”(hehe)或他/她对我的答案的评论中找到的@bendicott链接中提到了技术原因。在社交上,将大量工作交给不幸的同事,他必须维护代码并必须查找损坏的布局。
我认为任何LayoutManager都不能完全满足所有所需的布局需求。我真的需要为我的布局中的每个小变化实现一个新的LayoutManager吗?
是的,有足够强大的LayoutManagers可以很好地满足“所有布局需求”。前三个是JGoodies FormLayout,MigLayout,DesignGridLayout。因此,实际上,除了简单的高度专业化的环境外,您很少编写LayoutManager。
如果对4的回答为“是”,这是否会导致LayoutManager类的泛滥而导致难以维护?
(对4的回答为“否”。)
在需要定义子组件之间比例的情况下(例如,子组件1应使用10%的空间,子组件2应占40%的空间,子组件3应占50%的空间),是否可以在不实现自定义LayoutManager的情况下实现这一点?
三巨头中的任何一个都不能甚至不可以使用GridBag(永远不要操心真正的大师,以太少的力气就麻烦很多)。
一些启发式:
不要使用set[Preferred|Maximum|Minimum]Size(),当你真的要重写get[Preferred|Maximum|Minimum]Size(),因为可能会创建自己的组件,显示做在这里。
如此处和以下所示,请不要使用set[Preferred|Maximum|Minimum]Size()您可以依赖于组件被仔细重写的内容。getPreferred|Maximum|Minimum]Size
一定要用于set[Preferred|Maximum|Minimum]Size()导出后validate()几何,如下所示和此处。
如果某个组件没有首选的大小,例如JDesktopPane,您可能必须调整容器的大小,但是任何这样的选择都是任意的。发表评论可能有助于澄清意图。
如发现这些注释中所述,当您发现必须遍历许多组件以获得派生的大小时,请考虑使用备用布局或自定义布局。
import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.GridLayout; import java.awt.KeyboardFocusManager; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; /** * @see https://stackoverflow.com/questions/7229226 * @see https://stackoverflow.com/questions/7228843 */ public class DesignTest { private List<JTextField> list = new ArrayList<JTextField>(); private JPanel panel = new JPanel(); private JScrollPane sp = new JScrollPane(panel); public static void main(String args[]) { EventQueue.invokeLater(new Runnable() { @Override public void run() { DesignTest id = new DesignTest(); id.create("My Project"); } }); } private void addField(String name) { JTextField jtf = new JTextField(16); panel.add(new JLabel(name, JLabel.LEFT)); panel.add(jtf); list.add(jtf); } private void create(String strProjectName) { panel.setLayout(new GridLayout(0, 1)); addField("First Name:"); addField("Last Name:"); addField("Address:"); addField("City:"); addField("Zip Code:"); addField("Phone:"); addField("Email Id:"); KeyboardFocusManager.getCurrentKeyboardFocusManager() .addPropertyChangeListener("permanentFocusOwner", new FocusDrivenScroller(panel)); // Show half the fields sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); sp.validate(); Dimension d = sp.getPreferredSize(); d.setSize(d.width, d.height / 2); sp.setPreferredSize(d); JInternalFrame internaFrame = new JInternalFrame(); internaFrame.add(sp); internaFrame.pack(); internaFrame.setVisible(true); JDesktopPane desktopPane = new JDesktopPane(); desktopPane.add(internaFrame); JFrame frmtest = new JFrame(); frmtest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frmtest.add(desktopPane); frmtest.pack(); // User's preference should be read from java.util.prefs.Preferences frmtest.setSize(400, 300); frmtest.setLocationRelativeTo(null); frmtest.setVisible(true); list.get(0).requestFocusInWindow(); } private static class FocusDrivenScroller implements PropertyChangeListener { private JComponent parent; public FocusDrivenScroller(JComponent parent) { this.parent = parent; } @Override public void propertyChange(PropertyChangeEvent evt) { Component focused = (Component) evt.getNewValue(); if (focused != null && SwingUtilities.isDescendingFrom(focused, parent)) { parent.scrollRectToVisible(focused.getBounds()); } } } }