Java MouseEvent位置不准确

2023-12-01

我在 Java 中使用我创建的“canvas”类遇到了问题,该类是一个扩展JPanel,绘制动画环形图。该图表使用的是MouseListener获取点击事件。

问题是鼠标位置似乎不准确,这意味着它似乎不是相对于“画布”,而是相对于窗口(在左上角,我得到了大约 30px 的 y 坐标)。

这是我的代码:

我创建了一个类,它扩展了 JPanel 并且有一个 BufferedImage 作为成员。

public class Canvas extends JPanel {

    public BufferedImage buf;
    private RingChart _parent;

    public Canvas(int width, int height, RingChart parent){
        buf = new BufferedImage(width, height, 1);
    ...

在绘画组件方法中,我只绘制缓冲图像,因此我可以通过在公共的缓冲图像上绘画来从“外部”在画布上绘画。

public void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D)g; 
        g2.drawImage(buf, null, 0, 0); 

    }

现在有一个包含“画布”的 RingChart 类:

public class RingChart extends JFrame{

    public Canvas c;
    ...

我从画布类中的 bufferedImage 创建一个 Graphics2D 。这个g2d用于绘画:

public RingChart(){
    c = new Canvas(1500,980,this);
    add(c);
    setSize(1500, 1000);
    setTitle("Hans");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    g2d = (Graphics2D)c.buf.createGraphics();
    ...

我现在想要实现的是一个鼠标侦听器,用于侦听画布上发生的鼠标事件。因此,当用户单击画布时,我可以通过事件变量检索他在画布上单击的位置。

所以我创建了一个鼠标监听器:

class MouseHandler implements MouseListener {

    @Override
    public void mouseClicked(MouseEvent e){
        RingChart r = ((Canvas)e.getSource()).getParent();
        r.mouseClick(e);
    }
    ...

...并将此鼠标侦听器添加到 RingChart 类的画布中(myChart 是 RingChart 的实例,c 是它包含的画布):

        ...
        MouseHandler mouse = new MouseHandler();
        myChart.c.addMouseListener(mouse);
        ...

但正如我上面提到的,调用单击事件时返回的鼠标位置似乎不准确。我认为错误一定是我创建 mouseListener 的方式,或者可能将其分配给错误的元素或类似的东西。但我已经尝试了很多事情,但情况并没有改变。也许有人可以告诉我,我做错了什么?

UPDATE:

函数“mouseClick”的代码是 RingChart 的成员并在鼠标侦听器中调用:

public void mouseClick(MouseEvent evt){
    //evt = SwingUtilities.convertMouseEvent(this, evt, c);
    if(evt.getButton() == MouseEvent.BUTTON1 && animation == null){
        for(Element e : elements){
            if(e.getShape() != null && e.getShape().contains(evt.getPoint())){
                //do some stuff
            }
        }
    }
}

再次,我的类的层次结构: RingChart --包含一个--> Canvas --得到一个--> MouseListener。 该函数中的形状是已经在画布上绘制的形状c。现在我想检查用户是否单击了其中之一。因此,正如我所想,形状应该在画布坐标中,事件位置应该在画布坐标中,并且所有东西都应该配合在一起。但事实并非如此。 现在用户 MadProgrammer 告诉我,使用 ConvertMouseEvent 函数。但我目前不知道应该以哪种方式明智地使用它。

UPDATE:

我找到了一个解决方案:我所要做的就是将画布添加到而不是直接添加到JFrame但到ContentPane of the JFrame反而:

所以与其:

public RingChart(){
    c = new Canvas(1500,980,this);
    add(c);
    ...

I do:

public RingChart(){
    c = new Canvas(1500,980,this);
    getContentPane().add(c);
    ...

然后我给MouseListener to the ContentPane.

getContentPane().addMouseListener(new MouseHandler());
getContentPane().addMouseMotionListener(new MouseMoveHandler());

我不知道这是否是一个优雅的解决方案,但它确实有效。


鼠标事件会自动转换为相对于它发生的组件,即点 0x0 始终是组件的左上角。

通过使用RingChart r = ((Canvas)e.getSource()).getParent(),您实际上已经更改了引用,这意味着该位置不再有效。

您需要转换位置,使其坐标位于父组件的上下文中。看一眼SwingUtilities.convertMouseEvent(组件,MouseEvent,组件)

用图片更新

让我们举这个例子...

Sample

蓝色框与红色框的相对位置为 50px x 50px。如果您单击蓝色框,假设在 25x25,鼠标坐标将相对于蓝色框(0x0 将位于蓝色框的左上角)。

如果您随后将此事件传递给红色框并尝试使用其中的坐标,您会发现坐标现在将位于红色框左上角和蓝色框之间的中间位置,因为坐标是上下文相关的。

为了让它工作,您需要将鼠标事件位置从蓝色框转换为红色框,这将使其变为 75x75

现在,我不知道当您将鼠标事件传递给RingChart所以我只是猜测这就是您面临的问题。

已更新点击代码

好吧,假设你有一个Canvas100x100。你点击那个Canvas50x50。然后,您将该值传递回链上。

public void mouseClick(MouseEvent evt){
    //evt = SwingUtilities.convertMouseEvent(this, evt, c);
    if(evt.getButton() == MouseEvent.BUTTON1 && animation == null){
        for(Element e : elements){
            // Here, we are asking the shape if it contains the point 50x50...
            // Not 150x150 which would be the relative position of the click
            // in the context to the RingChart, which is where all your objects
            // are laid out.
            // So even the original Canvas you clicked on will return 
            // false because it's position + size (100x100x width x height) 
            // does not contain the specified point of 50x50...
            if(e.getShape() != null && e.getShape().contains(evt.getPoint())){
                //do some stuff
            }
        }
    }
}

UPDATED

我认为你的参考文献的方式是错误的......

public static MouseEvent convertMouseEvent(Component source,
                       MouseEvent sourceEvent,
                       Component destination)

我认为它应该读成类似

evt = SwingUtilities.convertMouseEvent(evt.getComponent(), evt, this);

更新代码示例

好吧,我把这个小例子放在一起......

public class TestMouseClickPoint extends JFrame {

    private ContentPane content;

    public TestMouseClickPoint() throws HeadlessException {

        setSize(600, 600);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        setLayout(new BorderLayout());

        content = new ContentPane();
        add(content);

    }

    protected void updateClickPoint(MouseEvent evt) {
        content.updateClickPoint(evt);
    }

    protected class ContentPane extends JPanel {

        private Point relativePoint;
        private Point absolutePoint;

        public ContentPane() {
            setPreferredSize(new Dimension(600, 600));
            setLayout(null); // For testing purpose only...

            MousePane mousePane = new MousePane();
            mousePane.setBounds(100, 100, 400, 400);

            add(mousePane);
        }

        protected void updateClickPoint(MouseEvent evt) {
            absolutePoint = new Point(evt.getPoint());
            evt = SwingUtilities.convertMouseEvent(evt.getComponent(), evt, this);
            relativePoint = new Point(evt.getPoint());

            System.out.println(absolutePoint);
            System.out.println(relativePoint);

            repaint();
        }

        protected void paintCross(Graphics2D g2d, Point p) {
            g2d.drawLine(p.x - 5, p.y - 5, p.x + 5, p.y + 5);
            g2d.drawLine(p.x - 5, p.y + 5, p.x + 5, p.y - 5);
        }

        /*
         * This is not recommended, but I want to paint ontop of everything...
         */
        @Override
        public void paint(Graphics g) {
            super.paint(g);

            Graphics2D g2d = (Graphics2D) g;

            if (relativePoint != null) {
                g2d.setColor(Color.BLACK);
                paintCross(g2d, relativePoint);
            }

            if (absolutePoint != null) {
                g2d.setColor(Color.RED);
                paintCross(g2d, absolutePoint);
            }

        }
    }

    protected class MousePane extends JPanel {

        private Point clickPoint;

        public MousePane() {

            addMouseListener(new MouseAdapter() {

                @Override
                public void mouseClicked(MouseEvent e) {
                    clickPoint = e.getPoint();
                    TestMouseClickPoint.this.updateClickPoint(e);
                    repaint();
                }
            });

            setBorder(new LineBorder(Color.RED));

        }

        @Override
        protected void paintComponent(Graphics g) {

            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.BLUE);

            if (clickPoint != null) {
                g2d.drawLine(clickPoint.x, clickPoint.y - 5, clickPoint.x, clickPoint.y + 5);
                g2d.drawLine(clickPoint.x - 5, clickPoint.y, clickPoint.x + 5, clickPoint.y);
            }

        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException ex) {
        } catch (InstantiationException ex) {
        } catch (IllegalAccessException ex) {
        } catch (UnsupportedLookAndFeelException ex) {
        }

        new TestMouseClickPoint().setVisible(true);
    }
}

基本上,它会画三个点。鼠标单击的点(相对于事件源)、父容器中未转换的点以及父容器中转换后的点。

enter image description here

您需要做的下一件事是确定鼠标位置实际上已转换,如果失败。我可能需要查看您的代码的工作示例来确定您实际上在做什么。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java MouseEvent位置不准确 的相关文章

随机推荐

  • 静态变量是否可以继承

    我已经在 1000 个位置读到静态变量不能被继承 但是这段代码如何正常工作呢 父类 java public class Parent static String str Parent 孩子 java public class Child e
  • Swift 可编码多种类型

    我尝试解析返回 json 对象的 api 我的问题是 某些键有时是字符串 有时是对象 如以下示例中的键 Value Description null Group Beskrivning av enheten GroupDescription
  • 使用纵横比时 CSS 会忽略子元素的宽度

    我遇到了有关 CSS 的问题aspect ratio在子元素上 我一直在尝试将元素的宽度和高度 两者相同 设置为等于父容器的高度 使用height 100 and aspect ratio 1 然而 这可以实现 使用时父容器似乎忽略了子容器
  • 有没有办法从 SQL 中的日期中减去天数?

    我知道 DATEDIFF d date1 date2 但我不想减去两个日期 而是减去一个日期的天数 例如 2010 04 13 4 2010 04 09 mySQL 可以吗 date sub date interval 4 day
  • 生成具有预定义模数和指数的公钥

    n rKZ 1zdz CoLekSynOtyWv6cPSSkV28Kb9kZZHyYL yhkKnH bHl8OpWiGxQiKP0ulLRIaq1IhSMetkZ8FfXH iptIDu4lPb8gt0HQYkjcy3HoaKRXBw2F
  • 使用 vstack 的全屏背景图像

    我想要一个带有导航视图的全屏背景图像 必须位于顶部 因为它来自基础视图 而不是通常位于 此 视图中 在此视图中 我想要一个位于安全区域内的 VStack 位于导航栏和底部布局之间 不幸的是我得到了 见图 I expected the tex
  • 使用外部计算的变量的回调函数

    基本上我想做这样的事情 arr 1 2 3 4 5 6 7 8 9 10 avg array sum arr count arr callback function val return val lt avg return array fi
  • Python SciPy 卡方测试返回与 Excel 和 LibreOffice 不同的 p 值

    读完一篇后最近的博客文章关于泊松分布的应用程序 我尝试使用 Python 的 scipy stats 模块以及 Excel LibreOffice POISSON 和 CHITEST 函数重现其发现 对于文章中显示的预期值 我简单地使用了
  • 如何使用 PowerShell 引用 .NET 程序集

    我是一名 C NET 开发人员 架构师 并且了解它使用对象 NET 对象 而不仅仅是流 文本 我希望能够使用 PowerShell 调用我的 NET C 库 程序集上的方法 如何在 PowerShell 中引用程序集并使用该程序集 通过 P
  • 警告:文件大小功能无法运行[关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 以下代码 结果是 Warning filesize function filesize
  • 在空白行上拆分 Pandas DataFrame

    我有一个大数据框 需要将其拆分为空行 这是 DataFrame 的简化示例 A B C 0 1 0 International 1 1 1 International 2 NaN 2 International 3 1 3 Internat
  • 循环遍历范围以查找匹配的字符串谷歌脚本

    我试图循环遍历电子表格的顶部标题行 以根据标题名称查找列的索引号 这样如果有人插入列 我的代码就不会中断 这是我到目前为止所拥有的 var sheet SpreadsheetApp getActive getSheetByName RawD
  • SharedPreferences ListPreference NullPointerException

    我试图在我的首选项 xml 中设置频率列表 但我不断收到此错误 我也附上了所有相关文件 我相信我设置的值是正确的 但我找不到当前的错误所在 另外 当我使用 SharedPreferences getString key defaultVal
  • 如何初始化类句柄向量?

    我有一个基于句柄的类 我需要创建它的向量 执行此操作的一个简单方法是在 for 循环中动态构造向量 但这会导致mlint抱怨向量大小的变化 classdef HandleClass lt handle end for i 1 10 foo
  • 启用分组时保留现有 Excel 工作表保护

    我试图允许在工作表中进行分组 EnableOutlined 下面是一个允许它的典型示例 但它也会重置指定的所有保护属性 不幸的是我不知道现有的属性是什么 设置分组属性时是否有简单的方法保留现有的保护属性 Private Sub Workbo
  • Java 8、JCE 无限强度策略和 TLS 上的 SSL 握手

    使用Java 8 服务器仅支持TLSv1 它无法从 centOS 建立安全套接字连接 Version java version 1 8 0 45 Java TM SE Runtime Environment build 1 8 0 45 b
  • 如何使用自定义概率分布进行随机选择

    我有一份来自美国人口普查网站的美国姓名及其各自的姓名列表 我想使用给定的概率从此列表中生成一个随机名称 数据在这里 美国人口普查数据 我见过类似的算法轮盘赌选择算法很容易实现 但我想知道是否有任何方法可以在 O 1 中生成随机名称 为了直方
  • gcloud docker 推送可靠性

    我在推送图像时遇到了很多问题gcloud docker push过去几周 我已经阅读了许多堆栈溢出讨论以及 github 问题和解决方法 但我还没有找到解决不一致问题的方法 通常我会尝试推送一两个容器镜像 第一次推送几乎总是会失败 并显示以
  • 如何将我的谷歌地图应用程序转换为谷歌地球应用程序?

    在maps google com上 您可以看到一个精彩的例子 展示谷歌地图应用程序如何突然顺利地变成谷歌地球应用程序 我正在开发一个谷歌地图应用程序 使用 API 版本 3 我在 Google Earth API 摘要中阅读了以下行 如果您
  • Java MouseEvent位置不准确

    我在 Java 中使用我创建的 canvas 类遇到了问题 该类是一个扩展JPanel 绘制动画环形图 该图表使用的是MouseListener获取点击事件 问题是鼠标位置似乎不准确 这意味着它似乎不是相对于 画布 而是相对于窗口 在左上角