将JScrollPane的可见区域移动到特定位置

时间:2015-11-30 23:42:19

标签: java swing awt

我正在尝试使用java模拟调试游标的移动。我有问题将JScrollPane的可视区域放到正确的位置。

这是我想要拍摄的照片: The desired layout

我想只在我想要跳过它的行不可见时滚动。使用这些常量在面板上绘制使用CodeDrowingPanel.NUMBER_OF_LINESCodeDrowingPanel.FONT_SIZE完成帮助的计算。

如果我必须跳,我必须跳的线应该在底部。

我必须记住,可见区域取决于屏幕分辨率。应用程序最大化,无法调整大小。

修改

public void setCursorToLine(int line, JScrollPane codeArea)
{
    if(line*CodeDrowingPanel.FONT_SIZE > this.getHeight()+43)
        this.cursorPosition = this.getHeight()+43;
    else
        this.cursorPosition = line * CodeDrowingPanel.FONT_SIZE;
    JViewport viewPort = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, codeArea);
    if (viewPort != null) 
    {
        Rectangle view = viewPort.getViewRect();
        view.y += line - previousLine;

        codeArea.scrollRectToVisible(view);
    }
    this.repaint();
}

这就是我现在尝试修改的方法。但它不起作用。我尝试从第一条评论中跟随你的第二个例子。我不知道如何使用第二条评论中的方法。

2 个答案:

答案 0 :(得分:2)

这是一个简单的示例,使用JListJScrollPane rowHeader支持。

Scroll rect to visible

魔法基本上发生在这里......

int index = list.getSelectedIndex();
index++;
if (index >= list.getModel().getSize()) {
    index = 0;
}
list.setSelectedIndex(index);
Rectangle cellBounds = list.getCellBounds(index, index);
list.scrollRectToVisible(cellBounds);

基本上,我们要求视图计算由所选索引表示的Rectangle,并简单地要求组件滚动以便矩形可见

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JList list;

        public TestPane() {
            setLayout(new BorderLayout());
            DefaultListModel model = new DefaultListModel();
            try (BufferedReader br = new BufferedReader(new FileReader(new File("src/test/Test.java")))) {
                String text = null;
                while ((text = br.readLine()) != null) {
                    model.addElement(text);
                }
            } catch (IOException exp) {
                exp.printStackTrace();
            }
            list = new JList(model);
            list.setSelectedIndex(0);
            JScrollPane sp = new JScrollPane(list);
            sp.setRowHeaderView(new Header(list));

            add(sp);

            JButton next = new JButton("Next");
            next.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    int index = list.getSelectedIndex();
                    index++;
                    if (index >= list.getModel().getSize()) {
                        index = 0;
                    }
                    list.setSelectedIndex(index);
                    Rectangle cellBounds = list.getCellBounds(index, index);
                    list.scrollRectToVisible(cellBounds);
                }
            });

            add(next, BorderLayout.SOUTH);
        }

    }

    protected class Header extends JPanel {

        private JList list;

        public Header(JList list) {
            this.list = list;
            list.addListSelectionListener(new ListSelectionListener() {
                @Override
                public void valueChanged(ListSelectionEvent e) {
                    repaint();
                }
            });
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Container parent = list.getParent();
            if (parent instanceof JViewport) {
                JViewport viewport = (JViewport) parent;
                Graphics2D g2d = (Graphics2D) g.create();
                int selectedRow = list.getSelectedIndex();
                if (selectedRow >= 0) {
                    Rectangle cellBounds = list.getCellBounds(selectedRow, selectedRow);
                    cellBounds.y -= viewport.getViewPosition().y;
                    g2d.setColor(Color.RED);
                    g2d.fillRect(0, cellBounds.y, getWidth(), cellBounds.height);
                }
                g2d.dispose();
            }
        }

    }

}

答案 1 :(得分:2)

enter image description here

我不认为行号应该是文本的一部分。例如,您有一个水平滚动条。如果向右滚动,则会丢失行号。

相反,您应该使用行标题来显示行号。

Text Component Line Number。它包含一个为您自定义绘制行号的类。您可以使用将此组件添加到行标题。

该类中的绘制代码将突出显示当前行号。如果要添加箭头,则需要修改绘制代码。在paintComponent(...)方法中,您可以添加以下内容:

g.drawString(lineNumber, x, y);  

//  Code to paint an arrow

if (isCurrentLine(rowStartOffset))
{
    int height = fontMetrics.getAscent() - fontMetrics.getDescent();

    Polygon triangle = new Polygon();
    triangle.addPoint(borderGap, y);
    triangle.addPoint(borderGap, y - height);
    triangle.addPoint(borderGap + 10, y - height / 2);
    Graphics2D g2d = (Graphics2D)g.create();
    g2d.fill( triangle );
    g2d.dispose();
}

要做的另一个改变。由于我们现在正在绘制箭头,我们需要增加组件的宽度。因此,在setPreferredWidth(...)方法中,您需要进行以下更改:

//int preferredWidth = insets.left + insets.right + width;
int preferredWidth = insets.left + insets.right + width + 15;
  

我想只在我想要跳过它的行不可见时滚动。

以下是一些代码:

public static void gotoStartOfLine(JTextComponent component, int line)
{
    Element root = component.getDocument().getDefaultRootElement();
    line = Math.max(line, 1);
    line = Math.min(line, root.getElementCount());
    int startOfLineOffset = root.getElement( line - 1 ).getStartOffset();
    component.setCaretPosition( startOfLineOffset );
}

我从Text Utilities获取了上述代码,其中可能有其他感兴趣的方法(如果不是现在,将来)。

如果要在文本窗格中突出显示整行,也可以使用Line Painter