白季飞龙的个人主页

使用CLion开发Qt应用

准备

  1. CLion 我的是CLion 2017.2.3
  2. MinGW 我的是 MinGW 4.9(CLion说是3.2.1)
  3. Qt5 For MinGW,有头文件和库就行,Qt Creator之类不需要

CMakeLists.txt

cmake_minimum_required(VERSION 3.3)
project(HelloWorld)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)

find_package(Qt5Widgets)

set(SOURCE_FILES main.cpp)

add_executable(HelloWorld ${SOURCE_FILES})

target_link_libraries(HelloWorld Qt5::Widgets)

main.cpp

#include <QApplication>
#include <QDialog>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QDialog *dlg = new QDialog();
    dlg->setWindowTitle("Hello World");
    dlg->show();
    return a.exec();
}

注意

运行

  1. 点击运行按钮,程序并没有跑起来,CLion控制台给了个非0的程序退出代码。实际上exe已编译好,只是缺qt的dll动态链接库
  2. 配好动态链接库,重新点击运行按钮

Qt5程序需要的动态链接库(debug+release)

怎样配置动态链接库

调试卡黑窗怎么办

调试进的是反汇编代码怎么办

CLion处理Qt的信号槽

Clion通过CMake可以编译Qt程序,如果用到了自定义信号槽,还需要单独的moc处理

CMakeLists.txt

cmake_minimum_required(VERSION 3.3)
project(HelloWorld)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

find_package(Qt5Widgets)

# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) # if you have any .ui files
set(CMAKE_AUTORCC ON) # if you have any .qrc files

# Add compiler flags for building executables (-fPIE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")

qt5_generate_moc(main.cpp main.moc)

# Tell CMake to create the qtlayoutexample executable
add_executable(HelloWorld main.cpp main.moc)

target_link_libraries(HelloWorld Qt5::Widgets)

main.cpp

//!!! Qt5
#include <QObject>

////////// newspaper.h
class Newspaper : public QObject {
Q_OBJECT
public:
    Newspaper(const QString &name) :
            m_name(name) {
    }

    void send() {
        emit newPaper(m_name);
    }

signals:

    void newPaper(const QString &name);

private:
    QString m_name;
};

////////// reader.h
#include <QObject>
#include <QDebug>

class Reader : public QObject {
Q_OBJECT
public:
    Reader() {}

    void receiveNewspaper(const QString &name) {
        qDebug() << "Receives Newspaper: " << name;
    }
};

////////// main.cpp
#include <QCoreApplication>

#include <main.moc> //!!!!!!!!!!!!!Important magic!!!!!!!!!!!!!

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    Newspaper newspaper("Newspaper A");
    Reader reader;
    QObject::connect(&newspaper, &Newspaper::newPaper,
                     &reader, &Reader::receiveNewspaper);
    newspaper.send();

    return app.exec();
}

CLion使用Qt的资源文件

要使用qrc资源文件,需要在cmake里进行编译链接的设置

CMakeLists.txt

cmake_minimum_required(VERSION 3.3)
project(HelloWorld)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

find_package(Qt5Widgets)

# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) # if you have any .ui files
set(CMAKE_AUTORCC ON) # if you have any .qrc files

# Add compiler flags for building executables (-fPIE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")

qt5_generate_moc(main.cpp main.moc)
qt5_add_resources(RESOURCES mainres.qrc)

# Tell CMake to create the qtlayoutexample executable
add_executable(HelloWorld main.cpp main.moc ${RESOURCES})

target_link_libraries(HelloWorld Qt5::Widgets)

mainres.qrc

<RCC>
    <qresource prefix="/images">
        <file alias="open">open.png</file>
    </qresource>
</RCC>

main.cpp

#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QMessageBox>
#include <QToolBar>

int main(int argc, char **argv) {
    QApplication app(argc, argv);
    QMainWindow window;
    auto *action = new QAction(QIcon(":/images/open"), "&Close", &app);
    action->setShortcut(QKeySequence::Close);
    action->setStatusTip("Close this window");
    QObject::connect(action, &QAction::triggered, [&](bool) {
        QMessageBox::information(&window, "Warning", "Hello World");
    });
    window.menuBar()->addMenu("&File")->addAction(action);
    window.addToolBar("Close too")->addAction(action);
    window.statusBar();
    window.show();
    return app.exec();
}

在macOS下用Homebrew安装Qt

  1. brew cask install qt-creator
  2. brew install qt 记住最后Qt安装位置的提示
  3. Qt Creator中,配置Qt版本到qmake可执行文件的位置,这样才能创建项目
  4. Qt Creator中,配置C++编译器为clang 64位,否则编译项目会抛异常

QML与C++互操作示例

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.5
import QtQuick.Controls.Material 2.3

Window {
    id: page
    visible: true
    width: 640
    height: 480
    title: qsTr("白云千载空悠悠")
    property Dialog dialog

    ColumnLayout {
        spacing: 0
        anchors.fill: parent
        Rectangle {
            Layout.fillHeight: true
            Layout.fillWidth: true
            Layout.preferredHeight: 0
            color: "olive"
            Text {
                anchors.fill: parent
                id: element
                color: "#d41414"
                text: app.now()
                visible: true
                font.pointSize: 36
                verticalAlignment: Text.AlignVCenter
                horizontalAlignment: Text.AlignHCenter
            }
        }

        Button {
            text: "CLICK"
            antialiasing: false
            Layout.fillHeight: true
            Layout.fillWidth: true
            Layout.preferredHeight: 0
            font.pointSize: 36
            background: Rectangle {
                color: "steelblue"
            }
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    element.text = "Ready."
                    console.log("CLICKED....")
                    thread.start()
                    var component = Qt.createComponent("Dialog.qml")
                    var dialog = component.createObject(page, {"parent": page});
                    dialog.modality = Qt.WindowModal
                    page.dialog = dialog;
                }
            }
        }
    }

    Connections {
        target: thread
        onDon: {
            console.log("DONE DONE DONE")
            element.text = "DONE DONE DONE DONE DONE"
            page.dialog.close()
        }
    }
}
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QDebug>


class MyThread : public QThread
{
    Q_OBJECT
public:
signals:
    void don();
public:
    MyThread();

    void run();

};

#endif // MYTHREAD_H
#include "mythread.h"
#include <QNetworkAccessManager>

MyThread::MyThread()
{
}

void MyThread::run()
{
    qDebug() << "Before sleep";
    sleep(1);

    emit(don());
    qDebug() << "After sleep";
}
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <applicationdata.h>
#include "mythread.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    MyThread myThread;

    QQmlApplicationEngine engine;
    QQmlContext *context = engine.rootContext();

    context->setContextProperty("thread", &myThread);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

漫漫路,莫论逍遥;潜心修,只为悟道