将视口移到更大的图像上; JLablel + JScrollPane [英] Moving a view port over a larger image; JLablel+JScrollPane

查看:44
本文介绍了将视口移到更大的图像上; JLablel + JScrollPane的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个JScrollPane m_jScrollPane,其中显示了JLabel m_jlImage. m_jlImage是屏幕截图,在用户最后一次单击屏幕的地方绘制了一个红点.我希望将m_jScrollPane的查看区域移动(滚动)在m_jlImage上的红点上. lastClick是用户单击的最后一个位置,并且位于与m_jlImage相同的坐标中.

I have a JScrollPane m_jScrollPane with a JLabel m_jlImage being displayed inside of it. The m_jlImage is a screen capture with a red dot drawn where the user last clicked on the screen. I wish to move (read scroll) the viewing area of the m_jScrollPane over the red dot on the m_jlImage. lastClick is the last place the user clicked and is in the same coordinates as m_jlImage.

事实证明,这比我想的要困难.

This is proving to be more difficult that I thought.

我决定获取点击点的值与沿着同一轴的整个屏幕长度的比率,并以最大的相同比率滚动相应的滚动条.这似乎仅在屏幕上最后单击的点在左上角时才有效.

I decided to get the ratio of the click point's value to the entire length of the screen along the same axis, and scroll the corresponding scroll bar by that same ratio of its maximum. This seems to only work if the point last clicked on the screen is in the upper left hand corner.

当单击的点位于屏幕边缘时,我不确定如何处理这种情况.这种情况下会产生一个比率,导致滚动条以相同的比率滚动,但是由于红点位于屏幕边缘,因此红点被滚动到视线之外.关于我该如何解决的任何建议?

I am not sure how to handle the situation when the clicked point is on the edge of the screen. This scenario produces a ratio, causing the scroll bar to scroll by the same ratio, but the red dot is scrolled out of view because it is on the edge of the screen. Any suggestions on how could I over come this?

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

推荐答案

这是一个非常基本的示例.它使用图像文件并将其放置在滚动窗格中(以一种循环方式).

This is a pretty basic example. It uses a image file and places it within a scrollpane (in a round about way).

从那里开始,它仅使用Swing Timer随机生成点(在图像范围内).

From there, it simply uses a Swing Timer to randomly generate points (within the bounds of the image).

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

Each time a new point is generated, I simply use scrollToRectVisible, passing it the location and the size of the point I want to render. This will ensure that the new point (and the dot) is visible within the scroll pane.

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<Point> 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 + p.x - radius / 2;
                        int y = yOff + p.y - 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();
        }
    }
}

现在,如果要显示尽可能靠近中心的点,则需要进行额外的工作...

Now, if you want to display the point as close to the centre as possible, that will require additional work...

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

Now, if you really want to have fun, set the delay to something like 50 - 100 milliseconds ;)

这篇关于将视口移到更大的图像上; JLablel + JScrollPane的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