How to scroll two JTextPane's?

2019-02-21 17:39发布

I am a Swing novice using NetBeans. I want to vertically scroll two side-by-side JTextPane's. The scrolling should be syncronized and done through a single scrollbar.

If I add JTextPanes from the NetBean designer they are automatically put inside a JScrollPane so they scroll independently. I have deleted the enclosing scroll panes and put them in a JPanel instead so the JPanel can be the client of a single JScrollPane. This seems to work except that when the JTextPanes are very long they seem to go beyong the end of the JPanel. I can scroll the panel and both text panes to a certain point. When I reach the bottom I can put a cusor in one of the text panes and arrow down beyond my field of view.

Here is code from my main method. I have copied the layout from something that was generated by the NetBeans designer.

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);
}
});

Here is an image that shows my implementation of the first answer where the text panes are not limited to the horizontal display area. Image showing text panes that are too wide for the horizontal display area

And this image shows the text panes limited in the horizontal display area but this example has the original issue of not scrolling vertically if the text panes are very long. Image showing text panes that are bounded horizontally

2条回答
手持菜刀,她持情操
2楼-- · 2019-02-21 18:14

If you use a GridLayout for both of your JTextPane and then wrap it with JScrollPane, the Scroll Bar will be for both JTextPanes since the GridLayout gets divided into equal sized rectangles.

Something like this should work (Tested on 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);

If you use the above approach, if amending text to either JTextPanes overflow the dimensions, the scroll bar will appear and when used, it will scroll both of the components. If amending text overflows a component, it will scroll down so your input will be visible.

Hope that helps!

查看更多
成全新的幸福
3楼-- · 2019-02-21 18:15

A trick I've used before is to use two JScrollPanes, hide the vertical scroll bar for the left pane, and set its model to the model for the right scroll pane. That way, when the user scrolls the right scroll bar, it updates both scroll panes, since they share the same model. Here is an example that also has dual synchronized horizontal scroll bars at the bottom:

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());

// ...

Note that it might not work so well if your JTextPanes have different sizes (I haven't tried it, but my best guess is it would cause problems)

You can also fix mouse wheel scrolling by redirecting wheel events from the left scroll pane to the right one:

spLeft.setWheelScrollingEnabled(false);
spLeft.addMouseWheelListener(new MouseWheelListener() {
    public void mouseWheelMoved(MouseWheelEvent e) {
        spRight.dispatchEvent(e);
    }
});
查看更多
登录 后发表回答