Qt 快速入门学习笔记

Qt 快速入门学习笔记

环境安装

  • 环境配置以及安装

安装包下载地址

1、windows安装

msvc编译器模块需要安装Windows软件开发工具包。

MinGW是Windows平台使用GNU工具导入库的集合。

2、Linux环境安装

双击.run文件即可

安装常用的开发依赖

apt-get install g++
apt-get install make
apt-get install libgl1-mesa-dev #gui运行依赖库

3、visual studio中创建Qt项目以及配置

1、工具安装

a、工具->扩展和更新->联机右上角搜索qt,下载安装Qt Visual Studio Tools

b、下载离线安装

配置Qt编译器版本:

1、点击Qt VS Tools选项 -> Qt Versions, 再弹出的框中添加对应的编译器版本

比如:D:\Qt\Qt5.12.12\5.12.12\msvc2017_64\bin

visual studio中开发qt程序打开控制台:

右键项目 -> 属性 -> 链接器 -> 系统 -> 子系统 修改为控制台 然后保存

基础配置以及原理

  • pro文件解析
QT       += core gui #项目依赖模块

# qt版本大于4才加入widgets模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

# app表示项目是exe应,lib表示是库
TEMPLATE = app

# 生成的可执行文件名称
TAEGET = “ceshi_demo”

# 使用C++11标准
CONFIG += c++11

# 设置头文件搜索路径
INCLUDEPATH += ../include

# $$PWD是pro的目录
INCLUDEPATH += $$PWD/../include
message("pwd = "$$PWD)

# 项目包含的源码
SOURCES += \
    dialog.cpp \
    main.cpp \
    widget.cpp

# 项目包含的头文件
HEADERS += \
    dialog.h \
    widget.h

# 项目包含的窗体文件
FORMS += \
    dialog.ui \
    widget.ui

# 指定库引用路径和名称 -L库路径 -l库名
LIBS += -L"./lib" -ltest

#修改可执行文件/目标文件输出路径
DESTDIR += ../build

qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

# 项目资源文件
RESOURCES += \
    res.qrc
    
#debug和release环境判断
CONFIG(debug,debug|release){
    TARGET = "ceshi_demo_debug"
} else {
    TARGET = "ceshi_demo_relsease"
}


#跨平台编译配置 win32 linux macx unix
win32{
message("win32")
}

!win32{
message("!win")
}

win32|linux{
message("win32|linux")
}

# 查看编译器信息
message($$QMAKESPEC)

# 查看编译器包括那些 D:\Qt\Qt5.12.12\5.12.12\mingw73_32\mkspecs

# dll输出路径
DLLDESTDIR += "../bin"

# 设置可执行程序图标 demo.ico存放在pro相同目录
RC_ICONS = demo.ico

# OBJECTS_DIR 表示程序生成的中间临时文件的存放路径
# MOC_DIR  moc命令生成的临时文件路径
# RCC_DIR 用来描述qt资源编译器输出文件路径
  • pri文件

在中大型项目中用pri文件配置各个子项目的公共变量、公共编译选项、公共路径

# 用来在pro/pri中引入某pri文件 include空格()
include (../my.pri)

# 环境变量 $${环境变量}

#自定义变量
CUSTOM_PATH = "../../home"

  • Qt程序编译的步骤

1、编译pro生成makefile

2、jom或者make编译makefile

# 生成界面的源码
D:\Qt\Qt5.12.12\5.12.12\mingw73_32\bin\uic.exe widget.ui -o ui_widget.h
# 生成信号槽代码
D:\Qt\Qt5.12.12\5.12.12\mingw73_32\bin\moc.exe widget.h moc_widget.cpp

qmake -o makefile demo.pro
jom /f makefile.Debug #windows
make # linux/mac

  • Qt元对象系统

QObject类是所有元对象系统的类的基类

在一个类的private部分声明Q_OBJECT宏,使得类可以使用元对象的特性如动态属性、信号与槽

Q_PROPERTY()宏可以定义属性

QObject ob;
// 设置动态属性
ob.setProperty("name", "zhansan");
// 获取属性值
ob.property("name")

UI基础组件以及常用功能

  • Qt容器类

顺序容器类:QList、QLinkedList、QVector、QStack、QQueue

QList数组列表

QLinkedList链式列表

QVector动态数组的功能,支持迭代器和下标访问

QStack类似堆栈先进后出

QQueue类似队列的先入先出

关联容器类:QMap、QMultiMap、QHash、QMultiHash、QSet

QMultiMap、QMultiHash支持一个键关联多个值

QSet是基于散列表的集合模板类,存储无顺序、查找速度快,内部用QHash实现

QMap存储基于键值对,存储按照key的顺序,不在乎顺序用QHash更快

QHash基于散列表来实现字典功能的模板类

  • 信号与槽

类似windows的消息机制,信号函数只发送,不需要知道接受者,需要QObject来绑定。

原理:

1、绑定信号函数和槽函数

2、调用信号函数(将信号写入队列)

3、主线程从队列中获取信号,在信号线程中找到信号和槽关联的队列处理,调用槽函数

connect(sender, SIGNAL(signal), receiver, SLOT(slot));

1、一个信号可以连接多个槽

2、多个信号可以连接同一个槽

3、一个信号可以连接另外一个信号

4、信号与槽的参数个数需要一致,信号的参数不能少于槽的参数

5、信号与槽的类中需要加入Q_OBJECT

6、当信号发射时,与其关联的槽函数立即执行,当关联的槽函数执行完毕之后才能执行发射信号处后的代码

手动添加信号槽:

1、Q_OBJECT

2、手动创建信号signals

3、手动创建槽 public slots

  • QWidget

1、所用用户界面对象的基类

2、窗口部件接收鼠标、键盘等事件

3、屏幕上绘制自己

