参见标题。我试图将组件的方向更改为RIGHT_TO_LEFT
,但这产生了意外的副作用-对于具有指定首选大小的组件,它的行为异常。
(JDK 1.6.0_23,Eclipse VE)
编辑
这是一个例子:
我们上面有JFrame
和jMainScrollPane
。在jMainScrollPane
内部,放置一个jMainPanel
。现在将jMainPanel
的首选大小设置为小于jMainScrollPane
的首选大小。 jMainPanel
仍将占用jMainScrollPane
上的所有空间。现在将jMainScrollPane
的方向更改为RIGHT_TO_LEFT
,然后看看会发生什么。
示例代码(更改jMainScrollPane
的方向以查看不同之处):
import java.awt.BorderLayout;
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class TestFrame extends JFrame {
private JPanel jContentPane = null;
private JScrollPane jMainScrollPane = null;
private JPanel jMainPanel = null;
public TestFrame(){
super();
initialize();
}
private void initialize(){
this.setSize(480, 339);
this.setContentPane(getJContentPane());
this.setTitle("JFrame");
}
private JPanel getJContentPane(){
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
jContentPane.add(getJMainScrollPane(), BorderLayout.CENTER);
}
return jContentPane;
}
private JScrollPane getJMainScrollPane(){
if (jMainScrollPane == null) {
jMainScrollPane = new JScrollPane();
jMainScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
jMainScrollPane.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
jMainScrollPane.setViewportView(getJMainPanel());
}
return jMainScrollPane;
}
private JPanel getJMainPanel(){
if (jMainPanel == null) {
jMainPanel = new JPanel();
jMainPanel.setLayout(new BorderLayout());
jMainPanel.setPreferredSize(new Dimension(30, 30));
}
return jMainPanel;
}
}
编辑2
由于这种奇怪的性质,我已经向Oracle提交了一个错误。他们寄给我一个错误链接
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7038455
目前还没有这样的错误-我想,它正在被检查。
但是,问题仍然存在-是否有解决方法或其他方法?
最佳答案
同意OP:这是错误。 RToL方向的设置触发viewPosition的计算。这是在布局完成之前发生的。在这种情况下,JViewport返回视图的preferredSize而不是其实际大小(当时为零)。在肠子深处,BasicScrollPaneUI.Handler不知道该伪造的大小,而是基于错误的数据进行计算。
这是一些要使用的代码(OP原件进一步精简,添加了彩色边框以查看位置):
public class COInScrollPane extends JFrame {
public COInScrollPane(){
super();
initialize();
}
private void initialize(){
this.setTitle("JFrame");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JScrollPane jMainScrollPane = getJMainScrollPane();
this.add(jMainScrollPane);
this.setSize(480, 339);
Action action = new AbstractAction("Toggle CO") {
@Override
public void actionPerformed(ActionEvent e) {
ComponentOrientation co = jMainScrollPane.getComponentOrientation().isLeftToRight() ?
ComponentOrientation.RIGHT_TO_LEFT : ComponentOrientation.LEFT_TO_RIGHT;
jMainScrollPane.applyComponentOrientation(co);
jMainScrollPane.revalidate();
jMainScrollPane.repaint();
}
};
add(new JButton(action), BorderLayout.SOUTH);
}
private JScrollPane getJMainScrollPane() {
JScrollPane jMainScrollPane = new JScrollPane(getJMainPanel());
jMainScrollPane.setViewportBorder(BorderFactory
.createLineBorder(Color.GREEN));
jMainScrollPane
.applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
return jMainScrollPane;
}
private JPanel getJMainPanel() {
JPanel jMainPanel = new JPanel();
jMainPanel.add(new JButton("just a button"));
jMainPanel.setBorder(BorderFactory.createLineBorder(Color.RED));
return jMainPanel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new COInScrollPane().setVisible(true);
}
});
}
}
初始布局完全错误(如OP所述),请使用按钮两次切换CO-布局看起来还可以。
一个快速而肮脏的技巧可能就是在生产过程中这样做:在初始布局后,将CO强制放入LToR以允许正确的坐标,然后返回RToL。