Qt:将信号/绑定参数适应插槽?

Posted

技术标签:

【中文标题】Qt:将信号/绑定参数适应插槽?【英文标题】:Qt: adapting signals / binding arguments to slots? 【发布时间】:2009-05-07 17:11:03 【问题描述】:

有没有办法将参数绑定到插槽ala boost::bind?

这是一个例子。我有一个带有树视图的窗口,我想允许用户从上下文菜单中隐藏一列。我最终会做类似的事情:

void MyWindow::contextMenuEvent (QContextMenuEvent* event) 
   m_column = view->columnAt (event->x());
   QMenu menu;
   menu.addAction (tr ("Hide Column"), this, SLOT (hideColumn ()));
   // .. run the menu, etc

我需要捕获激活上下文菜单的列的索引,并将其存储在我窗口的hideColumn 插槽使用的成员变量中:

void MyWindow::hideColumn () 
    view->setColumnHidden (m_column, true);

我真正想要的是能够在创建菜单时将列号绑定到我的插槽,这样我就不需要这个成员变量了。基本上相当于 Qt:

menu.addAction (tr ("Hide Column"),
                boost::bind (&MyWindow::hideColumn, this,
                             event->columnAt (event->x()));

或者更好的是调整QAction::triggered 信号并将其附加到QTreeView::hideColumn 插槽,该插槽将列索引作为参数:

menu.addAction (tr ("Hide Column"),
                boost::bind (&QTreeView::hideColumn, view,
                             event->columnAt (event->x())));

这些都可行吗?

【问题讨论】:

现在 Qt 5 支持 C++0x lambda,所有这些混乱都可以处理掉。见qt-project.org/doc/qt-5.0/qtcore/qobject.html#connect-5 【参考方案1】:

LibQxt 通过 QxtBoundFunction 和 QxtMetaObject 使这成为可能(由于某种原因,前者没有出现在他们的documentation 中)。这是一个开源项目,因此如果您对实现感兴趣,可以获取源代码。它使用以下语法:

connect(
    button,
    SIGNAL(clicked()),
    QxtMetaObject::bind(
        lineEdit,
        SLOT(setText(QString)),
        Q_ARG(QString, "Hello World!)
        )
    );

LibQxt 还有一些其他非常有用的功能,比如emit signals over a QIODevice 的功能,比如网络连接。

【讨论】:

【参考方案2】:

你不能使用QActionsetData函数吗?

void MyWindow::contextMenuEvent (QContextMenuEvent* event)

    m_column = view->columnAt (event->x());
    QMenu menu;
    QAction * action = menu.addAction (tr ("Hide Column"), this, SLOT (hideColumn ()));
    action->setData(QVariant(hideColumn));


void hideColumn()

    const QAction * action = qobject_cast<const QAction *>(this->sender());
    assert(action);

    int hide_column = action->data().value<int>();
    this->view->setColumnHidden (m_column, true);

【讨论】:

不错。不知道setData。既然可以在 Qt 5 中使用 C++0x lambda,那么这种混乱就可以完全消失了。耶!【参考方案3】:

AFAIK 唯一的方法是创建一个 QSignalMapper 对象来执行此操作。这就像一个额外的间接级别,可用于生成提供列索引的新信号。这有点笨拙的 IME,你可能会一直挂着很多 QSignalMapper 对象,但这似乎是目前最好的方式。 (理想情况下,IMO,您可以只提供任何值,例如将列索引作为 connect() 的参数传递给插槽,但您不能。)

【讨论】:

是的。 QT 信号非常低级(至少在当前版本中,在遥远的将来可能会有希望;)。实际上它们是基于文本的(只需查看 moc_xx.cpp 文件或如何定义 SLOT/SIGNAL 宏。)【参考方案4】:

正如上面评论中提到的,这在 Qt 5 中要容易得多,因为您可以将信号直接连接到函子,例如 std::tr1::bind() 或 boost::bind() 的结果。对于 Qt 4,有许多适配器库。 Kaleb 提到了 LibQxt。我有一个https://github.com/robertknight/qt-signal-tools

【讨论】:

以上是关于Qt:将信号/绑定参数适应插槽?的主要内容,如果未能解决你的问题,请参考以下文章

QT 插槽和信号参数

关于QT信号和槽机制的重复绑定错误及改正

使用 qt 中的信号/插槽更新 gui [关闭]

Qt:如何将不同类的静态信号连接到插槽?

Qt - 使用信号/插槽关闭子菜单

QT:使用移动语义将信号连接到插槽