QML - 捕获子对象的所有 UI 事件

Posted

技术标签:

【中文标题】QML - 捕获子对象的所有 UI 事件【英文标题】:QML - Capture all UI events of children objects 【发布时间】:2017-05-15 21:56:37 【问题描述】:

在我的 QML 项目中,我需要一个对象来捕获其子对象的所有 UI 事件。因此,如果它的任何子对象注册了单击或其他内容,则父对象需要知道它。这里的问题是所有子对象都是预定义的类,例如 MyButton 或 MyComboBox。这些类都定义了不能被覆盖的 MouseAreas 和 onClicked() 函数。因此,我需要父对象在不修改子对象的 MouseAreas 的情况下捕获其子对象的所有事件。请告诉我完成此任务的最佳方法。

【问题讨论】:

你需要知道哪个MouseArea被点击了吗? 【参考方案1】:

您可以爬取对象树,将一个函数连接到每个onClicked-信号。

为此,我们需要三个部分:

应连接的信号 进行爬取的函数 创建另一个函数以使用自定义参数调用信号的函数。

我选择了,我的信号必须有参数:senderarguments。 Sender 是我点击的对象,arguments 是被点击对象的clicked 信号的参数。这对于 QtQuick.Controls 2.x Buttons 是空的,并且包含一个用于 MouseAreas 的条目 (mouse)。

signal somethingWasClicked(var sender, var arguments)

由于对于每个可点击对象,此信号与clicked 的签名不同,因此我们无法将其直接连接到此信号。我们需要一个为我们调用信号的中间函数,在它的范围内有所需的参数并且没有参数。我们需要为我们监视的每个对象动态构建它。

function createSpyFunction(object) 
    return function()  somethingWasClicked(object, arguments) 

最后是爬虫功能。我们需要将我们创建的函数存储在某个地方。为此,我利用了所有 QtObjects 在某种意义上都是 JS 对象的事实,因此我可以对它们使用 Object.defineProperty to dynamically add JS-properties。在这里我可以存储我们的函数,而不需要自己修改组件的源代码。 创建此函数后,我将connect它发送到onClicked-handler。

function crawlChildren(obj) 
    if (obj.onClicked) 
        Object.defineProperty(obj, '__clickedFunction',  value: createSpyFunction(obj) )
        obj.onClicked.connect(obj.__clickedFunction)
    
    if (obj.children) 
        var i = 0
        for (; i < obj.children.length; i++) 
            crawlChildren(obj.children[i])
        
    

这个函数我终于调用了

Component.onCompleted: crawlObj(this.contentItem)

我的程序的根ApplicationWindow


因为我只在Component.onCompleted-handler 中调用它,在此之后添加的对象不会被监视。为了改变这一点,我们还需要监视onChildrenChanged,并抓取新添加的对象。那里的过程几乎相似,所以这留给用户作为练习,或者可能会受到新问题的影响。

【讨论】:

是的,它做到了。谢谢!【参考方案2】:

您可以尝试使用MouseArea 覆盖您的项目。在事件处理程序中,您可以检查位置并调用底层项目的事件处理程序。

Item 
  MyButton  id: mybutton
      /* set the anchors */
  
  MyMouseComboBox  id: myMouseComboBox 
     /* set the anchors */
  

  MouseArea 
     anchros.fill: parent
     onClicked: 
         // mouse.accepted = false
         // Check whether clicked point is within mybutton
         //   on true, call mybutton.doSomething()
         //   or call mybotton.onPressed(mouse)
     

【讨论】:

那么你不能在任何其他MouseAreas 中处理onPressed-handler 没有。可以通过调用mybutton.onPressed(mouse) 来调用处理程序 是的,所以你需要通过对象树找到所有MouseAreas,其中它们的层是未知的。 OP 写了关于自定义组件的使用。所以我假设他知道哪些组件正在使用以及位置在哪里。否则需要另一种解决方案。 如果是这样,他可以直接处理事件

以上是关于QML - 捕获子对象的所有 UI 事件的主要内容,如果未能解决你的问题,请参考以下文章

订阅并捕获子控件点击事件

[JS]笔记12之事件机制--事件冒泡和捕获--事件监听--阻止事件传播

如何捕获 QML 绘图缓冲区

iOS子线程操作UI

在 WPF 的子线程中捕获未处理的异常

使用具有UI控制的所有状态的1个图像在QT / QML中创建UI