您的位置:首页 > 编程语言 > Qt开发

Qt Widget重叠放置和兄弟Widget的事件传递

2016-12-21 12:12 120 查看

问题的提出

在项目中有一个要求:需将两个widget重叠放置,并且上面的widget为透明背景。

解决方案

在谷歌搜索中找到一个比较可行的解决方案,利用QGridLayout布局管理器对象实现两个Widget的重叠放置。

可以手动也可以利用QDesigner,将第一个widget加入到QGridLayout布局管理器对象中。

gridLayout->addWidget(widget_1, 0, 0, 1, 1);


第二个widget只能手动编码加入到QGridLayout中,并且和第一个widget放置在同一个单元格中,这样,第二个widget就可以重叠放置在第一个widget上面。

gridLayout->addWidget(widget_2, 0, 0, 1, 1);


问题的提出续

这样的确可以实现两个widget的重叠放置,但却带来了另一个问题,那就是底下的widget被上层的widget覆盖,底下的widget无法接受到任何事件通知了。

解决方案续

在国内搜索到,有个牛叉的人提出了一个可行的方案。重载第一个widget的事件处理函数,将其接收的事件再转发给第二个widget(底下的widget)。以鼠标移动事件为例。

void Widget_1::mouseMoveEvent(QMouseEvent *event) {
QWidget::mouseMoveEvent(event);
//第一个widget需要的事件
Process(event);
//将事件传递给兄弟widget(底下的被覆盖的widget
PostMouseEventToSiblings(event);
}

void Widget_1::PostMouseEventToSiblings(QMouseEvent *e)
{
if(this->parentWidget()) {
this->setAttribute(Qt::WA_TransparentForMouseEvents, true);
QPoint pt = this->mapTo(this->parentWidget(), e->pos());
QWidget *w = this->parentWidget()->childAt(pt);
if (w) {
pt = w->mapFrom(this->parentWidget(), pt);
QMouseEvent *event = new QMouseEvent(e->type(), pt, e->button(),
e->buttons(), e->modifiers());
QApplication::postEvent(w, event);
}
this->setAttribute(Qt::WA_TransparentForMouseEvents, false);
}
}


隐忧

我们在将事件传递给底下被覆盖的widget时,应用new运算符在堆上创建了一个QMouseEvent对象。熟悉Qt的都知道,父widget析构时会将其子对象一并析构掉。可是new出来的QMouseEvent并没有指定和加入到任何父widget当中,那它如何析构销毁呢,程序中也没有显示销毁的操作,这样会不会带来内存泄漏呢?

定心丸

在Qt的帮助文档中,通过sendEvent和postEvetn的解读,找到了我们寻求的答案。

sendEvent:
Sends event event directly to receiver receiver, using the notify() function. Returns the value that was returned from the event handler.

postEvent:
Adds the event event, with the object receiver as the receiver of the event, to an event queue and returns immediately.
The event must be allocated on the heap since the post event queue will take ownership of the event and delete it once it has been posted. It is not safe to access the event after it has been posted.


意思就是,如果你使用sendEvent,必须由调用者来创建和销毁事件对象,所以此事件一般在栈上创建。

如果你使用postEvent,他是通过事件队列来管理的,一旦post之后,就由事件队列来负责事件对象的销毁,所以此时事件对象必须创建在堆上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: