如何滚动两个JTextPane?

9

我是一个使用NetBeans的Swing新手。我想要垂直滚动两个并排的JTextPane。滚动应该同步,并通过单个滚动条完成。

如果我从NetBean设计器中添加JTextPanes,它们会自动放置在JScrollPane中,因此它们可以独立滚动。我已经删除了包含的滚动窗格,并将它们放在JPanel中,以便JPanel可以成为单个JScrollPane的客户端。这似乎有效,但当JTextPanes非常长时,它们似乎超出了JPanel的末端。我可以滚动面板和两个文本窗格到一定程度。当我到达底部时,我可以在其中一个文本窗格中放置一个光标并向下箭头超出我的视野范围。

这是我的主要方法中的代码。我复制了由NetBeans设计器生成的布局。

java.awt.EventQueue.invokeLater(new Runnable() {
    public void run() {
topFrame aTopFrame = new topFrame();
JScrollPane scollBothDiffs = new javax.swing.JScrollPane();
JPanel bothDiffsPanel = new javax.swing.JPanel();
JTextPane leftDiffPane = diffPane1;
JTextPane rightDiffPane = diffPane2;


javax.swing.GroupLayout bothDiffsPanelLayout = new javax.swing.GroupLayout(bothDiffsPanel);
bothDiffsPanel.setLayout(bothDiffsPanelLayout);
bothDiffsPanelLayout.setHorizontalGroup(
    bothDiffsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    .addGroup(bothDiffsPanelLayout.createSequentialGroup()
        .addGap(20, 20, 20)
        .addComponent(leftDiffPane, javax.swing.GroupLayout.PREFERRED_SIZE, 463, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(rightDiffPane, javax.swing.GroupLayout.PREFERRED_SIZE, 463, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addContainerGap(52, Short.MAX_VALUE))
);
bothDiffsPanelLayout.setVerticalGroup(
    bothDiffsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, bothDiffsPanelLayout.createSequentialGroup()
        .addContainerGap()
        .addGroup(bothDiffsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
            .addComponent(rightDiffPane, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 630, Short.MAX_VALUE)
            .addComponent(leftDiffPane, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 630, Short.MAX_VALUE))
        .addContainerGap())
);

scollBothDiffs.setViewportView(bothDiffsPanel);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(aTopFrame.getContentPane());
aTopFrame.getContentPane().setLayout(layout);
layout.setHorizontalGroup(
    layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    .addGroup(layout.createSequentialGroup()
        .addGap(20, 20, 20)
        .addComponent(scollBothDiffs, javax.swing.GroupLayout.DEFAULT_SIZE, 997, Short.MAX_VALUE)
        .addContainerGap())
);
layout.setVerticalGroup(
    layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(scollBothDiffs, javax.swing.GroupLayout.DEFAULT_SIZE, 671, Short.MAX_VALUE)
        .addContainerGap())
);

aTopFrame.pack();
aTopFrame.setVisible(true);
}
});

这里有一张图片展示了我对第一个答案的实现,其中文本窗格不限于水平显示区域。 图片展示了文本窗格宽度超出水平显示区域 而这张图片则展示了文本窗格在水平显示区域内受限的情况,但是如果文本窗格非常长,则会出现垂直滚动问题。
2个回答

17

我之前使用的一个技巧是使用两个JScrollPane,隐藏左侧面板的垂直滚动条,并将其模型设置为右侧滚动面板的模型。这样,当用户滚动右侧滚动条时,它会更新两个滚动面板,因为它们共享同一模型。此处提供一个示例,还有底部的双向水平滚动条:

