#java #swing #jscrollpane #jtextpane #caret
Вопрос:
У меня есть JTextPane внутри JScrollPane и кнопка J, которая перемещает положение курсора из верхней части документа в нижнюю.
Моя цель-сохранить текущее значение полосы прокрутки при нажатии на кнопку. Я пытаюсь сделать это, сохранив значение полосы прокрутки перед перемещением курсора, а затем сбросив значение полосы прокрутки после перемещения курсора.
Вот странная часть: если я включу JOptionPane (всплывающее диалоговое окно) прямо перед сбросом значения полосы прокрутки, это сработает. Без всплывающего диалогового окна полоса прокрутки остается внизу. Что делает диалог, который объясняет эту разницу?
Примечание: Одна вещь, которую я проверил, заключается в том, что, когда открывается диалоговое окно, оно отвлекает внимание от текстовой панели. Но я попытался вручную переместить фокус с текстовой панели после перемещения курсора, И я попытался установить все компоненты в положение, недоступное для фокусировки, и ни один из них не изменил ситуацию.
Я в тупике. Удачи и спасибо!
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.DefaultCaret;
public class ScrollTest2 implements Runnable {
public static void main(String[] args) {
EventQueue.invokeLater(new ScrollTest2());
}
private JFrame frame;
private JScrollBar scrollBar;
private JTextPane textPane;
@Override
public void run() {
frame = new JFrame("Scroll Test 2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel mainPanel = new JPanel();
mainPanel.setPreferredSize(new Dimension(250, 100));
textPane = new JTextPane();
textPane.setEditable(false);
textPane.setText("hellonhellonhellonhellonhellonhellonhellonhellonhellonhello");
textPane.setFont(new Font("Courier New", Font.BOLD, 12));
JScrollPane scrollPane = new JScrollPane(textPane);
scrollPane.setPreferredSize(new Dimension(80, 80));
mainPanel.add(scrollPane);
scrollBar = scrollPane.getVerticalScrollBar();
JButton button = new JButton("Click me");
button.addActionListener(new ButtonListener());
mainPanel.add(button);
return mainPanel;
}
public class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// Get the scroll bar's position
int scrollPos = scrollBar.getValue();
// The scroll bar is sent to the bottom.
textPane.setCaretPosition(0);
textPane.setCaretPosition(textPane.getDocument().getLength());
/**
* Comment out this line to test.
* When this line is present, the scroll bar is set to its original position (correct).
* When this line is commented out, the scroll bar remains at the bottom (incorrect).
*/
JOptionPane.showMessageDialog(frame, "test", "dialog", JOptionPane.PLAIN_MESSAGE);
// Set scroll bar to its original position.
scrollBar.setValue(scrollPos);
}
}
}
Ответ №1:
Код Swing выполняется на Event Dispatch Thread (EDT)
. Иногда некоторые методы добавляют код в конец EDT, поэтому код выполняется не в том порядке, в котором вы ожидаете.
Я предполагаю setCaretPosition(...)
, что метод является одним из этих методов, что означает, что ваш код для сброса значения полосы прокрутки фактически выполняется до логики из метода setCaretPosition (), который вызывает прокрутку полосы прокрутки.
Вы можете добавить код в конец EDT следующим образом:
//scrollBar.setValue(scrollPos);
SwingUtilities.invokeLater(() -> scrollBar.setValue(scrollPos));
Добавление кода JOptionPane туда каким-то образом влияет на EDT и порядок выполнения.