【问题标题】:Qt "connect" syntax is very long. Is it any tricks to make it shorter?Qt“连接”语法很长。有什么技巧可以让它变短吗?
【发布时间】:2013-04-28 19:59:49
【问题描述】:

在 C# 中,为了将信号连接到插槽(委托给方法),我所做的只是:

first.signal += second.slot

但在 Qt 中是:

connect( & first, SIGNAL( signal( int, int, QString ) ), & second, SLOT( slot( int, int, QSTring ) ) );

而且这个算短,通常它们会产生 2-3 行。当然,我完全理解 Qt 仅模拟 .h 文件,而对于 .cpp 它们绑定到标准语法,但是否有任何技巧/方法可以使信号槽连接更短一些?我知道通过给它们特殊名称来自动将信号连接到插槽,但这仅适用于 .ui 文件中的信号。有什么提示吗?

【问题讨论】:

    标签: qt


    【解决方案1】:

    我知道通过给它们指定特殊名称来自动将信号连接到插槽,但这仅适用于 .ui 文件中的信号

    这种方法可以在 .ui 文件之外使用,你可以在任何你想要的地方调用QMetaObject::connectSlotsByName

    【讨论】:

    • 请注意调用它的方式和时间...如果您在基类构造函数中执行此操作,然后在派生类构造函数中执行此操作(例如),您可能会得到一些插槽连接两次。它在运行时不区分已经连接的那些。 (你可能猜到我现在是怎么知道的。)
    【解决方案2】:

    如果您发现它冗长且重复,您可以使用宏来简化语法。例如:

    #define S_i_i(x) x(int, int, QString)
    #define CONNECT(sx,x,tx,sy,y,ty) connect(&x, SIGNAL(tx(sx)), &y, SLOT(ty(sy)))
    
    CONNECT(signal, first, S_i_i, slot, second, S_i_i)
    

    缺点是除非您仔细选择宏,否则您的代码将失去对其他人的可读性。

    【讨论】:

    • 我认为说这种语法更轻量级是有争议的......使用这种方法,您需要为每个信号签名使用#define。 might 唯一有用的地方是您需要将多个插槽连接到同一个信号,在这种情况下,您已经编写了一个 connect(...) 并且简单的复制/粘贴就可以了。
    • @daniel:OP 想要的是更短的 代码。没有那么多签名,它们可以在一个公共标头中定义一次,就像 C# 中的公共委托一样。话虽如此,我一开始并没有发现原始的 Qt 编码信号和插槽的方式很烦人,我宁愿坚持下去,但这只是个人喜好问题 :)
    【解决方案3】:

    如果您正在将 不同 对象中的信号连接到 this 对象中的插槽,您可以使用快捷方式,并使用以下命令:

    connect( & first, SIGNAL( signal( int, int, QString ) ), SLOT( slot( int, int, QSTring ) ) );
    

    而不是这个:

    connect( & first, SIGNAL( signal( int, int, QString ) ), & second, SLOT( slot( int, int, QSTring ) ) );
    

    这会删除一点点连接。我相信还有其他可用的快捷方式。但是,您的一般观点是有效的,并且主要是 Qt 如何执行其信号/插槽机制的副作用。如果您真的想要 C++ 中更简洁的语法,您可以查看 Boost::Signals 或 SigC++ 库,它们也提供了信号/槽机制。但是请注意语法冲突。

    【讨论】:

    • Boost::Signals 在 Qt 中没有很好地集成,不幸的是:(
    【解决方案4】:

    一个技巧是将 QtCreator 用作编辑器,因为它允许您在键入时从下拉列表中选择信号和插槽。

    一个看似无关的反映是 Qt 力求拥有一个相当冗长的 API,因为它更易于阅读(并且在编写时更容易记住)。因此,他们避免使用缩写并写出它们的意思:QAbstractItemModel、setWindowTitle 等。而不是 QAbstItModel、setWinTit 等。更多的输入,更少的误解和链接器错误(缺少符号)

    【讨论】:

    • QtCreator 只能连接 Gui 信号和槽,还是任何一个?
    • 当输入“connect(src, SIGNAL(”时,你会得到一个可用的信号列表......对于 SLOT(...
    【解决方案5】:

    我个人认为没有那么糟糕。您只需为每个信号/插槽编写一次,并且大多数情况下您不必在之后再触摸它。

    我发现在某种程度上有帮助的最接近的事情是将 boost::bind/function 与信号/插槽机制一起使用。它没有直接回答您的问题,但它是相关的,您可以使用它。你可以阅读它here

    【讨论】:

      【解决方案6】:

      几年后,我找到了一种可以缩短连接的解决方案。解决方案基于@WildSeal 的回答并使用这个简单的宏:

      #define QCON( a, b, c, d ) VERIFY( QObject::connect( a, SIGNAL(b), c, SLOT(d) ) )
      

      所以,有问题的长代码:

      VERIFY( QObject::connect( first, SIGNAL(signal(int,int,QString)), second, SLOT(slot(int,int,QSTring)) ) );
      

      会显着缩短:

      QCON( first, signal(int,int,QString), second, slot(int,int,QString) );
      

      欢迎任何 cmets 和建议 :)。我现在发现的唯一缺点是我需要一个单独的宏来将信号连接到信号。但是由于这种操作很少见,所以我刚刚介绍了QCONS(),它确实起到了作用。

      【讨论】:

        【解决方案7】:

        支持 Qt5 和 C++11 的编译器的另一种解决方案:

        #define Q_CONNECT(sender, signal, receiver, slot) \
            QWidget::connect( \
                sender, &boost::remove_reference<boost::mpl::identity<decltype(*sender)>::type>::type::signal, \
                receiver, &boost::remove_reference<boost::mpl::identity<decltype(*receiver)>::type>::type::slot);
        
        #define Q_CONNECT_LAMBDA(sender, signal, receiver) \
            QWidget::connect( \
            sender, &boost::remove_reference<boost::mpl::identity<decltype(*sender)>::type>::type::signal, \
            receiver);
        

        请注意,boost::mpl::identity 仅适用于尚未处理以下内容的编译器(如 VS2010):

        decltype(expr)::member
        

        使用示例:

        Q_CONNECT(
            this, mySignalMethodName,
            &someHandler, handlerMethodName);
        
        Q_CONNECT_LAMBDA(
            this, mySignalMethodName,
            [=]() { handlerCode(); });
        

        优点:

        • 无需输入参数列表;
        • 无需显式复制类型信息;
        • 无需使用任何 SIGNAL、SLOT、Q_SIGNAL、Q_SLOT 宏;
        • 所有兼容性检查都是在编译时进行的。

        缺点:

        • 不适用于重载方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-02-25
          • 2020-11-01
          • 1970-01-01
          • 1970-01-01
          • 2020-05-25
          • 2022-12-06
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多