Swing JScrollPane - 如何将垂直滚动条设置为左侧?

3
看标题就知道了。我试图将组件方向更改为RIGHT_TO_LEFT,但这会导致意外的副作用 - 它与指定首选大小的组件表现得很奇怪。(JDK 1.6.0_23,Eclipse VE)
编辑
这是一个例子:
我们有一个带有的。在内部,我们放置一个。现在将的首选大小设置为比窄。 仍将占据上的所有空间。现在更改的方向为RIGHT_TO_LEFT,看看会发生什么。
示例代码(更改的方向以查看差异):
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

目前还没有这样的错误 - 我想,正在检查中。

但是,问题仍然存在 - 是否有解决方法或其他方式?


1
@Manoj似乎@Frozen_Spider已经尝试了提到问题的答案,但对结果不满意。 - Riduidel
@Frozen_Spider 当你说“里面的布局被破坏了”时,能否告诉我们你的意思?或者发送一张截图? - Riduidel
我现在无法提供您代码示例或屏幕截图。您能否耐心等待,直到明天? - Alex Abdugafarov
1
我注意到你有两个JScrollPane,主要的一个是查看jMainPanel,第二个则没有任何作用。为什么你要这样设计呢?如果你的意图是为了触发jMainPanel的垂直滚动条,你只需要使用JMainPanel.setPreferredSize(new Dimension(500, 400));,并且删除我看不出有任何作用的第二个JScrollPane - eee
显示剩余3条评论
1个回答

3

同意楼上的观点:这是一个错误。RToL方向的设置会触发viewPosition的计算。这在布局完成之前发生。在这种情况下,JViewport返回视图的preferredSize而不是其实际大小(此时为零)。在BasicScrollPaneUI.Handler中,由于没有了真正的大小信息,所以它基于不正确的数据进行计算。

以下是一些代码可供测试(原始代码已经简化,并添加了彩色边框以查看位置):

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设置为从左到右,以允许正确的坐标,然后再设置回从右到左。


感谢你,脏技巧有效 :) 我也发布了一个错误链接,但是——我真惭愧——我描述的错误比你更糟糕。 - Alex Abdugafarov
@Frozen Spider,很高兴它对你有用 :-) 评论ID是什么(自动错误响应上的数字)? - kleopatra
这个 bug 到底有什么秘密... 一些 bug 由于安全原因未包含在 Bug 数据库中。 - eee
无论如何,这已经在http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4845945之前报告过了。 - eee
错误ID已发布在问题底部:7038455@eee:看来你是对的。好吧,我很高兴他们知道这件事。 - Alex Abdugafarov
由于Oracle的贡献,上述的7038455错误已经不存在了,而4845945错误则被注释为(1)一个404的讨论链接,(2)一条说明“应该在下一个版本中修复”,然后(3)仅仅以“不会修复”的方式关闭,并没有进一步提供任何信息。唉。 - Ti Strga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接