将视口移动到更大的图像上; JLablel + JScrollPane的

我有一个JScrollPane m_jScrollPane ,里面显示了一个JLabel m_jlImagem_jlImage是一个屏幕截图,在用户最后点击屏幕的位置绘制了一个红点。 我希望移动(读取滚动) m_jScrollPane的查看区域在m_jScrollPane上的红点上。 lastClick是用户单击的最后一个位置,与m_jlImage位于相同的坐标中。

事实certificate这比我想象的要困难得多。

我决定将点击点的值与屏幕的整个长度的比率沿同一轴线进行比较,然后按相应的最大比例滚动相应的滚动条。 这似乎只有在屏幕上最后点击的点位于左上角时才有效。

当点击的点位于屏幕边缘时,我不确定如何处理这种情况。 此方案生成一个比率,导致滚动条以相同的比例滚动,但红点滚动到视图之外,因为它位于屏幕的边缘。 关于我怎么能得到这个的任何建议?

  public void scrollViewToLastClick() { int clckH = lastClick.y; int clckW = lastClick.x; int picH = this.m_jlImage.getHeight(); int picW = this.m_jlImage.getWidth(); int ratW = (int)(m_jScrollPane.getWidth()*(double)clckW/(double)picW); int ratH = (int)(m_jScrollPane.getHeight()*(double)clckH/(double)picH); m_jScrollPane.getHorizontalScrollBar().setValue(ratW); m_jScrollPane.getVerticalScrollBar().setValue(ratH); } 

这是一个非常基本的例子。 它使用一个图像文件并将其放置在一个滚动窗格内(在一个圆形的方式)。

从那里,它只是使用Swing Timer来随机生成点(在图像的边界内)。

每次生成一个新点时,我只需使用scrollToRectVisible ,传递它想要渲染的点的位置和大小。 这将确保新点(和点)在滚动窗格中可见。

在此处输入图像描述

 import java.awt.Color; import java.awt.EventQueue; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.LineBorder; public class ScrollTest { public static void main(String[] args) { new ScrollTest(); } private JScrollPane scrollPane; private DesktopPane desktopPane; public ScrollTest() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } try { desktopPane = new DesktopPane(); scrollPane = new JScrollPane(desktopPane); JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(scrollPane); frame.setSize(desktopPane.getPreferredSize().width / 2, desktopPane.getPreferredSize().height / 2); frame.setLocationRelativeTo(null); frame.setVisible(true); } catch (IOException exp) { exp.printStackTrace(); } } }); } public class DesktopPane extends JLayeredPane { private List points; public DesktopPane() throws IOException { points = new ArrayList<>(25); final BufferedImage img = ImageIO.read(new File("Desktop.jpg")); final JLabel desktop = new JLabel(new ImageIcon(img)); final JPanel overlay = new JPanel() { @Override protected void paintComponent(Graphics g) { super.paintComponent(g); int xOff = desktop.getX(); int yOff = desktop.getY(); int count = 0; FontMetrics fm = g.getFontMetrics(); int height = fm.getHeight(); for (Point p : points) { g.setColor(Color.RED); String text = Integer.toString(++count); int width = fm.stringWidth(text); int radius = Math.max(width, height) + 5; int x = xOff + px - radius / 2; int y = yOff + py - radius / 2; g.fillOval(x, y, radius, radius); g.setColor(Color.WHITE); x += (radius - width) / 2; y += ((radius - height) / 2) + fm.getAscent(); g.drawString(text, x, y); } } }; overlay.setOpaque(false); setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.weightx = 1; gbc.weighty = 1; gbc.fill = GridBagConstraints.BOTH; add(desktop, gbc); add(overlay, gbc); setLayer(desktop, 0); setLayer(overlay, 5); overlay.setBorder(new LineBorder(Color.RED)); Timer timer = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int x = (int) Math.round(Math.random() * img.getWidth()); int y = (int) Math.round(Math.random() * img.getHeight()); points.add(new Point(x, y)); repaint(); FontMetrics fm = getFontMetrics(overlay.getFont()); int height = fm.getHeight(); String text = Integer.toString(points.size() - 1); int width = fm.stringWidth(text); int radius = Math.max(width, height) + 5; scrollRectToVisible(new Rectangle(x - radius / 2, y - radius / 2, radius, radius)); } }); timer.start(); } } } 

现在,如果要将点显示为尽可能靠近中心,则需要额外的工作……

现在,如果你真的想玩得开心,可以将延迟设置为50-100毫秒;)