4、父子关系有相对坐标

手动创建QWidget对象
QWidget w;
w.show(); //显示包含子窗口
w.hide(); // 隐藏包含子窗口
w.geometry(); // 获取窗口坐标大小

// 获取x.y.width.height
int x =  w.x();
int y = w.y();
int width = w.width();
int height = w.height();

// 重新设置窗口大小、移动窗口位置
w.resize(300, 400);
w.move(0, 0);

// 设置窗口状态  WindowMinimized  WindowFullScreen
setWindowState(Qt::WindowMaximized);

// 同setWindowState效果
showNormal();
showMinimized();
showMaximized();
showFullScreen();

// 去除界面边框和标题栏,无法缩放移动
//setWindowFlags(Qt::FramelessWindowHint);

//  标题栏保留,去除所有按钮
setWindowFlags(Qt::WindowTitleHint | Qt::CustomizeWindowHint);
  • QString常用用法

QString中字符串是Unicode码,每一个字符是一个16位的QChar。所以处理中文没有问题。

// 1.字符串判空
QString str;
// QString str = nullptr;
str == ""
str.isNull()
str.isEmpty()

// 2.字符串拼接 =+ 、append()
str += " end";

// 3.格式化输出
QString str2 = QString("print %1 %2").arg("number = ").arg(45);
QString str3 = QString("格式化输出 %1, %2").arg(16, 0, 2).arg(255, 0, 16);
QString str;
str.sprintf("age is %d", 34);

// 4.数字转QString
QString num = QString::number(35);

// 5.字符串遍历
QString itstr = QString("hello, blob asfdfdasm fafasdfad");
// 方法一
for (QString::iterator itr = itstr.begin(); itr != itstr.end(); itr++) {
    qDebug() << *itr;
}
// 方法二
for (int i = 0; i

Qt中文乱码问题:

1、默认字符集设置(默认UTF-8)

2、文件字符集格式vs qtcreator中设置,vs中默认是gbk的编码

3、字符集转换QStringLiteral

// qt creator中输出中文
QString str = "中文测试";
qDebug() << str;

// vscode中开发qt,输出中文
QString str1 = QStringLiteral("中文测试");
qDebug() << str1;

// vscode中开发qt,输出中文
// 1.头文件中设置编码方式
#pragma execution_character_set("UTF-8")

QString str = "中文测试";
qDebug() << str;

// 2.文件编码为GBK
const char* src = "元数据是中文GBK,多字节数据存入QString";
QString str1 = QString::fromLocal8Bit(src);
qDebug() << str1;

// 把QString转为gbk
std::cout << str1.toLocal8Bit().toStdString() << std::endl;

QString s = QStringLiteral("测试");
//  win api调用QString作为参数
MessageBox(0, s.toStdWString().c_str(), L"标题", 0);
  • QLabel

显示文字、换行、样式设置字体、颜色、背景色、显示图片、播放gif动画

换行直接输入\n

label = new QLabel(Widget);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(190, 320, 251, 101));
// 设置样式表
label->setStyleSheet(QString::fromUtf8("font: 14pt \"Algerian\";color: rgb(119, 51, 255);"));
// 播放gif
QMovie *mov = new QMovie("test.gif");
label->setMovie(mov);
  • QPushButton

事件设置、快捷键、样式设置

click()/click(bool)/pressed()/released()

// 设置按钮快捷键
ui->pushButton->setShortcut(tr("Ctrl+x"));
// 设置样式
pushButton->setStyleSheet(QString::fromUtf8("background-color: rgb(255, 255, 0);color: rgb(42, 74, 255);border-radius:10px"));
// hover样式设置
pushButton->setStyleSheet(QString::fromUtf8("QPushButton::hover{background-color: rgb(0, 0, 0);}\n"
"QPushButton::!hover{background-color: rgb(255, 255, 0);color: rgb(42, 74, 255);border-radius:10px;}"));
  • QLineEdit
QLineEdit *edit = new QLineEdit(this);
edit->setObjectName("edit");
// 占位文字
edit->setPlaceholderText(QString("中文测试2"));
edit->move(100, 30);
edit->resize(100, 80);
// 清除按钮
edit->setClearButtonEnabled(true);
edit->setMaxLength(10);
// 设置显示密码的显示模式
edit->setEchoMode(QLineEdit::Password);
edit->setStyleSheet(QString("color: rgb(170, 0, 0);border-raduis: 20px;"));
// 输入验证
//edit->setInputMask("00.00;_");
// 只读
//eiit->setReadOnly(true);
// 校验器
QDoubleValidator *validator = new QDoubleValidator();
validator->setRange(-100, 1000, 3);
edit->setValidator(validator);

// returnPressed 有效触发信号
connect(edit, SIGNAL(returnPressed()), this, SLOT(returnPressedTest()));

// 另外一个按钮事件里面获取相关数据
void Widget::on_pushButton_clicked()
{
    QLineEdit *eiit = findChild("edit");
    // 获取内容
    qDebug() << eiit->text();
}
  • 遍历查找组件的子元素
QObjectList list = this->children();
for (int i = 0; i < list.size(); i++) {
    QObject* obj = list[i];
    const QMetaObject* metaObject = obj->metaObject();
     // 获取子元素类名
    QString className = metaObject->className();
    // 获取子元素objectName
    qDebug() << obj->objectName();
    qDebug() << className;
    // 转化
    if(className == "QPushButton") {
        QPushButton *btn = qobject_cast(obj);
        qDebug() << "找到了QPushButton text = " << btn->text();
    }
}
  • 容器布局Layout
//sizeHint推荐尺寸只能重载修改
//size() 不包含边框的窗口大小

//QSizePolicy::PolicyFlag
//GrowFlag 必要时可超过推荐
//ExpandFlag 尽可能的拓展
//ShrinkFlag 必要时可小于推荐
//IgnoreFlag 缺省大小被忽略

