Edit 4
(希望是最后一个:-)
最终的罪魁祸首似乎是scrollPane的主视口:一旦它小于其首选视图,在RToL中调整其视图大小时,它就会感到困惑。没有跟踪到底出了什么问题,但看起来是一个可行的(缺少找到核心中的错误并推动 snoracle 修复它;)解决方案是使视图实现 Scrollablable,具体实现
- getPreferredScrollableViewportSize 返回 getPreferredSize
- 实现 getScrollableTracksViewportHeight/Width 以在高度/宽度小于父级高度/宽度时返回 true,否则返回 false
JXPanel(包含在SwingX http://swingx.java.net) 是一个 Scrollable,默认执行第一个操作,并且可以通过适当设置 ScrollableSizeHints 来配置后者:
private JPanel initPnlButton() {
JXPanel pnlButton = new JXPanel(new GridBagLayout());
pnlButton.setScrollableWidthHint(ScrollableSizeHint.PREFERRED_STRETCH);
pnlButton.setScrollableHeightHint(ScrollableSizeHint.PREFERRED_STRETCH);
...
}
完成后,不需要更多的 hacky 行,只需在添加所有组件后应用 CO:
applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
pack();
setExtendedState(JFrame.MAXIMIZED_BOTH);
setVisible(true);
Edit 2
我们(@Reza Gh 和我)使用选项越多,我就越倾向于将这种行为视为错误。总结我们的最新发现
- 滚动窗格似乎是罪魁祸首(Reza)
- 一旦面板的大小调整到/低于其首选大小,错误行为就会开始(注意人工 - 至少我希望它不是 Reza 的生产代码的一部分 - 创建面板时设置首选)
Edit
多玩一点,在我看来,实例化时的行为非常奇怪。一个可以使用的片段(在实例化结束时)
pack();
// [1]
setSize(getWidth() + 1, getHeight() + 1);
// [2]
setExtendedState(JFrame.MAXIMIZED_BOTH);
setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
}
});
并评论 1、2 或两者
- 评论两者:框架以压缩尺寸出现,最大化它不会填充框架,但子元素停靠在右边缘
- 评论 1:框架以最大化尺寸出现,子项填充完成的内容,然后调整大小以打包并再次最大化:子项未填充
- 评论 2:框架提供了几乎(大一像素)的压缩尺寸,最大化(以及所有其他调整大小)正确填充屏幕
确切的行为可能也取决于本机组件的方向(我的是 LToR)。总的来说,我认为这是组件方向核心处理中的一个错误(毫不奇怪,多年来它并不像我们预期的那么稳定)。
看起来一个 hack 方法是在打包后调整大小(稍微调整 1 个像素左右,单独使用 max 不起作用),然后调用 applyCO。
Original
这并没有解决最初的问题(即在框架实例化时应用 componentOrientation),仅演示如何在运行时安全地切换 CO
Action createCOToggle(final JFrame frame) {
Action toggleComponentOrientation = new AbstractAction("toggle orientation") {
@Override
public void actionPerformed(ActionEvent e) {
ComponentOrientation current = frame.getComponentOrientation();
if (current.isLeftToRight()) {
frame.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
} else {
frame.applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
}
frame.getRootPane().revalidate();
frame.invalidate();
frame.validate();
frame.repaint();
}
};
return toggleComponentOrientation;
}
用它配置一个动作感知组件,将使框架的行为符合预期,即填充整个区域。许多重新/输入/验证看起来很奇怪 - 但结果证明是必要的(在 jdk6 中),正如我们在SwingX 测试覆盖率 http://swingx.java.net
现在我的期望是,在框架实例化结束时调用相同的操作也会使其表现良好,即
.... // configure/fill frame
setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createCOToggle(MyFrame.this).actionPerformed(null);
}
});
不幸的是,事实并非如此。目前不知道为什么不,抱歉。