- 这样做是错误的:
public class TestCatchClickPoint extends JFrame {
private Point p = new Point();
public TestCatchClickPoint() {
setBounds(100, 0, 200, 200);
setVisible(true);
JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.CENTER);
panel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
p = e.getPoint();
repaint();
}
});
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.drawString("m", p.x, p.y);
}
public static void main(String[] args) {
new TestCatchClickPoint();
}
}
结果字母m出现的位置,总比鼠标点击的实际位置差一点。原因是
p = e.getPoint();
获取的是鼠标相对于panel的位置,但是由于重写的是jframe的paint函数,所以会按照jframe的位置来画。
- 方案1:重写panle控件。
class MyJPanel extends JPanel{
private Point p = new Point();
public MyJPanel(){
super();
}
public void SetP(Point p){
this.p = p;
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.drawString("m", p.x, p.y);
}
}
//事件部分依然写在外部。原因:panel本身不应该有捕获鼠标位置的行为,而是交由jframe来控制。
panel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
p = e.getPoint();
panel.SetP(p);
repaint();
}
});
方案2:组件坐标转换
方案1的做法没有灵活性。假如将JPanel换成JLabel则又得重写label。所以需要一种更简单的方法。
此外,在那个组件中重写public void paint(Graphics g),则将坐标转化到那个组件。下文中的jframe只是个例子,可以替换成任意组件。根据组件与窗体的相对位置来计算
//先获取窗体的位置 private Point winLocation = this.getLocationOnScreen(); //捕获鼠标在屏幕上的位置 mouseP = new Point(e.getXOnScreen(),e.getYOnScreen()); //最终的位置 p.x = mouseP.x - winLocation.x; p.y = mouseP.y - winLocation.y;
根据现有函数来做:
javax.swing.SwingUtilities
//将JPanel捕获的坐标转化到JFrame中的坐标 Component source = panel; aPoint = e.getPoint();//鼠标在panel中的位置 destination = jframe; p = SwingUtilities.convertPoint(source,aPoint,destination); //将屏幕坐标转化成JFrame中的坐标 p = new Point(e.getXOnScreen(),e.getYOnScreen()); SwingUtilities.convertPointFromScreen(p, jf);