//QVBoxLayout
// 垂直布局
QVBoxLayout *layout = new QVBoxLayout(this);
// 设置距离边框的边距
layout->setContentsMargins(10,20,30,40);
// 设置元素之间的间距
layout->setSpacing(30);

QPushButton *btn = new QPushButton("btn1");
// 设置按钮size的策略 推荐的大小
btn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
layout->addWidget(btn);

QPushButton *btn2 = new QPushButton("btn2");
btn2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(btn2);

QPushButton *btn3 = new QPushButton("btn3");
// 忽略 大小尽量缩放
btn3->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
// 设置最大和最小值
btn3->setMaximumSize(300, 300);
btn3->setMinimumSize(50,50);
layout->addWidget(btn3);


// QGridLayout
QGridLayout *layout = new QGridLayout(this);
// 设置间距
layout->setVerticalSpacing(20);
layout->setHorizontalSpacing(10);

QPushButton *btn1 = new QPushButton("btn1");
layout->addWidget(btn1, 0, 0);

QPushButton *btn2 = new QPushButton("btn2");
layout->addWidget(btn2, 0, 1);

QPushButton *btn3 = new QPushButton("btn3");
layout->addWidget(btn3, 1, 0);

QPushButton *btn4 = new QPushButton("btn4");
layout->addWidget(btn4, 1, 1);

// QFormLayout
QFormLayout *layout = new QFormLayout(this);
layout->setVerticalSpacing(20);
layout->setHorizontalSpacing(10);

QLineEdit *account = new QLineEdit();
layout->addRow(QString("账号"), account);

QLineEdit *password = new QLineEdit();
layout->addRow(QString("密码"), password);

QHBoxLayout *hLayout = new QHBoxLayout();
layout->addRow(hLayout);

QPushButton *login = new QPushButton(QString("登录"));
hLayout->addWidget(login);

connect(login, SIGNAL(clicked()), this, SLOT(test()));

void Widget::test() {
    qDebug() << "test";
    QFormLayout *lay = qobject_cast(this->layout());
    qDebug() << lay;
}
  • qDebug输出调试信息的方式
// 1
qDebug() << "state = " << state;
// 2
qDebug("message = %s", info);
// 3 自定义类输出到qDebug
// 4 将标准输出重定向为到文件qInstallMessageHandler()
  • QCheckBox、QButtonGroup
QString res = ui->checkBox->text();
qDebug() << res;
ui->checkBox1->setText("text");
//  快捷键
ui->checkBox->setShortcut(tr("x"));
// 选中状态
ui->checkBox->isChecked();
// 同一父组件中的box单选
ui->checkBox->setAutoExclusive(true);

// QButtonGroup
QButtonGroup *group= new QButtonGroup(this);

// .ui 拖拽生成box1
// 加组后默认变单选
group->addButton(ui->box1);
group->addButton(ui->box2);
group->addButton(ui->box3);

// 单选变多选
group->setExclusive(false);
// 绑定信号
QObject::connect(group, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(testClicked(QAbstractButton *)));
  • QRadioButton
QButtonGroup *group= new QButtonGroup(this);
group->setObjectName("group");
QRadioButton *radio1 = new QRadioButton("QRadioButton1");
QRadioButton *radio2 = new QRadioButton("QRadioButton2");
QRadioButton *radio3 = new QRadioButton("QRadioButton3");
group->addButton(radio1);
group->addButton(radio2);
group->addButton(radio3);

QVBoxLayout *layout = new QVBoxLayout(this);

for (int i = 0; ibuttons().size() ; i++) {
   layout->addWidget(group->buttons()[i]);
}

// 获取选中的radioButton
QButtonGroup *group = findChild("group");
QRadioButton *radio = (QRadioButton *)group->checkedButton();
qDebug() << radio->text();
  • QComboBox

属性编辑、图标大小、插入数据(字符串、图标、自定义数据)、读取数据、信号事件

// 自定义数据处理
struct CustomType
{
    QString name;
};
Q_DECLARE_METATYPE(CustomType);


// 清空之前的item
ui->comboBox->clear();
ui->comboBox->addItem("item1");
ui->comboBox->addItem("item2");
// 添加带图标的item 图标在资源文件中
QIcon icon(":/tt/image/install_logo.png");
ui->comboBox->addItem(icon, "item_icon");
// 添加自定义数据item
CustomType type;
type.name = "zhansan";
QVariant ant;
ant.setValue(type);
ui->comboBox->addItem("custom_item", ant);

// 获取数据
QString res = ui->comboBox->itemText(0);
qDebug() << res;
// 获取自定义数据
QVariant ant = ui->comboBox->itemData(3);
CustomType type = ant.value();
qDebug() << type.name;
  • QSlider

常用属性、信号事件、样式设计、重载鼠标自定义事件

// 滑动槽的样式
QSlider::groove {
  border: 1px solid #999999;
  height:28px;
  background: rgba(155,155,155,200);
  border-radius: 10px;
}
// 滑块的样式
QSlider::handle {
  background: rgba(255,0,0,200);
  border-radius: 10px;
  width:20px;
  margin: -10px 0;
}

// 剩余槽的样式
QSlider::add-page {
	background: rgba(255, 0, 0, 10);
}

// 滑过的槽的样式
QSlider::sub-page {
	background: rgba(0, 255, 0, 30);
}

QSlider重载鼠标事件:

1、界面设计器添加自定义CustomSlider类,提升控件

2、覆写mousePressEvent

3、计算鼠标位置

// customSlider.h
#ifndef CUSTOMSLIDER_H
#define CUSTOMSLIDER_H

#include 
#include 

