将视口移到更大的图像上; JLablel + JScrollPane [英] Moving a view port over a larger image; 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屋!