List of Qt signal slots

List of Qt signal slots

Signals and slots are used for communication between objects. The signals and slots mechanism is a core feature of Qt, and probably the most different from features offered by other frameworks. Signals and slots are made possible by Qt's meta-object system.

In GUI programming, when we change one widget, we usually want another widget to be notified. More generally, we want objects of any type to be able to communicate with each other. For example, if the user clicks the Close button, we might want to call the window's Close() function.

Other toolkits use callbacks to achieve this communication. A callback function is a pointer to a function, so if you want a handler to notify you of an event, you need to pass a pointer to another function (the callback function) to the handler. Then, the handler function calls the callback when appropriate. While successful frameworks using this approach do exist, callbacks can be unintuitive, and you can have problems ensuring the type correctness of callback parameters.

In Qt we have an alternative to the callback technique: we use signals and slots. Emit a signal when a specific event occurs. Qt's widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. Slots are functions that are called in response to specific signals. Qt's widgets have a number of predefined slots, but it's common practice to subclass the widget and add your own slots in order to handle signals of interest.

insert image description here

The signal and slot mechanism is type-safe: the signature of the signal must match the signature of the receiving slot. (Actually, a slot's signature may be shorter than the signal it receives, since it can ignore the extra arguments.) Since the signatures are compatible, the compiler can help us detect type mismatches when using function pointer-based syntax . The string-based SIGNAL and SLOT syntax will detect type mismatches at runtime. Signals and slots are loosely coupled: a class that emits a signal neither knows nor cares which slot receives the signal. **Qt's signal and slot mechanism ensures that if you connect a signal to a slot, the slot will be called at the correct time with the signal's arguments. ** Signals and slots can accept any number of arguments of any type. They are completely type safe.

All classes that inherit from QObject or its subclasses (such as QWidget) can contain signals and slots. Signals are emitted when an object changes its state in a way that other objects may be interested in. That's all the objects do to communicate. It doesn't know and doesn't care if anything receives the signal it sends. This is true information encapsulation and ensures that objects can be used for component-based software engineering.

Slots can be used to receive signals, but they are also normal member functions. Just as an object doesn't know if anything receives its signal, a slot doesn't know if any signal is connected to it. This ensures that truly self-contained components can be created with Qt.

You can connect as many signals as you want to a single slot, and you can connect as many signals as you want to as many slots. It is even possible to connect one signal directly to another. (As soon as the first signal is emitted, it will immediately emit the second signal.)

Signals and slots form a powerful component programming mechanism.

Signals

A signal is emitted when an object's internal state has changed in some way that may be of interest to the object's client or owner. Signals are public access functions and can be emitted from anywhere, but we recommend emitting them only from the class that defines the signal and its subclasses.

When a signal is emitted, the slot connected to it normally executes immediately, just like a normal function call. When this happens, the signals and slots mechanism is completely independent of any GUI event loop. Once all slots have returned, the code following the emit statement is executed. The situation is slightly different when using queued connections; in this case, the code following the emit keyword will continue immediately, and the slot will be executed later.

If multiple slots are connected to a signal, those slots will execute one after the other in the order they were connected when the signal is emitted.

Signals are automatically generated by moc and cannot be in . Cpp files. They can never have a return type (i.e. use void).

Note on parameters: Our experience shows that signals and slots are more reusable if they don't use special types. If QScrollBar::valueChanged() were to use a special type, say the hypothetical QScrollBar::Range, then it could only be connected to a slot designed specifically for QScrollBar. It is not possible to wire different input widgets together.

Slots

A slot is called when the signal connected to the slot is emitted. Slots are normal C++ functions and can be called normally; their only property is that signals can be connected to them.

Because slots are ordinary member functions, they follow ordinary C++ rules when called directly. However, as slots, they can be called by any component, regardless of its access level, through a signal-slot connection. This means that a signal emitted from an instance of an arbitrary class can cause a private slot to be called in an instance of an unrelated class.

You can also define slots as virtual, which we've found to be very useful in practice.

Signals and slots are slightly slower than callbacks because they provide more flexibility, although for real applications the difference in this respect is not significant. In general, emitting a signal connected to some slot is about ten times slower than calling a non-virtual function call to the receiver directly. This is the overhead required to locate the connection object, iterate over all connections safely (i.e. check whether subsequent receivers are destroyed in the middle of a send), and marshal any parameters in a generic way. While 10 non-virtual function calls may sound like a lot, it's much less overhead than any new or delete operation. Once you've performed a string, vector, or list operation, the background needs to be new or deleted, and the signal and slot overhead is only a small fraction of the overall function call cost. It's the same whether you're doing a system call in a slot, or calling ten or more functions indirectly. The simplicity and flexibility of the signals and slots mechanism is well worth the overhead, and your users won't even notice it.

Note that other libraries that define variables called signals or slots may cause compiler warnings and errors when compiled with Qt-based applications. To fix this, use the # undef preprocessor symbol.

The usage of connect in Qt

The old version of the writing method is more complicated, and the signal and slot need to be clearly specified, including formal parameters.

class MyButton : public QWidget
{
    Q_OBJECT
public:
    explicit MyButton(QWidget *parent = nullptr);

signals:
    void sigClicked();
    void sigClicked(bool check);
};

The old version is written at a glance, but it is more troublesome

connect(m_pBtn,SIGNAL(sigClicked()),this,SLOT(onClicked()));
connect(m_pBtn,SIGNAL(sigClicked(bool)),this,SLOT(onClicked(bool)));

How to write after Qt5.0

connect(m_pBtn,&MyButton::sigClicked,this,&Widget::onClicked);

If the signal is overloaded, an error will be reported

error: no matching member function for call to ‘connect’ connect(m_pBtn,&MyButton::sigClicked,this,&Widget::onClicked);

Use the following writing method to specify the specified version of the signal function. If the slot function is overloaded, it is also possible to use the old method

connect(m_pBtn, static_cast<void (MyButton::*)(bool)>(&MyButton::sigClicked), this, &Widget::onClicked);

Optimize signal function overloading

But still can't link the overloaded slot function.

connect(m_pBtn, QOverload<bool>::of(&MyButton::sigClicked),this,&Widget::onClicked);

Lambda function writing method

If the content of the slot function is simple, there is no need to define a slot link separately, it is convenient to use the Lambda function directly.

connect(m_pBtn, QOverload<bool>::of(&MyButton::sigClicked),

               [=](bool check){

                /* do something.. */

                });

connect(m_pBtn, static_cast<void (MyButton::*)(bool)>(&MyButton::sigClicked), this, [=](bool check){

                 //do something

                 });

Lambda function

[capture](parameters) mutable ->return-type{statement}

1.[capture]: capture list. The capture list always appears at the beginning of the Lambda function. In fact, [] is a lambda quote. The compiler judges whether the following code is a Lambda function based on the elicitor. The capture list can capture variables in the context for use by Lambda functions;

2. (parameters): parameter list. Consistent with the parameter list of ordinary functions. If parameter passing is not required, it can be omitted together with the brackets "()";

3. mutable: mutable modifier. By default, a Lambda function is always a const function, and mutable can cancel its constness. When using this modifier, the parameter list cannot be omitted (even if the parameter is empty);

4.->return-type: return type. Declare the return type of a function with the trace return type form. We can also omit it together with the symbol "->" when we don't need a return value. In addition, when the return type is clear, this part can also be omitted to let the compiler deduce the return type;

5. {statement}: function body. The content is the same as a normal function, but in addition to the parameters, all captured variables can also be used.

The biggest difference from ordinary functions is that in addition to parameters, Lambda functions can also access data in some contexts through capture lists. Specifically, the capture list describes which data in the context can be used by Lambda, and how to use it (by value or by reference). Syntactically, what is included in "[]" is a capture list, and the capture list consists of multiple capture items separated by commas. Capture lists come in the following forms:

1. [var] indicates that the value transfer method captures the variable var;
2. [=] indicates that the value transfer method captures all variables in the parent scope (including this);
3. [&var] indicates that the reference transfer captures the variable var;
4. [& ] means that the reference transfer method captures all variables in the parent scope (including this);
5. [this] means that the value transfer method captures the current this pointer.

The above mentioned a parent scope, that is, the statement block containing the Lambda function. In layman's terms, it is the "{}" code block containing Lambda. The capture lists above can also be combined, for example:

1.[=,&a,&b] means to capture variables a and b by reference, and capture all other variables by value; 2.[&,a,this] means to capture variables a
and this by value , the pass-by-reference method captures all other variables.

However, it is worth noting that the capture list does not allow variables to be passed repeatedly. The following examples are typical duplications that lead to compile-time errors. For example:

3. [=, a] here has captured all variables by value transfer, but if a is captured repeatedly, an error will be reported;
4. [&,&this] here & has captured all variables by reference transfer, and then capture this It is also a repetition.

Lambda function example

[capture] explanation

On the basis of the project in the previous section, add the button mybutton_1, press the button, and change the button text. According to the basic composition code of the Lambda expression above, it can be written as (wrong way of writing):

QPushButton *mybutton_1=new QPushButton(this);
mybutton_1->setText("关注<程序媛讲QT>");
mybutton_1->move(150,100);   //移动按键
connect(mybutton_1,&QPushButton::pressed,
        []()
        {
             mybutton_1->setText("Lambda表达式");
         }
);

At this time, the error message "error: 'mybutton_1' is not captured" will appear when compiling, which means that mybutton_1 is not within my scope. At this time, you need to use [capture] to pass in external variables. At this point, we only need to pass in mybutton_1, and the code can be compiled and run normally. The connect() function code is changed to:

connect(mybutton_1,&QPushButton::pressed,
        [mybutton_1]()
        {
              mybutton_1->setText("Lambda表达式");
        }
);

At this point the code can be compiled and run normally. Then when there are multiple variables outside, it is too troublesome to write them into [] one by one. At this time, we can use "=". For example:

QPushButton *mybutton_1=new QPushButton(this);
mybutton_1->setText("关注<程序媛讲QT>");
mybutton_1->move(150,100);   //移动按键
int a=2,b=7;
connect(mybutton_1,&QPushButton::pressed,
        [=]()
         {
               mybutton_1->setText("Lambda表达式");
               qDebug()<<a+b;
          }
);

qDebug() is a printout, similar to printf in C language, you need to #include “QDebug” when using it.
  Compile and run, after the button is pressed, the button text changes and the text "9" is output. It can be seen that "=" has passed in the values ​​of external variables a, b, and mybutton_1.
  It can be seen that "=" can pass all external local variables and all members of the class in by value. Similarly, "this" means that all members in the class are passed by value; "&" means that all external local variables are referenced.

Summarize:

  • [capture]: In the Lambda expression, this part must exist and cannot be omitted.
  • =: Pass all external local variables and all members of the class into the Lambda expression by value. The default is read-only, and the value of the variable cannot be changed.
  • &: All local variables (including this in the class where the Lambda expression is located), the transfer method of the reference.
  • this: Member variables in the class where Lambda is located can be used in the function body.
  • "=" is recommended.

Mutable explained

As mentioned above, "=" is passed by value. It is read-only by default. If we want to change the external variable, we can use mutable at this time. The code is as follows:

connect(mybutton_1,&QPushButton::pressed,
        [=]() mutable
        {
              b=3;
              mybutton_1->setText("Lambda表达式");
              qDebug()<<a+b;
         }
);
  • Summarize:
  • In Lambda expressions, mutable can be omitted. When passing a variable by value, adding the mutable modifier can modify the value of the variable in the Lambda expression, but the value itself is not modified.

(parameters) explanation

When the Lambda expression has no parameters, this part can be ignored; when the signal has parameters, you can use () to overload the function parameters. For example:

connect(mybutton_1,&QPushButton::clicked,
             [=](bool Check)
             {
                  qDebug()<<Check;
             }
         );

The signal void QAbstractButton::clicked(bool checked = false) of QPushButton has parameters, and the parameters can be passed into the Lambda expression through ().

Summarize:

utton::clicked,
[=](bool Check)
{
qDebug()<<Check;
}
);


 QPushButton的信号void QAbstractButton::clicked(bool checked = false)是有参数的,通过()可将参数传入Lambda表达式中。

**总结:**

- **在Lambda表达式中无参数时,(parameters)部分是可以省略的。**

Guess you like

Origin blog.csdn.net/weixin_43925768/article/details/131124411