class CustomSlider : public QSlider
{
public:
    CustomSlider(QWidget *p = NULL);
    virtual void mousePressEvent(QMouseEvent *ev);
};

#endif // CUSTOMSLIDER_H

// customSlider.cpp
#include "customslider.h"
#include 
#include 

CustomSlider::CustomSlider(QWidget *p): QSlider(p)
{
}

void CustomSlider::mousePressEvent(QMouseEvent *ev) {
   qDebug() << ev->pos().x();
   QSlider::mousePressEvent(ev);
  // 百分比
   double p = (double)ev->pos().x() / (double)width();
   int val = p*(maximum() - minimum()) + minimum();
   setValue(val);
}
  • QListWidget

基本属性、插入和获取选中内容、遍历和排序、在列表中显示其他控件

// 关闭 水平垂直滚动条
ui->listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->listWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// 多选模式
//ui->listWidget->setSelectionMode(QAbstractItemView::MultiSelection);
//  设置方向
//ui->listWidget->setFlow(QListView::LeftToRight);
// 设置每一行的大小
//ui->listWidget->setGridSize(QSize(100, 50));
// 清除.ui中添加的数据
ui->listWidget->clear();
// 插入数据
QListWidgetItem *item = new QListWidgetItem("code insert");
ui->listWidget->addItem(item);
ui->listWidget->addItems({"item2","item 3", "item3"});

// 插入包含图标的item
QListWidgetItem *item_icon = new QListWidgetItem("icon item");
item_icon->setIcon(QIcon(":/tt/image/install_logo.png"));
ui->listWidget->addItem(item_icon);

// 遍历
for (int i = 0; i< ui->listWidget->count() ; i++) {
    qDebug() << ui->listWidget->item(i)->text();
}

// 设置 双击为可编辑状态
ui->listWidget->setEditTriggers(QAbstractItemView::DoubleClicked);
for (int i = 0; i< ui->listWidget->count() ; i++) {
    ui->listWidget->item(i)->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable);
}

// 排序
ui->listWidget->sortItems(Qt::DescendingOrder);

// 添加其他控件
QLineEdit *edit = new QLineEdit("QLineEdit");
// item(0) 第一个组件替换为QLineEdit
ui->listWidget->setItemWidget(ui->listWidget->item(0), edit);
  • QTableWidget

常用属性设置、设置水平/垂直标题、插入数据、获取选中数据、删除、信号

// 清空所有标题和内容
ui->tableWidget->setColumnCount(0);
ui->tableWidget->setRowCount(0);

ui->tableWidget->setColumnCount(4);
ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("header1"));
ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem());
ui->tableWidget->horizontalHeaderItem(1)->setText("header2");

ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("header3"));
ui->tableWidget->setHorizontalHeaderItem(3, new QTableWidgetItem("header4"));

// 设置 第0列 标题的宽度
ui->tableWidget->setColumnWidth(0, 200);
// 设置垂直标题
ui->tableWidget->setRowCount(3);
QStringList list = {"col1", "col2", "col3"};
ui->tableWidget->setVerticalHeaderLabels(list);

// 插入数据
ui->tableWidget->setItem(0,0, new QTableWidgetItem("col 0,0"));
ui->tableWidget->setItem(0,1, new QTableWidgetItem("col 0,1"));
ui->tableWidget->setItem(0,2, new QTableWidgetItem("col 0,2"));
ui->tableWidget->setItem(1,0, new QTableWidgetItem("col 1,0"));
ui->tableWidget->setItem(2,0, new QTableWidgetItem("col 2,0"));

// 结尾添加一行
int row = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(row);
ui->tableWidget->setItem(row, 0, new QTableWidgetItem("new row 4"));

// 开始添加一行
ui->tableWidget->insertRow(0);
ui->tableWidget->setItem(0, 0, new QTableWidgetItem("new row 0"));

// 插入图片
ui->tableWidget->setItem(0, 1, new QTableWidgetItem("new row 1 icon"));
ui->tableWidget->item(0, 1)->setIcon(QIcon(":/tt/image/install_logo.png"));
// 设置行高
ui->tableWidget->setRowHeight(0, 80);
// 设置图标显示大小
ui->tableWidget->setIconSize(QSize(ui->tableWidget->rowHeight(0), ui->tableWidget->rowHeight(0)));

// 插入widght 图片
QLabel *label = new QLabel();
QPixmap pix(":/tt/image/install_logo.png");
// 缩放图片
pix = pix.scaled(ui->tableWidget->columnWidth(0), ui->tableWidget->rowHeight(row));
label->setPixmap(pix);
ui->tableWidget->setCellWidget(row, 0, label);

// 如何获取选中的数据?
// 没有数据的item无法选择
auto items = ui->tableWidget->selectedItems();
for (int i = 0; i < items.size() ; i++ ) {
    qDebug() << "row = " << items[i]->row() << " col = " << items[i]->column() << " text = " << items[i]->text();
}

// 选择模式器
QItemSelectionModel *mode = ui->tableWidget->selectionModel();
// 获取所有的选择索引
auto list = mode->selectedIndexes();
qDebug() << list;

样式:标题格式、间隔线、背景颜色间隔

// 标题样式
QHeaderView::section {
	background-color: rgb(60, 193, 255);
  color: white;
  padding-left: 4px;
  border: 1px solid #6c6c6c;
}
// 选中
QHeaderView::section:checked {
	background-color: rgb(255, 170, 0);
}

// 悬停
QHeaderView::section:hover {
	background-color: red;
}
  • QTreeWidget

常用属性、标题、内容插入、内容选择、拖动和删除、信号事件

// 清理.ui中生成的标题
ui->treeWidget->setHeaderItem(new QTreeWidgetItem());
//  清理数据
ui->treeWidget->clear();

ui->treeWidget->setColumnCount(3);

