Qt 笔记

This works for developing Qt project with Qt designer and CMake.

CMakeLists.txt for Qt developing

A example:

cmake
cmake_minimum_required(VERSION 3.1)

project("Example")

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)

find_package(Qt5Widgets REQUIRED)
find_package(Qt5 COMPONENTS Gui REQUIRED)

file(GLOB example_HEADER source/*.h)

file(GLOB example_UIS ui/*.ui)
qt5_wrap_ui(example_UIS ${example_UIS})

file(GLOB example_SRC source/*.cpp)

add_executable(example ${example_HEADER} ${example_SRC} ${example_UIS})
target_link_libraries(example Qt5::Core Qt5::Widgets Qt5::Gui)

Qt's documentation includes information on which component to include for each class.

Some lines are explained below.

Pre-process .ui files into c++ header

cmake
file(GLOB uis *.ui)
qt5_wrap_ui(uis ${uis})
add_executable(example ${uis} ...)

Custom widgets

Inherit from QWidgets and set up ui in constructor

cpp
#include "ui_form.h"

class MyWidget: public QWidget {
private:
  Ui::Form ui;
public:
  MyWidget(QWidget* parent = nullptr): QWidget(parent) {
    ui.setupUi(this);
  }
};

Dynamically add widgets

Example of adding widget to grid layout:

cpp
QGridLayout *grid = findChild<QGridLayout *>("yourObjectName");
  grid->addWidget(widget, 0, 0, 1, 1);

Key press & release event

In the custom widget, override event() or eventfilter()

Note: tab key press is handled specially by Qt framework. It's catchable by the window only when child widgets cannot get focus

Signal & Slot

Declare & Defination

For a widget to have custom slot, Q_OBJECT macro must be used.

cpp
class MyWidget: public QWidget {
  Q_OBJECT
  ...
  signals:
    void clicked();
  public slots:
    void slotFoo() {

    }
};

Then add this to CMakeLists.txt so that the macro can be processed:

cmake
set(CMAKE_AUTOMOC ON)

Connect

Signals and slots can be connected using connect(). Or you can specify the connections in Qt Designer.

Parameter of signal

To use a type in queued signal & slot connection (pass as param of signal):

  1. use macro Q_DECLARE_METATYPE(T) after declaring the type
  2. call qRegisterMetaType<T>() in main function

Threads

Sub-classing QThread

  • put works in run()
  • or, call exec() in run() and handle works via signal & slots
    • in destructor, call quit() and wait() to make sure the event loop exits

Thread affinity

An QObject have a thread affinity (lives in a certain thread). By default this is the thread it's created in.

Notes: QTcpSocket and QUdpSocket are said to work only in thread where they are created. Even calling moveToThread() doesn't help.

About slots & signals

Different connection type decides which thread the slot is executed on:

  • queued: where receiver lives
  • direct: where the signal is emitted (not where the sender lives)
  • auto (default): if same thread, then direct, else queued