我有JScrollPane m_jScrollPane
,其中显示JLabel m_jlImage
。 m_jlImage
是一个屏幕截图,用户最后点击屏幕时会显示一个红点。我希望移动(读取滚动)m_jScrollPane
上{+ 1}}上红点的查看区域。 m_jlImage
是用户点击的最后一个位置,与lastClick
位于同一坐标中。
事实证明这更加困难。
我决定将点击点的值与屏幕的整个长度的比率沿同一轴线进行比较,然后按相应的最大比例滚动相应的滚动条。这似乎只有在最后点击屏幕上的点位于左上角时才有效。
当点击的点位于屏幕边缘时,我不确定如何处理这种情况。此方案生成一个比率,导致滚动条以相同的比例滚动,但红点滚动到视图之外,因为它位于屏幕的边缘。关于我怎么能过来这个的任何建议?
m_jlImage
答案 0 :(得分:4)
这是一个非常基本的例子。它使用一个图像文件并将其放置在一个滚动窗格内(绕一个方向)。
从那里,它只是使用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<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();
}
}
}
现在,如果您希望将点显示为尽可能靠近中心,则需要额外的工作......
现在,如果你真的想玩得开心,可以将延迟设置为50-100毫秒;)