// 设置标题
ui->treeWidget->headerItem()->setText(0, "header1");
ui->treeWidget->headerItem()->setText(1, "header2");
ui->treeWidget->headerItem()->setText(2, "header3");

// 插入数据
// 从结尾处插入
ui->treeWidget->addTopLevelItem(new QTreeWidgetItem());
ui->treeWidget->topLevelItem(0)->setText(0, "tree node col1");
ui->treeWidget->topLevelItem(0)->setText(1, "tree node col2");

ui->treeWidget->addTopLevelItem(new QTreeWidgetItem({"tree row1 col1", "tree row1 col2"}));

// 开头插入
ui->treeWidget->insertTopLevelItem(0, new QTreeWidgetItem({"tree row0 col1", "tree row0 col2"}));

// 结尾插入
ui->treeWidget->insertTopLevelItem(ui->treeWidget->topLevelItemCount(), new QTreeWidgetItem({"tree end col1"}));
// 结尾插入
QTreeWidgetItem *node = new QTreeWidgetItem(ui->treeWidget);
node->setText(0, "new end col1");

// 插入子节点
ui->treeWidget->topLevelItem(0)->addChild(new QTreeWidgetItem({"child1"}));
ui->treeWidget->topLevelItem(0)->addChild(new QTreeWidgetItem({"child2"}));
ui->treeWidget->topLevelItem(0)->addChild(new QTreeWidgetItem({"child3"}));

ui->treeWidget->topLevelItem(1)->addChild(new QTreeWidgetItem({"2 - child1"}));
ui->treeWidget->topLevelItem(1)->addChild(new QTreeWidgetItem({"2 - child2"}));

// 插入孙节点
ui->treeWidget->topLevelItem(0)->child(1)->addChild(new QTreeWidgetItem({"grandSon"}));

// 设置图标
ui->treeWidget->setIconSize(QSize(50, 50));
ui->treeWidget->topLevelItem(0)->setIcon(0, QIcon(":/tt/image/install_logo.png"));

// 插入 widget
QPushButton *btn = new QPushButton("button");
ui->treeWidget->setItemWidget(ui->treeWidget->topLevelItem(1), 0, btn);

// 设置颜色交错
ui->treeWidget->setAlternatingRowColors(true);

样式处理

// 行列样式
QTreeView {
	background-color:#fefff7;
	alternate-background-color: #cbe8d9;
}
QTreeView::item {
	border: 1px solid #c5daff;
}
// 选中和悬停的样式
QTreeView::item:hover {
	background: #c5daff;
}
QTreeView::item:selected {
	background: #debbe8;
}
// 标题样式
QTreeView::section {
	background-color: #ffe0d8;
  border: 1px solid #c5daff;
}

如何利用手册查看对应的样式示例:

点击帮助 -> 搜索 -> style sheeet -> Qt Style Sheets Examples -> 查找对应的控件设置详情

// 图片放在资源文件中
QTreeView::branch:has-siblings:!adjoins-item {
 border-image: url(":/tt/image/vline.png") 0;
}

QTreeView::branch:has-siblings:adjoins-item {
 border-image: url(":/tt/image/branch-more.png") 0;
}

QTreeView::branch:!has-children:!has-siblings:adjoins-item {
 border-image: url(":/tt/image/branch-end.png") 0;
}

QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {
     border-image: none;
     image: url(":/tt/image/branch-closed.png");
}

QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings  {
     border-image: none;
     image: url(":/tt/image/branch-open.png");
}
  • QDialog

QDialog包括QColorDialog、QErrorMessage、QFileDialog、QFontDialog、QInputDialog、QMessageBox、QProgressDialog.

CustomDialog dialog;
dialog.setWindowTitle("dialog");
int result = dialog.exec();
switch (result) {
  case QDialog::Accepted:
      qDebug() << "Accepted";
      break;
  case QDialog::Rejected:
      qDebug() << "Rejected";
      break;
  default:
      break;;
}

自定义messagebox

// 添加qt设计师界面类
// 在界面中自定义ui
// 添加必要的信号槽

// CustomMessageBox.h
#ifndef CUSTOMMESSAGEBOX_H
#define CUSTOMMESSAGEBOX_H

#include 

namespace Ui {
class CustomMessageBox;
}

class CustomMessageBox : public QDialog
{
    Q_OBJECT

public:
    explicit CustomMessageBox(QWidget *parent = nullptr);
    ~CustomMessageBox();
    static int info(QString msg);
private:
    Ui::CustomMessageBox *ui;
};

#endif // CUSTOMMESSAGEBOX_H

// CustomMessageBox.cpp
#include "custommessagebox.h"
#include "ui_custommessagebox.h"

CustomMessageBox::CustomMessageBox(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::CustomMessageBox)
{
    ui->setupUi(this);
    // 去掉标题栏
    setWindowFlags(Qt::FramelessWindowHint);
    // 设置背景透明
    this->setAttribute(Qt::WA_TranslucentBackground, true);
}

CustomMessageBox::~CustomMessageBox()
{
    delete ui;
}

int CustomMessageBox::info(QString msg)
{
    CustomMessageBox box;
    box.ui->label->setText(msg);
    return box.exec();
}

// ui中添加了一个widght作为背景视图,添加一个label、两个按钮

// 添加样式表,圆角
#widget {
	border-radius:30px;
	background-color: rgb(204, 204, 204);
}
Qdialog {
	border-radius:30px;
	background-color: rgb(204, 204, 204);
	border: 1px solid gray;
}

自定义processDialog进度条

// ProcessDialog.h
#include 

namespace Ui {
class ProcessDialog;
}

class ProcessDialog : public QDialog
{
    Q_OBJECT

public:
    explicit ProcessDialog(QWidget *parent = nullptr);
    ~ProcessDialog();
public slots:
    void setDialog(int value);
private:
    Ui::ProcessDialog *ui;
};

