0

我正在尝试在视图和视口坐标之间进行转换。但是 JViewport/JScrollpane 似乎不像记录的那样工作。JViewport.toViewCoordinates() 认为视图总是在组件的左上角,即使显然不是这样。

String text = "blahblahblah\nblahblah\nblah";
JFrame frame = new JFrame("title");
JTextArea textArea = new JTextArea(text, 1, 30); // shows only one line
frame.add(new JScrollPane(textArea));
frame.pack();
frame.setVisible(true);
textArea.setCaretPosition(text.length()); // now showing the last line
JViewport viewport = ((JViewport)textArea.getParent());

viewport.getViewRect(); // returns java.awt.Rectangle[x=0,y=0,width=330,height=16]

viewport.getViewPosition(); // returns java.awt.Point[x=0,y=0]

viewport.toViewCoordinates(new Point(0,0)); // returns java.awt.Point[x=0,y=0]

以上是人为的例子。我的真实JTextArea大于一条线。我不需要 JTextArea “模型”坐标(文本中的偏移量)。我需要真正的二维坐标。

视图位置不应为 (0,0),因为视口中的第一个可见字符实际上位于 JTextArea 的第 3 行。

关于在使用 JScrollPane 时如何在视图和组件坐标之间进行转换的任何其他建议?

- - 添加 - -

这也失败了。

SwingUtilities.convertPoint(viewport,0,0, textArea);
(java.awt.Point) java.awt.Point[x=0,y=0]

- - 添加 - -

这是基于我收到的答案的最终工作版本。它显示java.awt.Point[x=0,y=32]了我所期望的。

@Test
public void test() throws InterruptedException {

    String text = "blahblahblah\nblahblah\nblah";
    JFrame frame = new JFrame("title");
    JTextArea textArea = new JTextArea(text, 1, 30);
    frame.add(new JScrollPane(textArea));
    frame.pack();
    frame.setVisible(true);
    textArea.setCaretPosition(text.length());
    final JViewport viewport = ((JViewport)textArea.getParent());

    SwingUtilities.invokeLater(new Runnable()
    {
        @Override
        public void run() {
            System.out.println(viewport.getViewPosition());
        }
    });

    Thread.sleep(1000);
}
4

2 回答 2

2

问题是获取 viewPosition() 的方法在视口实际滚动之前执行。这是因为有时 Swing 会将代码添加到事件线程的末尾以供以后处理。

通常可以通过将代码包装在 SwingUtilities.invokeLater() 中来解决此问题,以便在 Swing 完成所有处理后执行代码。但是在下面的简单演示中,我发现我需要添加两个 invokeLater() 方法。我不确定为什么。

向上/向下移动插入符号,您将看到视图位置发生变化。第二个值将包含正确的位置:

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;

public class Test5
{
    public static void createAndShowGUI()
    {
        String text = "one\ntwo\nthree\nfour\nfive";
        JFrame frame = new JFrame("title");
        JTextArea textArea = new JTextArea(text, 1, 30); // shows only one line
        JScrollPane scrollPane = new JScrollPane( textArea );
        frame.add(scrollPane);
        frame.pack();
        frame.setVisible(true);

        final JViewport viewport = scrollPane.getViewport();

        textArea.addCaretListener( new CaretListener()
        {
            public void caretUpdate(CaretEvent e)
            {
                SwingUtilities.invokeLater(new Runnable()
                {
                    public void run()
                    {
                        System.out.println("First : " + viewport.getViewPosition() );

                        SwingUtilities.invokeLater(new Runnable()
                        {
                            public void run()
                            {
                                System.out.println("Second: " + viewport.getViewPosition() );
                            }
                        });
                    }
                });
            }
        });

        textArea.setCaretPosition(text.length());
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
于 2010-08-28T03:18:40.070 回答
0

could

SwingUtilities.convertPoint

be of use?

于 2010-08-27T23:42:30.390 回答