GNU开发工具——CMake构建Qt工程实践
一、CMake构建Qt工程
1、Qt工程源码
创建Migration目录,在目录下创建main.cpp文件:
#include
#include
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel label(QString("Hello Qt%1!").arg(int(QT_VERSION >> 16)));
label.setAlignment(Qt::AlignCenter);
label.resize(200, 100);
label.show();
return app.exec();
}
2、Qt4和Qt5兼容宏
编写兼容Qt4和Qt5的CMake宏,QtMigration.cmake文件如下:
# 定义宏QT_USE_MODULES
macro(QT_USE_MODULES _target)
# Enable AUTOMOC
set_target_properties(${_target} PROPERTIES AUTOMOC TRUE)
# Local variables
set(_modules_qt4)
set(_modules_qt5)
# Prepare modules
foreach(_module ${ARGN})
list(APPEND _modules_qt4 Qt${_module})
list(APPEND _modules_qt5 ${_module})
if(_module MATCHES "Gui")
list(APPEND _modules_qt5 "Widgets")
endif(_module MATCHES "Gui")
endforeach(_module ${ARGN})
list(REMOVE_DUPLICATES _modules_qt4)
list(REMOVE_DUPLICATES _modules_qt5)
# Find Qt libraries
find_package(Qt5 QUIET COMPONENTS ${_modules_qt5})
if(Qt5_FOUND)
qt5_use_modules(${_target} ${_modules_qt5})
else(Qt5_FOUND)
find_package(Qt4 QUIET COMPONENTS ${_modules_qt4})
if(Qt4_FOUND OR QT4_FOUND)
include(${QT_USE_FILE})
include_directories(${QT_INCLUDES})
add_definitions(${QT_DEFINITIONS})
target_link_libraries(${_target} ${QT_LIBRARIES})
endif(Qt4_FOUND OR QT4_FOUND)
endif(Qt5_FOUND)
endmacro(QT_USE_MODULES)
3、CMakeLists.txt编写
编写工程CMakeLists.txt文件,内容如下:
cmake_minimum_required(VERSION 2.8.9)
project(Migration)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
include(QtMigration.cmake)
QT_USE_MODULES(${PROJECT_NAME} Core Gui)
4、构建工程
Migration工程内创建build目录,进入build目录,进行构建。
cmake ..
make
5、CMake的Qt相关变量
对于Qt4,使用FIND_PACKAGE后,会生成有效的Qt4_FOUND,QT_USE_FILE,QT_INCLUDES,QT_LIBRARIES变量。
FIND_PACKAGE(Qt4 REQUIRED Core Gui)
if(Qt4_FOUND)
INCLUDE(${QT_USE_FILE})
INCLUDE_DIRECTORIES(${QT_INCLUDES})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${QT_LIBRARIES})
endif()
对于Qt5,使用FIND_PACKAGE后,会生成有效的Qt5_FOUND,Qt5Core_INCLUDE_DIRS,Qt5Xml_INCLUDE_DIRS,Qt5Gui_INCLUDE_DIRS,Qt5Widgets_INCLUDE_DIRS,Qt5OpenGL_INCLUDE_DIRS,Qt5Widgets_LIBRARIES,Qt5Core_LIBRARIES,Qt5Gui_LIBRARIES,Qt5Xml_LIBRARIES,Qt5OpenGL_LIBRARIES等相应模块的变量。
FIND_PACKAGE(Qt5 REQUIRED Core Gui Widgets OpenGL Xml)
if(Qt5_FOUND)
INCLUDE_DIRECTORIES(${Qt5Core_INCLUDE_DIRS} ${Qt5Xml_INCLUDE_DIRS}
${Qt5Gui_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5OpenGL_INCLUDE_DIRS})
#定义QT_LIBRARIES
SET(QT_LIBRARIES ${Qt5Widgets_LIBRARIES} ${Qt5Core_LIBRARIES}
${Qt5Gui_LIBRARIES} ${Qt5Xml_LIBRARIES} ${Qt5OpenGL_LIBRARIES})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${QT_LIBRARIES})
endif(Qt5_FOUND)
开启MOC支持set(CMAKE_AUTOMOC ON)
开启RCC支持set(CMAKE_AUTORCC ON)
开启UIC支持set(CMAKE_AUTOUIC ON)
设置Qt安装目录:set(CMAKE_PREFIX_PATH "Qt to path ") //bin lib include目录层
二、QtCreator使用CMake构建Qt工程
1、QtCreator创建Qt工程(CMake构建)
选择新建工程,创建一个Plain C++ Application。
选择使用CMake构建工程:
选择使用的Qt Kits版本:
2、增加C++类
选择菜单栏新建文件按钮,选择Files and Classes,C++ Class。
填写创建C++类的名称BarModelMapperChartWidget:
选择创建类文件所在位置,点击浏览按钮:
点击新建目录按钮创建ChartWidget目录,选择ChartWidget。
BarModelMapperChartWidget.h文件如下:
#ifndef BARMODELMAPPERCHARTWIDGET_H
#define BARMODELMAPPERCHARTWIDGET_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
QT_CHARTS_USE_NAMESPACE
/**
* @brief 柱状图ModelMapper报表界面类
*/
class BarModelMapperChartWidget : public QWidget
{
Q_OBJECT
public:
explicit BarModelMapperChartWidget(QWidget *parent = NULL);
/**
* @brief 初始化ModelMapper
* @param model
*/
void initModelMapper(QAbstractTableModel* model);
private:
QChart* m_chart;//报表组件
QChartView* m_chartView;//报表视图组件
};
#endif // BARMODELMAPPERCHARTWIDGET_H
BarModelMapperChartWidget.cpp文件如下:
#include "BarModelMapperChartWidget.h"
BarModelMapperChartWidget::BarModelMapperChartWidget(QWidget *parent) : QWidget(parent)
{
m_chart = new QChart;
m_chart->setAnimationOptions(QChart::AllAnimations);
m_chartView = new QChartView(m_chart);
m_chartView->setRenderHint(QPainter::Antialiasing);
QHBoxLayout* layout = new QHBoxLayout;
layout->addWidget(m_chartView);
setLayout(layout);
}
void BarModelMapperChartWidget::initModelMapper(QAbstractTableModel *model)
{
QBarSeries *series = new QBarSeries;
int first = 3;
int count = 5;
QVBarModelMapper *mapper = new QVBarModelMapper(this);
mapper->setFirstBarSetColumn(1);
mapper->setLastBarSetColumn(4);
mapper->setFirstRow(first);
mapper->setRowCount(count);
// 设置mapper的数据集对象
mapper->setSeries(series);
// 设置mapper对应的数据Model
mapper->setModel(model);
m_chart->addSeries(series);
QStringList categories;
categories << "April" << "May" << "June" << "July" << "August";
QBarCategoryAxis *axis = new QBarCategoryAxis();
axis->append(categories);
m_chart->createDefaultAxes();
m_chart->setAxisX(axis, series);
}
创建TableModel类:
TableModel.h文件如下:
#ifndef TABLEMODEL_H
#define TABLEMODEL_H
#include
#include
#include
#include
#include
#include
#include
/**
* @brief 数据模型
*/
class TableModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit TableModel(QObject *parent = 0);
virtual ~TableModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
Qt::ItemFlags flags(const QModelIndex &index) const;
/**
* @brief 生成数据
*/
void generateData();
private slots:
/**
* @brief 定时器超时信号的槽函数
*/
void onGenerateData();
private:
QList * > m_data;//模型数据容器
int m_columnCount;//列数
int m_rowCount;//行数
QTimer timer;//定时器
};
#endif // TABLEMODEL_H
TableModel.cpp文件如下:
#include "TableModel.h"
TableModel::TableModel(QObject *parent) : QAbstractTableModel(parent)
{
m_columnCount = 6;
m_rowCount = 12;
// 创建数据容器并初始化
for (int i = 0; i < m_rowCount; i++)
{
QVector* dataVec = new QVector(m_columnCount);
for (int k = 0; k < dataVec->size(); k++)
{
dataVec->replace(k, 100 + qrand() % 50);
}
m_data.append(dataVec);
}
// 每隔2秒超时
timer.start(2000);
connect(&timer, SIGNAL(timeout()), this, SLOT(onGenerateData()));
}
TableModel::~TableModel()
{
qDeleteAll(m_data);
}
int TableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_data.count();
}
int TableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_columnCount;
}
QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Horizontal)
return QString("201%1").arg(section);
else
return QString("%1").arg(section + 1);
}
QVariant TableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
{
return m_data[index.row()]->at(index.column());
}
else if (role == Qt::EditRole)
{
return m_data[index.row()]->at(index.column());
}
return QVariant();
}
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole)
{
m_data[index.row()]->replace(index.column(), value.toDouble());
emit dataChanged(index, index);
return true;
}
return false;
}
Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
{
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}
void TableModel::generateData()
{
// 生成新的数据
for (int i = 0; i < m_rowCount; i++)
{
for (int k = 0; k < m_data.at(i)->size(); k++)
{
m_data.at(i)->replace(k, 100 + qrand() % 50);
}
}
QModelIndex leftTop = index(0, 0);
QModelIndex rightBottom = index(m_rowCount - 1, m_columnCount - 1);
// 生成新数据后发送模型数据发生变化的信号dataChanged
emit dataChanged(leftTop, rightBottom);
}
void TableModel::onGenerateData()
{
generateData();
}
增加MainWindow类:
MainWindow.h文件如下:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include "ChartWidget/BarModelMapperChartWidget.h"
#include "Model/TableModel.h"
/**
* @brief 程序主界面类
*/
class MainWindow : public QWidget
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = NULL);
private:
BarModelMapperChartWidget* m_barModelMapperChartWidget;//报表组件
QTableView* m_tableView;//表格视图组件
TableModel* m_model;//表格模型
};
#endif // MAINWINDOW_H
MainWindow.cpp文件如下:
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent) : QWidget(parent)
{
m_model = new TableModel();
m_barModelMapperChartWidget = new BarModelMapperChartWidget(this);
m_barModelMapperChartWidget->initModelMapper(m_model);
m_tableView = new QTableView(this);
m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_tableView->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_tableView->setModel(m_model);
QHBoxLayout* layout = new QHBoxLayout;
layout->addWidget(m_tableView);
layout->addWidget(m_barModelMapperChartWidget);
setLayout(layout);
resize(800, 400);
}
main.cpp文件:
#include
#include "MainWindow.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.show();
return app.exec();
}
3、工程CMakeLists.txt文件
CMakeLists.txt文件如下:
# CMake版本约束
cmake_minimum_required(VERSION 2.8.3)
#工程名称
project(CMakeDemo)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "-fPIC")
set(CMAKE_BUILD_TYPE "Debug")
# 增加子目录ChartWidget的源码到变量SOURCES
aux_source_directory(ChartWidget SOURCES)
# 增加子目录Model的源码到变量SOURCES
aux_source_directory(Model SOURCES)
# 设置QT安装路径
set(CMAKE_PREFIX_PATH "/usr/local/Trolltech/Qt5.10.1/5.10.1/gcc_64")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 开启Qt MOC
set(CMAKE_AUTOMOC ON)
#开启Qt ROC
set(CMAKE_AUTORCC ON)
# 开启Qt UIC
set(CMAKE_AUTOUIC ON)
set(QT Core Gui Widgets Charts)
# 查找Qt库
find_package(Qt5 REQUIRED ${QT})
if(Qt5_FOUND)
include_directories(${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS}
${Qt5Widgets_INCLUDE_DIRS} ${Qt5Charts_INCLUDE_DIRS})
set(QT_LIBRARIES ${Qt5Widgets_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Charts_LIBRARIES})
# 增加可执行文件
add_executable(${PROJECT_NAME} ${SOURCES} main.cpp MainWindow.cpp)
target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES})
endif(Qt5_FOUND)
4、构建
QtCreator管理工程如下:
编译、调试可以使用QtCreator直接进行,方便快捷。
如果需要调试,必须在CMakeLists.txt设置(CMAKE_BUILD_TYPE为Debug。
set(CMAKE_BUILD_TYPE "Debug")
运行结果如下:
源码示例:https://down.51cto.com/data/2461580