【问题标题】:C++ Qt: is it possible to create a sort of template slot?C++ Qt:是否可以创建一种模板槽?
【发布时间】:2018-11-27 23:38:43
【问题描述】:

我是 Qt 新手,不是 C++ 专家,所以请多多包涵。 我正在开发一个具有 12 个不同 QPushButtons 的应用程序,但它们都执行非常相似的操作:它们从地图中获取一些值,然后使用它来设置该按钮的样式:

void MainWindow::on_btn01_clicked(){
    QString img=images["btn01"];
    ui->btn01->setStyleSheet("#btn01{ background-image: url(://" + img + ") }");
}

对于 12 个按钮中的每一个,我都必须创建一个插槽,该插槽仅在所使用的按钮上有所不同。所以创建 12 个几乎完全相同的函数看起来有点奇怪。

有没有更好的方法来做到这一点?

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

    一般来说,我见过几种方法:

    1. 首选方法:lambda 表达式。

      如果您使用的是现代 C++(C++11 或更新版本),您可以使用 a lambda function 来获得您描述的确切效果。

      我希望生成的代码看起来像这样:

      foreach( QPushButton * button : buttons ) {
        connect( button, &QPushButton::clicked, [button, &images]() {
          button->setStyleSheet( QString( "{ background-image: url(://%1) }" )
            .arg( images[button->objectName()] ) );
        });
      }
      

      有关如何使用 Qt 编写 lambda 函数的更多指导,请参阅“Qt Slots and C++11 lambda”。

    2. 更脏的方式:QObject::sender()。

      Qt 允许您在槽中使用QObject::sender() 来获取指向调用它的对象的指针。多年来,这一直是一种广泛使用的方法,但存在一些限制,如 Qt 文档中所述:

      警告:如上所述,当插槽通过 Qt::DirectConnection 从与此对象线程不同的线程调用时,此函数的返回值无效。请勿在此类场景中使用此功能。

      有关详细信息,请参阅“How to get sender widget with a signal/slot mechanism?”。

    3. 过时的代码:QSignalMapper。

      有一个QSignalMapper 类可让您将信号与一些数据(如字符串)相关联,然后连接到使用此参数的插槽。这曾经作为 Qt 中的一个便利类存在,但由于 lambda 方法使其毫无意义,因此正在逐步淘汰。

      如果您需要更新使用 QSignalMapper 的代码来删除它,this tutorial 是一个合理的起点。

    【讨论】:

    • 如果您绝对不能使用 C++11,则为此创建了已弃用和过时的 [QSignalMapper][1]。但是,不鼓励在新代码中使用它,而且我认为您很难找到支持 Qt5 但不支持 C++11 的平台。 [1]:doc.qt.io/qt-5/qsignalmapper.html
    • 我确实在使用 C++11,所以谢谢你的好建议 :)
    【解决方案2】:

    您可以尝试一种更简单的方法,即分别设置QPushButton 的对象名称,然后检查您的插槽中的对象名称并使用该字符串。这可以为您节省大量代码。

    例如:
    QPushButton 1 对象名称设置为button->setObjectName("btn01");,您可以分别设置按钮的其他名称,在您的插槽中您可以执行类似的操作

    void MainWindow::on_button_clicked(){
         QPushButton* btn=qobject_cast<QPushButton*>(sender()); 
         QString name=btn->objectName(); 
         QString img=images[name]; btn->setStyleSheet("#" + name + "{ background-image: url(://" + img + ");
    }
    

    然后将你所有的QPushButtons 连接到这个插槽

    【讨论】:

    • 我能够使用类似的方法(更改了一些内容,因为我不断收到有关 QPushButton 尝试转换为 QString 的错误)。首先将我的所有按钮连接到构造函数中的插槽:connect(ui-&gt;btn01, SIGNAL(clicked()), this, SLOT(on_button_clicked())); 并为每个按钮执行一次(不确定是否有办法避免调用它 12 次)。然后我将插槽实现为:QPushButton* btn=qobject_cast&lt;QPushButton*&gt;(sender()); QString name=btn-&gt;objectName(); QString img=images[name]; btn-&gt;setStyleSheet("#" + name + "{ background-image: url(://" + img + ") }");
    猜你喜欢
    • 2015-05-15
    • 2019-02-22
    • 2021-11-03
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-08
    相关资源
    最近更新 更多