#endif

// ProcessDialog.cpp
#include 

ProcessDialog::ProcessDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ProcessDialog)
{
    ui->setupUi(this);

    // 去掉标题栏和设置背景透明
    setWindowFlags(Qt::FramelessWindowHint);
    setAttribute(Qt::WA_TranslucentBackground, true);
}

ProcessDialog::~ProcessDialog()
{
    delete ui;
}

void ProcessDialog::setDialog(int value)
{
    ui->progressBar->setValue(value);
    if (value == 1000) {
        for (int i = 100; i > 0; i-- ) {
            this->setWindowOpacity((float)i / 100.0);
            QThread::msleep(5);
            
            // 设置label,shoudon
//            ui->label->setText(QString::number(i));
//            QEventLoop loop;
//            loop.processEvents();
        }
        this->close();
    }
}

// 自定义多线程 CustomThread.h
#include 

class CustomThread : public QThread
{
    Q_OBJECT
public:
    CustomThread();
    void run();

signals:
    void setPos(int value);
};

// CustomThread.cpp
void CustomThread::run()
{
    for(int i = 0; i <= 1000; i ++)
    {
        setPos(i);
        msleep(10);
    }
}

// 外部使用
ProcessDialog dialog;
CustomThread thread;
QObject::connect(&thread, SIGNAL(setPos(int)), &dialog, SLOT(setDialog(int)));
thread.start();
dialog.exec();
  • QMenuBar

QMenuBar、QMenu、QAction

// 插入菜单栏
QMenuBar *bar = new QMenuBar(this);
bar->resize(width(), bar->height());
// 一级菜单
QMenu *menu = bar->addMenu("菜单一");
m_menu = menu;

// 二级菜单
QAction *action1 = menu->addAction("二级菜单1");
QAction *action2 = menu->addAction("二级菜单2");
QAction *action3 = menu->addAction("二级菜单3");
QMenu *menu1 = menu->addMenu("二级菜单4");
// 菜单设置图标
menu1->setIcon(QIcon(":/tt/image/install_logo.png"));
menu1->addAction("三级菜单");

// 添加快捷键
action1->setShortcut(tr("x"));
// 绑定点击信号
connect(action1, SIGNAL(triggered()), this, SLOT(test()));
// 绑定鼠标悬停信号
connect(action2, SIGNAL(hovered()), this, SLOT(testHovered()));

//  设置action可以选中
action1->setCheckable(true);
action2->setCheckable(true);
action3->setCheckable(true);

// QActionGroup
QActionGroup *group = new QActionGroup(this);
group->addAction(action1);
group->addAction(action2);
group->addAction(action3);

// 设置group中的按钮单选
group->setExclusive(true);

// 鼠标位置显示菜单(用于动态显示创建好的菜单)
m_menu->exec(QCursor::pos());
  • QToolBar/QStatusBar
QToolBar *toolbar = new QToolBar(this);
toolbar->setGeometry(0, bar->height(), width(), 40);
toolbar->setIconSize(QSize(30, 30));
QAction *a = new QAction(QIcon(":/tt/image/install_logo.png"), "toolaction");
//a->setIcon(QIcon(":/tt/image/install_logo.png"));
toolbar->addAction(a);

QStatusBar *statusBar = new QStatusBar(this);
statusBar->setGeometry(0, height() - 40, width(), 40);
statusBar->showMessage("测试status message", 3000);
  • MainWindow
menuBar()->addAction("menu1");
statusBar()->showMessage("status bar message");

QToolBar *toolBar = new QToolBar(this);
toolBar->addAction("topaction");
QAction *a = new QAction(QIcon(":/tt/image/install_logo.png"), "icon action");
toolBar->addAction(a);
// 设置action text在icon下面
toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
// 在左侧添加toolbar   Qt::LeftToolBarArea
addToolBar(Qt::TopToolBarArea, toolBar);
  • QT事件Event

事件函数event、鼠标事件、键盘事件、窗口大小变化事件、重绘事件QPainter

// QEvent子类 QKeyEvent、QMouseEvent、QWheelEvent、QTouchEvent

bool EventDemo::event(QEvent *ev)
{
    qDebug() << ev->type();
    // 键盘事件
    if (ev->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEv = static_cast(ev);
        qDebug() << keyEv->key();
        // 代表处理,不会把事件传递给其他控件,继续处理下一个事件
        return true;
    }

    // 父类处理
    return QWidget::event(ev);
} 

// 键盘按下
void EventDemo::keyPressEvent(QKeyEvent *event)
{
    // 过滤自动重复触发的
    if(event->isAutoRepeat()) return;
    qDebug() << "keyPressEvent = " << event->key();
}

// 键盘弹起
void EventDemo::keyReleaseEvent(QKeyEvent *event)
{
    qDebug() << "keyReleaseEvent = " << event->key();
}

鼠标事件

bool EventDemo::event(QEvent *ev)
{
    qDebug() << ev->type();
    // 鼠标事件
    if (ev->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent *event = static_cast(ev);
        // 相对坐标
        qDebug() << "QMouseEvent x = " << event->x() << " y = " << event->y();
        // 程序坐标
        qDebug() << "windowPos x = " << event->windowPos().x() << " y = " << event->windowPos().y();
        // 屏幕坐标
        qDebug() << "screenPos x = " << event->screenPos().x() << " y = " << event->screenPos().y();

        // 本地坐标转屏幕坐标
        QPoint point = mapToGlobal(event->pos());
        qDebug() << "mapToGlobal x = " << point.x() << " y = " << point.y();

        // 获取鼠标的屏幕坐标
        qDebug() << "QCursor x = " <<  QCursor::pos().x() << " y = " << QCursor::pos().y();

        // 鼠标按键事件
        if (event->buttons() & Qt::LeftButton)
        {
            qDebug() << "LeftButton click";
        }
        if (event->buttons() & Qt::RightButton)
        {
            qDebug() << "RightButton click";
        }
        if (event->buttons() & Qt::MidButton)
        {
            qDebug() << "MidButton click";
        }
        if ((event->buttons() & Qt::LeftButton) && (event->buttons() & Qt::RightButton))
        {
            qDebug() << "LeftButton && RightButton click";
        }
        return true;
    }
    return QWidget::event(ev);
}

