[英]Moving a view port over a larger image; JLablel+JScrollPane
I have a JScrollPane m_jScrollPane
with a JLabel m_jlImage
being displayed inside of it. 我有一个JScrollPane m_jScrollPane
,其中显示了一个JLabel m_jlImage
。 The m_jlImage
is a screen capture with a red dot drawn where the user last clicked on the screen. m_jlImage
是屏幕截图,在用户最后一次单击屏幕的地方绘制了一个红点。 I wish to move (read scroll) the viewing area of the m_jScrollPane
over the red dot on the m_jlImage
. 我想移动(读滚动)的的可视面积m_jScrollPane
过的红点m_jlImage
。 lastClick
is the last place the user clicked and is in the same coordinates as m_jlImage
. lastClick
是用户单击的最后一个位置,并且与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). 它使用图像文件并将其放置在滚动窗格中(以某种方式循环)。
From there, it simply uses a Swing Timer
to randomly generate points (within the bounds of the image). 从那里开始,它仅使用Swing Timer
随机生成点(在图像范围内)。
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. 每次生成新点时,我只需使用scrollToRectVisible
,向其传递要渲染的点的位置和大小。 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... 现在,如果要显示尽可能靠近中心的点,则需要进行额外的工作...
Now, if you really want to have fun, set the delay to something like 50 - 100 milliseconds ;) 现在,如果您真的想玩得开心,请将延迟设置为50-100毫秒;)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.