JTextPane leftDiffPane = diffPane1;
JTextPane rightDiffPane = diffPane2;
JScrollPane spLeft = new JScrollPane(leftDiffPane, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
JScrollPane spRight = new JScrollPane(leftDiffPane, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
spLeft.getHorizontalScrollBar().setModel(spRight.getHorizontalScrollBar().getModel());
spLeft.getVerticalScrollBar().setModel(spRight.getVerticalScrollBar().getModel());

// ...

请注意,如果您的JTextPanes大小不同,则可能效果不佳(我没有尝试过,但我的最佳猜测是会导致问题)。

您还可以通过将滚轮事件从左侧滚动窗格重定向到右侧滚动窗格来修复鼠标滚轮滚动:

spLeft.setWheelScrollingEnabled(false);
spLeft.addMouseWheelListener(new MouseWheelListener() {
    public void mouseWheelMoved(MouseWheelEvent e) {
        spRight.dispatchEvent(e);
    }
});

这个几乎可以工作,但是左侧窗格比右侧宽,因为右侧被滚动条占用了一些宽度。这意味着两个窗格不会包裹相同的内容,所以当你向下滚动窗格时,文本会失去同步。 - mikeatv
@mikeatv:阅读Swing教程,学习如何正确使用布局管理器,确保两个JScrollPane显示相同的滚动条。 - Hovercraft Full Of Eels
3
不需要隐藏滚动条,只需共享模型,您可以使用任何一个滚动条来滚动两个文本窗格。是的,此技术仅适用于相同大小的文本窗格。 - camickr
这个对我有用,但我更喜欢不使用两个滚动条。 - mikeatv
1
@mikeatv - 你是指两个水平滚动条吗?你可以隐藏它们并在面板下方使用JScrollBar。难点在于正确地将滚动窗格的滚动模型与滚动条绑定,我认为有界范围必须相同。 - Kevin K
不需要隐藏滚动条,对于我来说,这对于相同大小的图像有效。 - 18446744073709551615

4
如果您为您的JTextPane使用GridLayout,并将其与JScrollPane包装,则滚动条将用于两个JTextPanes,因为GridLayout被分成相等大小的矩形。类似这样的东西应该可以工作(在Java 6上测试过)。
// Text Panes initialization. I am just setting text so you can see
// what each pane is.
JTextPane leftDiffPane = new JTextPane();
leftDiffPane.setText("left");
JTextPane rightDiffPane = new JTextPane();
rightDiffPane.setText("right");

// Wrap the Text Panes with a Panel since you can only
// have a single component within a scroll pane.      
JPanel bothDiffsPanel = new JPanel();
bothDiffsPanel.setLayout(new GridLayout(1, 2));
bothDiffsPanel.add(leftDiffPane, BorderLayout.WEST);
bothDiffsPanel.add(rightDiffPane, BorderLayout.EAST);

// Fill in the frame with both of the panels.
setLayout(new BorderLayout());
add(new JScrollPane(bothDiffsPanel), BorderLayout.CENTER);

如果您使用以上的方法,当向JTextPanes添加文本使其超出尺寸时,滚动条将出现。当使用滚动条时,它将同时滚动两个组件。如果添加的文本超出了一个组件的尺寸,它会向下滚动以确保您的输入可见。
希望这能帮到您!

这看起来很有前途。谢谢。但现在文本窗格不受水平显示区域的限制。它们不会自动换行并滚动到侧面。换行是第一种情况下使文本窗格变得如此长的原因。为了进行比较,这些窗格需要同时可见。 - mikeatv
没问题,你所说的“受水平显示区域限制”是什么意思?上面的窗格可以同时显示以进行比较。如果在左侧和右侧各添加20行,但视图区域只有10行,如果滚动左侧窗格,则右侧窗格也会被滚动。你想要不同的行为吗? - Mohamed Mansour
我已经在问题中添加了图片,以展示文本窗格不受水平显示区域限制的含义。我希望它们可以分割包含框架的水平显示区域。 - mikeatv
在第二张图中,文本窗格的宽度受到最大限制。这是可以接受的。如果包含框架的调整后宽度比某个合理值更窄,我不需要窗格分裂可用宽度。然而,文本窗格将保留一些非常长的行,因此它们必须受到限制。无论是通过包含框架还是通过某个合理值来实现。 - mikeatv

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