修改鼠标样式

QCursor cursor;
QPixmap map(":/tt/image/install_logo.png");
cursor = QCursor(map, -1, -1);
setCursor(cursor);

//  还原
setCursor(Qt::ArrowCursor);

窗口大小改变事件

void EventDemo::resizeEvent(QResizeEvent *event)
{
    qDebug() << "resizeEvent";
  // 改变子控件的大小
    ui->pushButton->resize(width() * 0.3, height() * 0.3);
}
  • QPainter

绘制文字、绘制线、绘制图形、绘制融合图片

QPen用于控制线条的颜色、宽度、线型等

QBrush用于设置填充颜色、填充方式、渐变特性等,可以使用图片做填充

QFont用于绘制文字时设置文字的样式大小

void PainterDemo::paintEvent(QPaintEvent *event)
{
    // 设置绘制设备
    QPainter p(this);
    // 画笔颜色
    p.setPen(QColor(255,0,0,150));
    // 字体
    p.setFont(QFont("黑体", 20));
    p.drawText(100, 50, "绘制文字");

    // 绘制线
    QPen pen;
    // 实线
    pen.setStyle(Qt::SolidLine);
    // 线的宽度
    pen.setWidth(10);
    // 线刷子
    pen.setBrush(Qt::red);
    // 设置刷子为图片
    //pen.setBrush(QBrush(QImage(":/tt/image/install_logo.png")));
    // 结尾端样式
    pen.setCapStyle(Qt::RoundCap);
    // 连接处样式
    pen.setJoinStyle(Qt::RoundJoin);

    p.setPen(pen);
    p.drawLine(QLine(10, 10, 300, 90));

}
  • QImage
QImageDemo::QImageDemo(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::QImageDemo)
{
    ui->setupUi(this);
    img = QImage(1280, 720, QImage::Format_RGBA8888);
    // 填入颜色
    img.fill(QColor(255,0,0,200));
    // 遍历设置颜色
    uchar *data = img.bits();
    // 假定已对齐,不对齐就出错
    for (int i = 0; i < img.width() ; i++ ) {
        for (int j = 0; j < img.height() / 2 ; j++) {
            data[j * img.width() * 4 + i * 4] = 0; // r
            data[j * img.width() * 4 + i * 4 + 1] = 255; // g
            data[j * img.width() * 4 + i * 4 + 1] = 0; // b
            data[j * img.width() * 4 + i * 4 + 1] = 255; // a
        }
    }

    for (int i = img.width() / 2; i < img.width() ; i++ ) {
        for (int j = 0; j < img.height() ; j++) {
            img.setPixelColor(i,j, QColor(0, 0, 0, 255));
        }
    }
}

void QImageDemo::paintEvent(QPaintEvent *ev)
{
    QPainter p(this);
    if(!img.isNull()) {
        p.drawImage(0, 0, img);
    }
}
  • 文件系统

QIODevice:所有 I/O 设备类的父类,提供了字节块读写的通用操作以及基本接口;
QFileDevice:Qt5新增加的类,提供了有关文件操作的通用实现。
QFlie:访问本地文件或者嵌入资源;
QTemporaryFile:创建和访问本地文件系统的临时文件;
QBuffer:读写QbyteArray, 内存文件;
QProcess:运行外部程序,处理进程间通讯;
QAbstractSocket:所有套接字类的父类;
QTcpSocket:TCP协议网络数据传输;
QUdpSocket:传输 UDP 报文;
QSslSocket:使用 SSL/TLS 传输数据;

顺序访问设备:
是指它们的数据只能访问一遍:从头走到尾,从第一个字节开始访问,直到最后一个字节,中途不能返回去读取上一个字节,这其中,QProcess、QTcpSocket、QUdpSoctet和QSslSocket是顺序访问设备。
随机访问设备:
可以访问任意位置任意次数,还可以使用QIODevice::seek()函数来重新定位文件访问位置指针,QFile、QTemporaryFile和QBuffer是随机访问设备

QFile file("D:\\code\\123.txt");
// 获取当前目录
//QDir::currentPath()
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    qDebug() << "Open file failed.";
    return;
} else {
    while (!file.atEnd()) {
        qDebug() << file.readLine();
    }
}

QFileInfo info(file);
qDebug() << info.isDir();
qDebug() << info.isExecutable();
qDebug() << info.baseName();
qDebug() << info.completeBaseName();
qDebug() << info.suffix();
qDebug() << info.completeSuffix();

QDataStream二进制文件读写

// 写入
QFile file("D:\\code\\123.txt");
if (!file.open(QIODevice::WriteOnly)) {
    qDebug() << "Open file failed.";
    return;
} else {
    QDataStream out(&file);
    out << QString("123");
    file.close();
}

// 读取
QFile file("D:\\code\\123.txt");
if (!file.open(QIODevice::ReadOnly)) {
    qDebug() << "Open file failed.";
    return;
} else {
    // 读取
    QString res;
    QDataStream in(&file);
    in >> res;
    qDebug() << "res = " << res;
    file.close();
}

QTextStream文本文件读写

// 写入
QFile file("D:\\code\\123.txt");
if (!file.open(QIODevice::WriteOnly| QIODevice::Truncate)) {
    qDebug() << "Open file failed.";
    return;
} else {
    QTextStream out(&file);
    out.setCodec("UTF-8");
  // 写入一行换行
    out << QString("test message") << endl;
    out << QString("test message other");
    file.close();
}

