【问题标题】:How do I add a MouseListener to a graphics object inside another graphics object?如何将 MouseListener 添加到另一个图形对象内的图形对象?
【发布时间】:2012-04-02 05:56:14
【问题描述】:

我正在开发纸牌游戏的 GUI,为了熟悉起见,我正在使用 ACM's student graphics library。我编写了一个程序,可以将我的单人纸牌游戏绘制到屏幕上,但无法使其具有交互性。

背景:

这里有很多类,我会尽力描述它们。

  • 包含应用程序的顶级 JFrame。
    • GCanvas(包含所有图形对象)
      • SolitaireGameControl(GCompound 持有构成纸牌游戏的所有其他 GCompound)
        • Array of PileViews,一堆卡片(由一组卡片组成的GCompound)
          • 卡片(由矩形和标签组成的 GCompound)

(GCompound: 被视为一个对象的图形对象的集合。(如果 car 是 GCompound,它将有 GOval[] wheels, GRect body,因此当我将它添加到画布时,它会显示作为一个对象))

从顶级类看到的卡片看起来有点像这样:jFrame.gCanvas.solitaireGameControl.pileViews[pile number].cardView

我一直在尝试为每张卡片添加一个 MouseListener,这样当点击卡片并触发 MouseEvent 时,MouseEvent e.getSource() = 被点击的卡片。

现在是这样的:

public SolitaireGameControl(SolitaireGame game) {
    this.game = game; // Model of the game.
    this.pileViews = PileView.getPileViews(game.drawPiles); // ArrayList of PileViews (the pile of cards)

    for(PileView pv : pileViews) {
        for(CardView cv : pv.cardViews) {
            cv.addMouseListener(this); // add a mouseListener to the card
        }
    }

    this.addMouseListener(this); // if I don't include this, nothing happens when I click anything. If I do include this, this whole object is the source.
}

@Override
public void mouseClicked(MouseEvent e) {
    System.out.println(e.getSource()); // should return the card I clicked.
}

当我运行这个程序时,每个事件的来源都是 SolitaireGameControl,当然我离开了this.addMouseListener(this);。如果我取出这个语句,根本不会打印任何内容,这让我相信我添加的 mouseListeners 只工作了一层。 (画布上的第一个 GCompound,而不是其中的 GCompound。)

因此,我的问题如下:有没有办法为一个 GCompound inside of a GCompound inside of a GCompound 获取 MouseListener,并让 MouseEvent 的 getSource 到正确识别卡?如果没有,有没有办法重组我的程序以使其按预期工作? (我知道我真的应该为初学者使用更好的图形库。)

【问题讨论】:

  • 请查看我的代码here 以了解在桌子周围拖动扑克牌的示例。
  • 有趣!那么,您所做的是使用图像创建 JLabels,将它们设置到 JLayeredPane 上,然后在每个上放置一个 mouseListener?
  • 另外,Component comp = basePane.getComponentAt(mEvt.getPoint()); 似乎是我正在寻找可以解决我的问题的代码类型......如果同一点有多个组件,它如何确定哪一个选择?是从最顶层选卡吗?

标签: java graphics mouselistener


【解决方案1】:

这是有道理的。根据我的经验,如果我将一些组件放在顶级容器中,则该容器就是接收输入事件的容器。

您是否尝试过类似的方法:

/* This is the mouse listener for the top-level container. */
@Override
public void mouseClicked(MouseEvent e) {
    for(PileView pv : pileViews) {
        for(CardView cv : pv.cardViews) {
            if(cv.getBounds().contains(e.getPoint())) {
                cv.dispatchEvent(e);
            }
        }
    }
}

... 然后正常处理“CardView”级别上的鼠标点击。

当顶级容器接收到鼠标事件时,它会根据事件的位置检查鼠标是否与卡片交互(如果卡片的区域包含该点)。如果是,它会将鼠标事件传递给卡片的鼠标侦听器。

我假设“pv.cardViews”开头附近的元素是更靠前的卡片。

【讨论】:

  • 非常有帮助!我现在正在尝试,但我不确定 getBounds 是否返回任何有用的东西。我正在查看调试器中的所有内容,并为每个 getBounds 获取矩形,其输出如下:"cv.getBounds()"= GRectangle (id=119) myHeight= 141.0 myWidth= 81.0 xc= 0.0 yc= 15.0 每次单击卡片时,检查都会失败。
  • pastebin.com/JZQ5Zxj4 - 为了更好地解释,这里是输出。我的观点是鼠标指针的坐标。下面的每一行都是该字段的 getbounds() 输出上的卡片。 X 的坐标似乎都是 0.0,可能是相对于它们的父级 PileViews,它们将它们添加到(0,0 0,15 0,30 等)
  • 啊哈!我想我明白了! PileView pv = (PileView) this.getElementAt(p); CardView cv = (CardView) pv.getElementAt(pv.getLocalPoint(p)); - 问题在于,在每个 GObject 中,都会在 (0,0) 处创建一个新的坐标网格,以便一切都可以相对于对象。在稍微修改了代码之后,我想出了如何将这些局部坐标更改为整个 GCanvas 上的坐标。它现在似乎有效。谢谢!
  • 你是对的。 Component.getBounds() 是相对于组件的,意思是 (0, 0) 是组件的角而不是容器。另一方面, MouseEvent.getPoint() 是相对于容器的。所以组件上的 (0, 0) 可能是容器上的 (100, 100)。另外,如果这解决了您的问题,请将其标记为答案;)
猜你喜欢
  • 2018-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多