// 读取多行
 QFile file("D:\\code\\123.txt");
if (!file.open(QIODevice::ReadOnly)) {
    qDebug() << "Open file failed.";
    return;
} else {
    QTextStream in(&file);
    QString res;
    while (in.readLineInto(&res)) {
        qDebug() << res;
    }
    file.close();
}
  • Qt样式表

1、Qt样式表支持CSS2中定义的所有选择器

选择器 例子 用途
通用选择器 * 所有组件
类型选择器 QPushButton 所有QPushButton类及其子类
属性选择器 QPushButton[flat=“false”] 所有QPushButton属性flat=false的类及其子类
非子类选择器 .QPushButton 所有QPushButton类不包括其子类
ID选择器 QPushButton#btn ObjectName="btn"的QPushButton组件
从属对象选择器 QDialog QPushButton QDialog下面的所有QPushButton实例
子对象选择器 QDialog>QPushButton QDialog下面直接从属的所有QPushButton实例

2、子控件,组合组件下面的控件控制,例如QProgressBar::chunk 进度显示块的控制

3、伪状态的控制,如:hover

4、属性的控制 如:border

样式表的使用:

1、设计窗体中设置

2、setStyleSheet函数设置

多线程以及同步

  • QThread

基础使用

#ifndef CUSTOMTHREAD_H
#define CUSTOMTHREAD_H

#include 

class CustomThread : public QThread
{
    Q_OBJECT
public:
    CustomThread();
    void run();

signals:
    void setPos(int value);
};

#endif // CUSTOMTHREAD_H


// cpp
#include "customthread.h"

CustomThread::CustomThread()
{

}

void CustomThread::run()
{
    for(int i = 0; i <= 1000; i ++)
    {
      // 发送信号,外面绑定信号处理
        setPos(i);
        msleep(10);
    }
}

  • 线程同步方案

1、基于互斥量的线程同步

QMutex、QMutexLocker 每次只有一个线程获得互斥量的权限

2、QReadWriteLock 适合用于一个线程写,多个线程获取的场景

3、QWaitCondition 适用于一个线程满足某个条件,然后通知其他线程响应的场景

4、基于信号量的线程同步 QSemaphore 适用于保护一定数量的资源

网络编程

  • 获取本机相关信息

QHostInfo、QNetworkInterface

// QT       += network

// 电脑设备名称
QString hostName = QHostInfo::localHostName();
QString domainName = QHostInfo::localDomainName();
qDebug() << hostName;
qDebug() << domainName;

QHostInfo host = QHostInfo::fromName(hostName);
// 获取地址列表
QList address = host.addresses();
for(int i = 0; i < address.size(); i++)
{
    qDebug() << address[i];
    if (address[i].protocol() == QAbstractSocket::IPv4Protocol) {
         qDebug() << "IPv4Protocol";
    } else {
        qDebug() << "IPv6Protocol";
    }
}

// 获取主机网络接口
QList interface = QNetworkInterface::allInterfaces();
for(int i = 0; i < interface.size(); i++)
{
    // 设备名称
    qDebug() << interface[i].humanReadableName();
    // 设备地址
    qDebug() << interface[i].hardwareAddress();
}
  • 网络通信

QTcpSocket

QUdpSocket

QNetworkRequest、QNetworkRequest、QNetworkAccessManager

#include 
#include 
#include 
#include 
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_readyRead();
    void on_finished();
    void on_process(qint64 current, qint64 totle);

private:
    Ui::Widget *ui;
    QNetworkRequest request;
    QNetworkAccessManager manger;
    QNetworkReply *reply;
    QFile *downloadFile;
};
#endif // WIDGET_H

// cpp

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    QString urlString = "http://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png";
    QUrl url = QUrl::fromUserInput(urlString);
    if (!url.isValid())
    {
        qDebug() << "url error";
        return;
    }
    request = QNetworkRequest(url);
    reply = manger.get(request);
    connect(reply, SIGNAL(finished()), this, SLOT(on_finished()));
    connect(reply, SIGNAL(readyRead()), this, SLOT(on_readyRead()));
    connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(on_process(qint64,qint64)));
    
    QString fileName = QDir::currentPath() + "/" + url.fileName();
    qDebug() << "fileName = " << fileName;
    if (QFile::exists(fileName))
        QFile::remove(fileName);
    downloadFile = new QFile(fileName);
    downloadFile->open(QIODevice::ReadWrite);
}

void Widget::on_readyRead()
{
    qDebug() << "on_readyRead";
    downloadFile->write(reply->readAll());
}
void Widget::on_finished()
{
    qDebug() << "on_finished";
    downloadFile->close();
}
void Widget::on_process(qint64 current, qint64 totle)
{
    qDebug() << "current = " << current << " totle = " << totle;
}

打包发布

  • 程序发布

静态发布:将所有的需要的运行库编译到应用程序中,生成独立的可执行文件

共享库形式发布:将程序依赖的共享库和可执行程序一起发布

  • windows平台程序打包

1、进入编译完成的release版本安装包目录

2、找到对应编译器的工具windeployqt

# D:\Qt\Qt5.12.12\5.12.12\msvc2017\bin
# windeployqt一般再对应的编译器bin目录下
# 打包程序 等待完成即可
# windeployqt并不能保证一次将所有的依赖都复制到对应的目录下,需要移除qt环境变量或者找个不包含qt环境的电脑测试,如果有缺失dll,将缺失的dll复制到对应的目录
D:\Qt\Qt5.12.12\5.12.12\msvc2017\bin\windeployqt.exe demo.exe

你可能感兴趣的:(C++,qt,学习,笔记,Qt快速入门)