Qt

介绍

Qt安装

https://download.qt.io/

目前我下载的是5.12.10版本

https://download.qt.io/archive/qt/5.12/5.12.10/

VS插件安装:

https://download.qt.io/archive/vsaddin/

第一个Qt项目

工程规范化:

  1. 创建一个文件夹Lesson,然后分别创建bindoclibsrc文件夹.
1
2
3
4
5
6
7
D:.
└─Lesson
    ├─bin
    ├─doc
    ├─lib
    └─src
  1. 新建一个qt工程,目录放在src中.

Qt创建第一个工程

目录文件介绍:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
D:.
  
├─bin
├─doc
├─lib
└─src
    ├─build-QtTest-Desktop_Qt_5_12_10_MSVC2017_32bit-Debug
        .qmake.stash
        Makefile
        Makefile.Debug
        Makefile.Release
        ui_widget.h           //这是qt设计器代码
        
      ├─debug
            main.obj
            moc_predefs.h     //qt中与信号槽相关的代码
            moc_widget.cpp
            moc_widget.obj
            QtTest.exe
            QtTest.ilk
            QtTest.pdb
            QtTest.vc.pdb
            widget.obj
            
      └─release
    └─QtTest
            main.cpp
            QtTest.pro            //这是qt的项目文件,用来生成makefile文件.
            QtTest.pro.user       //这是qt的编译环境,可删掉,重新指定编译环境.
            widget.cpp
            widget.h
            widget.ui
注意

在Qt中创建的.h .cpp文件的文件名要小写,为了跨平台.

在windows平台,文件名大小写不敏感,但在其他平台大小写可能是敏感的.

QMake

Qt程序编译步骤

  1. 编译Qt pro文件生成makefile
  2. 使用jom或make编译makefile

jom下载链接

jom或make会进行下述代码生成:

  • 生成界面源码
1
uic.exe widget.ui -o ui_widget.h
  • 生成信号槽代码
1
moc.exe widget.h moc_widget.cpp

控制台手工编译Qt程序步骤如下:

  1. 准备源文件
1
2
#include <stdio.h>
void func1();
1
2
3
4
5
#include "func1.h"

void func1(){
	printf("func1\n");
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdlib.h>
#include <stdio.h>
#include "func1.h"

int main(){
    func1();
	printf("main\n");
	system("pause");
	return 0;
}
  1. 编写pro文件
1
2
3
4
5
6
7
8
SOURCES += \
    main.cpp \
    func1.cpp

HEADERS += \
    func1.h

CONFIG += console

这一步也可以利用qmake自动生成

1
2
3
4
//命令行执行以下语句,添加VC环境
"D:/VS2019/VS2019/VC/Auxiliary/Build/vcvarsx86_amd64.bat"
//执行qmake语句
qmake -project
  1. 编译
1
2
3
4
call "D:/VS2019/VS2019/VC/Auxiliary/Build/vcvarsx86_amd64.bat"
qmake -o makefile LuoQt.pro
jom /f makefile
pause

控制台编译Qt.7z

Qt项目转VS工程

有以下两种方式:

  1. 命令行
1
2
3
4
//添加VC环境
"D:/VS2019/VS2019/VC/Auxiliary/Build/vcvarsx86_amd64.bat"
//生成vcxproj文件
qmake -tp vc luoQt.pro
  1. 利用插件打开pro项目

VS插件打开pro项目

信号槽

摘要
  • 类似Windows的消息机制

  • 信号函数只发送不需要知道接收者

  • 槽函数只接收不管通信.在主线程中调用,不要在其他线程中调,会崩!!!

  • 使用QObject::connect()函数进行绑定

Qt信号槽原理如下:

  1. 绑定信号函数与槽函数.
  2. 调用信号函数(将信号写入队列中).
  3. 主线程从队列中获取信号.

信号槽关系图

通过QtCreator设置信号槽

有以下两种方式:

  1. 拖动.

信号槽设置1

  1. 添加,点下方的加号进行添加.

信号槽设置2

手动添加槽函数

Q_OBJECT:

如果一个类中,我们添加了信号槽,我们就要定义Q_OBJECT这个宏,这样的话,QT的moc程序才会帮我们生成代码.

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class luoqt : public QWidget
{
    Q_OBJECT

public:
    luoqt(QWidget *parent = Q_NULLPTR);
    
//信号函数,只声明即可
signals:
    void TstSignal();
    
//槽函数声明
public slots:
    void TstSlot();

private:
    Ui::luoqtClass ui;
};

//槽函数定义
void luoqt::TstSlot()
{
    printf("Hello TstSlot\n");
}

利用QtCreator绑定信号槽

将上述写的槽函数绑定到按钮的点击事件中:

  1. 新建一个按钮,利用QtCreator拖动来设置.

槽函数绑定到按钮事件1

  1. 点击上述编辑按钮后,添加新建的槽函数.

槽函数绑定到按钮事件2

  1. 将按钮点击和刚创建的槽函数绑定起来.

槽函数绑定到按钮事件3

这样的话,就可以了,测试的时候,我们将控制台打开.

工程打开控制台

将上述写的信号函数和槽函数绑定起来:

  1. 利用QtCreator拖动来设置,在空白的地方拖一下就可以了.

信号函数和槽函数绑定1

  1. 添加信号函数和槽函数.

信号函数和槽函数绑定2

  1. 绑定.

信号函数和槽函数绑定3

Qt生成代码分析:

上面这些操作Qt帮我们生成了很多的代码,

  • 生成Connect代码.

QT生成代码1

  • 将信号和槽函数转化为字符串.

QT生成代码2

  • moc生成的槽函数调用代码.

QT生成代码3

手动绑定信号槽

  1. 新建一个按钮.

手动绑定信号槽1

  1. 添加信号和槽函数.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//luoqt.h
class luoqt : public QWidget
{
    Q_OBJECT

public:
    luoqt(QWidget *parent = Q_NULLPTR);
    
//信号函数
signals:
    void TstSignal();

//槽函数
public slots:
    void TstSlot();
    void TstConnect();

private:
    Ui::luoqtClass ui;
};
  1. 使用connect函数进行绑定.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
//luoqt.cpp
luoqt::luoqt(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    //使用connect进行绑定
    //发送者 信号函数 接收者 槽函数
    QObject::connect(ui.btn_connect, SIGNAL(TstSignal()), this, SLOT(TstConnect()));
}

void luoqt::TstSlot()
{
    printf("Hello TstSlot\n");
}

void luoqt::TstConnect()
{
    printf("Hello TstConnect\n");
}

QThread

新建一个类,继承QThread,重写run函数即可.

1
2
3
4
5
6
7
8
9
#include <QThread>
class LuoThread : public QThread
{
public:
	void run() {
		//休眠5s
		QThread::msleep(5000);
	}
};
1
2
3
4
5
//调用,调start,就会自动调用上述的run函数
LuoThread luoThread;
luoThread.start();
//或者使用下面这种
(new LuoThread())->start();

QWidget

所有用户界面对象的基类.

使用示例:

假设我们要实现的是,程序启动的时候,运行的窗口是我们新建的类所关联的一个窗口,然后5s之后窗口隐藏.

  1. 新建一个类,继承QWidget.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
//LuoQWidget.h
#include <QWidget>
class LuoQWidget : public QWidget
{
	Q_OBJECT

public:
	LuoQWidget();
	~LuoQWidget();
signals:
	void LuoHide();
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//LuoQWidget.cpp
LuoQWidget::LuoQWidget()
{
    //手动绑定信号槽
	QObject::connect(this, SIGNAL(LuoHide()), this, SLOT(hide()));
}

LuoQWidget::~LuoQWidget()
{

}
  1. 新建一个类,继承QThread.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
//LuoThread.h
#include "LuoQWidget.h"
#include <QThread>
class LuoThread : public QThread
{
public:
	LuoThread(LuoQWidget* pQWidget) {
		m_pQWidget = pQWidget;
	}
public:
	void run() {
		//休眠5s
		QThread::msleep(5000);
        //发信号
		m_pQWidget->LuoHide();
	}
private:
	LuoQWidget* m_pQWidget;
};
  1. main函数中进行调用.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//main.cpp
#include <QtWidgets/QApplication>
#include "LuoQWidget.h"
#include "LuoThread.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    LuoQWidget w;
    w.setWindowTitle("LuoQWidget");
    w.show();

    LuoThread luoThread(&w);
    luoThread.start();

    return a.exec();
}
注意
不要在其他线程中直接调用槽函数,否则会崩,我们可以绑定一个信号和槽函数,然后在其他线程中发信号.

相关函数:

获取窗口坐标和尺寸:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
QRect &QWidget::geometry();
void QWidget::setGeometry(int ax, int ay, int aw, int ah);
 
QWidget w;
w.x();
w.y();
w.width();
w.height();

void QWidget::move(int ax, int ay);
void QWidget::resize(int w, int h);

窗口状态:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
void setWindowState(Qt::WindowStates state);
//参数如下
enum WindowState {
        WindowNoState    = 0x00000000,
        WindowMinimized  = 0x00000001,
        WindowMaximized  = 0x00000002,
        WindowFullScreen = 0x00000004,
        WindowActive     = 0x00000008
    };

//Qt定义的槽函数
void showMinimized();
void showMaximized();
void showFullScreen();
void showNormal();

定制窗口:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
QWidget w;
//无边框
w.setWindowFlags(Qt::FramelessWindowHint);

//去掉最大最小化按钮
//w.setWindowFlag(Qt::WindowMinimizeButtonHint, false);
//w.setWindowFlag(Qt::WindowMaximizeButtonHint, false);

//标题栏保留,去除所有按钮
w.setWindowFlags(Qt::WindowTitleHint | Qt::CustomizeWindowHint);

w.show();

QString

使用示例

  1. 空判断
1
2
3
4
5
QString qstr;
if (qstr.isEmpty())
{
	printf("qstr is empty\n");
}
  1. 字符串拼接
1
2
3
4
QString qstr1 = "Luo";
QString qstr2 = "Hun";
qstr1 += qstr2;
//qstr1, LuoHun
  1. 字符串格式化
1
2
3
4
5
6
QString qstr;
qstr = QString("name = %1, arg = %2 %3")
		.arg("Luo", 2)
		.arg(56)
		.arg(10, 0, 16);
//qstr, name = Luo, arg = 56 a
  1. 单个整型字符串互转
1
2
3
4
//单个整型转字符串
QString qstrNum = QString::number(5566);
//字符串转整型
int num = qstrNum.toInt();
  1. 提取字符串
1
2
3
4
5
6
7
8
9
QString qstr = "Luo5566,Hun8899";
QString qstrLeft = qstr.left(5);
//qstrLeft, Luo55

QString qstrMid = qstr.mid(2, 6);
//qstrMid, o5566,

QString qstrRight = qstr.right(5);
//qstrRight, n8899
  1. 字符串查找
1
2
3
QString qstr = "Luo5566,Hun8899";
int n = qstr.indexOf("55");
//n, 3
  1. 检查字符串是否以XXX开始或结束
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
QString qstr = "Luo5566Hun";
if (qstr.startsWith("luo", Qt::CaseInsensitive))
{
	printf("startsWith True\n");
}

if (qstr.endsWith("Hun", Qt::CaseSensitive))
{
	printf("endsWith True\n");
}
  1. 字符串替换
1
2
3
QString qstr = "Luo5566,5566Hun8899";
QString qstr1 = qstr.replace("5566", "2233");
//qstr1, Luo2233,2233Hun8899
  1. 字符串两端删除空白符
1
2
3
QString qstr = " Luo5566,Hun8899 ";
QString qstr1 = qstr.trimmed();
//qstr1, Luo5566,Hun8899
  1. 分割字符串
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
QString qstr = "Luo5566:5566Hun:8899";
QStringList qLst = qstr.split(":");

for (QString str: qLst)
{
	printf("%s\n", str.toStdString().c_str());
}
//Luo5566
//5566Hun
//8899

VS中解决中文乱码

QString内部采用UTF-16编码,构造函数QString::QString(const char *str)默认使用fromUtf8(),将str所指的执行字符集从UTF-8转码成UTF-16.

VS默认创建的源码文件格式为GBK.

QtCreator默认创建的源码文件格式为UTF-8.

  1. 使用QStringLiteral
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <QDebug>
#include <QStringLiteral>
#include <QMessageBox>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	QWidget w;

	QString qstr = QStringLiteral("中文");
	qDebug() << qstr;
	QMessageBox::information(NULL, "Luo", qstr);

	w.show();
	return a.exec();
}
注意
如果源文件本身的格式为UTF-8,再用QStringLiteral这个宏进行转换就会产生乱码.
  1. 手动将该源文件格式转换为UTF-8
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <QDebug>
#include <QStringLiteral>
#include <QMessageBox>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	QWidget w;

	QString qstr = "中文";
	qDebug() << qstr;
	QMessageBox::information(NULL, "Luo", qstr);

	w.show();
	return a.exec();
}
  1. 使用代码修改源文件字符集为UTF-8
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <QDebug>
#include <QStringLiteral>
#include <QMessageBox>
#pragma execution_character_set("utf-8")

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	QWidget w;

	QString qstr = "中文";
	qDebug() << qstr;
	QMessageBox::information(NULL, "Luo", qstr);

	w.show();
	return a.exec();
}

编码方式转换

设置本地字符集:

1
2
#include <QTextCodec>
QTextCodec::setCodecForLocale(QTextCodec::codecForName("GBK"));//或UTF-8

GBK->UTF-8:

通常在VS中使用QString::fromLocal8Bit

1
2
3
char* szSrc = "中文测试";
//VS本地编码默认为GBK
QString qstr = QString::fromLocal8Bit(szSrc);

UTF-8->GBK:

通常在QtCreator中使用QString::fromUtf8

1
2
3
const char* szSrc = "中文测试";
//QtCreator本地编码默认为UTF-8
QString qstr = QString::fromUtf8(szSrc);

QString与WinAPI

将QString中存放的中文在WinAPI中使用.

1
2
3
4
5
6
7
char* szSrc = "中文测试";
//VS       中使用QString::fromLocal8Bit
//QtCreator中使用QString::fromUtf8
QString qstr = QString::fromLocal8Bit(szSrc);

::MessageBoxA(NULL, qstr.toLocal8Bit(), "MessageBoxA", MB_OK);
::MessageBoxW(NULL, qstr.toStdWString().c_str(), L"MessageBoxW", MB_OK);

QLabel

主要成员函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void setText(QString); //设置label框内的文本. 
void hide(); //隐藏label框. 
void setBuddy(QWidget*); //把另一个部件设为label框的伙伴,方便快捷使用. 
void clear(); //清空label框内所有内容. 
void setPixmap(QPixmap(QString)); //设置图片. 
void setMovie(QMovie*); //设置电影. 
void setScaledContents(bool); //设置是否按比例填充满整个label框(非常重要) 
void setToolTip(QString); //设置信息提示,鼠标放在label框上面会自动跳出文字. 
void setToolTipDuration(int); //设置信息提示的持续时间,单位是毫秒. 
void setAlignment(Qt::Alignment); //设置label框的对齐格式. 
void setStyleSheet(QString); //设置label框的样式.

播放Gif动画:

1
2
3
4
5
6
QLabel* label = new QLabel(this);
label->setGeometry(0, 0, 400, 400);
QMovie* mov =  new QMovie("tst.gif");
label->setMovie(mov);
label->show();
mov->start();

文本格式:

两种格式:

  • PlainText, \n换行.
  • RichText, 支持html.

QLabel文本格式

Url链接:

首先选择RichText.

1
2
<br>是换行.
QtCreator有点Bug,我目前使用的是5.12.0,要在文本中输入<br>后双击文本,才可以弹出下面的框

插入链接1

通过上图插入链接,Qt已经定义好了两个信号,然后就可以写槽函数来处理相应的事件了.

1
2
3
4
//鼠标点击url链接信号
void linkActivated(QString);
//鼠标滑过url链接信号
void linkHovered(QString));

属性设置:

QLabel属性

通过勾选上述标志,可设置QLabel可选择可编辑等.

QPushButton

事件信号:

1
2
3
4
void QAbstractButton::clicked()
void QAbstractButton::clicked(bool checked = false) //是否选中
void QAbstractButton::pressed()
void QAbstractButton::released()

设置快捷键:

  1. 在英文按钮前加&符号.

快捷键1

这样的话,通过快捷键Alt + P就可以激发click信号了.

  1. 使用下述代码
1
2
ui.btn_shortCut->setShortcut(tr("Alt+x"));
ui.btn_shortCut->setShortcut(tr("Alt+x,Ctrl+c"));

QLineEdit

常用函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void setText(QString); //设置文本,槽函数 不发信号
QString text();//获取文本
void setPlaceholderText(const QString &);//设置提示文字
void setClearButtonEnabled(bool enable);//是否设置一个清空按钮
void setReadOnly(bool);
void setMaxLength(int);
void setEchoMode(QLineEdit::EchoMode);//设置行编辑框内文本的显示模式
//最常用的模式,分别为:QLineEdit::Normal,QLineEdit::Password.默认为QLineEdit::Normal.
void setDragEnabled(bool); //设置行编辑框内的被选择的文本能否被拖拽,默认不能被拖拽
void setAcceptDrops(bool); //设置行编辑框能否被拖拽进来文本.
bool isModified(); //判断文本是否被修改.
void selectAll(); //选中框内所有文本.
QString displayText(); //返回显示的文本.
QString selectedText(); //返回被选中的文本.

void setInputMask(const QString &inputMask);//格式掩码
void setValidator(QVaildator*); //设置输入验证器

事件信号:

1
2
3
4
void editingFinished();//按下回车,焦点移开
void returnPressed();//格式有效,如setInputMask的参数为"NNN",则编辑框内必须输入3个英文字母或者数字,此时按回车,方可激发该信号
void textChanged(const QString &text);//setText()也会激发这个信号
void textEdited(const QString &text);

格式掩码:

假如说编辑框中要设置格式,比如说要指定输入IP地址

1
2
ui.Edt_IP->setInputMask("000.000.000.000;_");
//;后面的_,表示无输入时,填_

格式校验:

设置有效范围:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <QIntValidator>
#include <QDoubleValidator>

//设置只输入整型,设置有效范围为10, 100
QIntValidator* iVal = new QIntValidator();
iVal->setRange(10, 100);
ui.Edt_Int->setValidator(iVal);

//设置只输入浮点,设置有效范围为10, 20,精度为2,即小数点后面有两位
QDoubleValidator* dVal = new QDoubleValidator(0);
dVal->setRange(10, 20, 3);
dVal->setNotation(QDoubleValidator::StandardNotation);
ui.Edt_Double->setValidator(dVal);

//验证邮箱
QRegExp exp("[a-zA-Z0-9-_]+@[a-zA-Z0-9_]+\\.[a-zA-Z]+");
QRegExpValidator* rVal  = new QRegExpValidator();
rVal->setRegExp(exp);
ui.Edt_RegExp->setValidator(rVal);
注意
上述是设置LineEdit的有效范围,并不是限制输入的范围,如果想要限制输入的范围,我们可以使用QSpinBox、QDoubleSpinBox.
1
2
ui.spinBox->setRange(10, 20);
ui.doubleSpinBox->setRange(1.0, 20.0);

校验是否有效:

我们可以设置一个按钮,当编辑框输入内容后,点击按钮来校验.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
const QValidator* pQValidator = ui.Edt_Int->validator();
int pos = 0;
int nRet = pQValidator->validate(ui.Edt_Int->text(), pos);
if (nRet == QValidator::Acceptable)
{
	qDebug() << QStringLiteral("格式正确");
}
//nRet的返回值有以下三种
//QValidator::Invalid       格式正确
//QValidator::Intermediate  中间输入没结束
//QValidator::Acceptable    格式正确

Qt布局

遍历QObject子节点:

1
2
3
4
5
6
7
8
9
QObjectList cs = this->children();
for (int i = 0; i < cs.size(); i++)
{
	//遍历子节点, 获取节点对象名称
	qDebug() << cs[i]->objectName();
	//遍历子节点, 获取节点对象类型
	const QMetaObject* oj = cs[i]->metaObject();
	qDebug() << oj->className();
}

递归遍历QObject子节点:

可以遍历子节点的子节点.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void PrintName(QObject* obj)
{
	if (!obj)  //为空直接返回
	{
		return;
	}

	printf("%s :", obj->objectName().toStdString().c_str());
	const QMetaObject* mobj = obj->metaObject(); //获取元数据
	QString cname = mobj->className();
	printf("%s\n", cname.toStdString().c_str());

	//对PushButton进行操作
	if (cname == "QPushButton")
	{
		QPushButton* pb = qobject_cast<QPushButton*>(obj);
		if (pb)
		{
			pb->setText(pb->text() + "class");
		}
	}

	//递归打印名字
	QObjectList cs = obj->children();
	if (cs.size() <= 0)
	{
		return;
	}
	for (int i = 0; i < cs.size(); i++)
	{
		PrintName(cs[i]);
	}
}

QSizePolicy布局尺寸策略分析:

有四种布局:

  • Vertical Layout
  • Horizontal Layout
  • Grid Layout
  • Form Layout

SizeHint推荐尺寸:

1
2
QSize sizeHint() //推荐尺寸,只能重载修改
QSize size()     //不包含边框的窗口尺寸

QSizePolicy::PolicyFlag:

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

QSizePolicy::Policy:

QSizePolicy::Policy QSizePolicy::PolicyFlag
Fixed 0 只参考sizeHint()
Minimum GrowFlag 伸展和收缩 >= sizeHint()
Maximum ShrinkFlag 伸展和收缩 <= sizeHint()
Preferred GrowFlag | ShrinkFlag
Expanding GrowFlag | ShrinkFlag | ExpandFlag 尽量缩放,最小值为推荐值
MinimumExpanding GrowFlag | ExpandFlag
Ignored ShrinkFlag | GrowFlag | IgnoreFlag 忽略推荐大小,尽量缩放

QVBoxlayout,QHBoxLayout:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <QWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	//设置全局字体
	QFont f("Yahei Mono", 12);
	a.setFont(f);

	QWidget* LuoWin = new QWidget;
	LuoWin->resize(400, 400);

	//垂直布局
	QVBoxLayout* lay = new QVBoxLayout;

	//新建一个按钮
	QPushButton* btn1 = new QPushButton("btn1");
	//设置按钮的尺寸策略, 设置Fixed, 使用推荐尺寸
	btn1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
	//设置按钮的最大最小尺寸
	btn1->setMinimumSize(20, 10);
	btn1->setMaximumSize(600, 100);

	QPushButton* btn2 = new QPushButton("btn2");
	//布局中添加按钮
	lay->addWidget(btn1);
	lay->addWidget(btn2);

	//设置布局的边界, 在LuoWin->show()前设置和后面设置是不一样的,在前设置才可以改变btn1->width()的值
	lay->setContentsMargins(0, 0, 0, 0);

	//设置布局中元素之间的间距,垂直布局,当缩的很小的时候,就可以看到间距了
	lay->setSpacing(10);

	//添加上述布局
	LuoWin->setLayout(lay);

	LuoWin->show();

	//打印推荐尺寸,这个值只有在设置了布局,才可能有效
	qDebug() << "width:\t" << btn1->sizeHint().width() <<" height:" << btn1->sizeHint().height();

	//打印实际尺寸
	qDebug() << "width:\t" << btn1->width() <<" height:" << btn1->height();

	return a.exec();
}

QGridLayout:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <QWidget>
#include <QSizePolicy>
#include <QGridLayout>
#include <QPushButton>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	//设置全局字体
	QFont f("Yahei Mono", 12);
	a.setFont(f);

	QWidget* LuoWin = new QWidget;
	LuoWin->resize(200, 200);

	QGridLayout* lay = new QGridLayout;

	QPushButton* btn00 = new QPushButton("btn00");
	QPushButton* btn02 = new QPushButton("btn02");
	QPushButton* btn12 = new QPushButton("btn12");
	QPushButton* btn33 = new QPushButton("btn33");

	lay->addWidget(btn00, 0, 0);
	lay->addWidget(btn02, 0, 2);
	lay->addWidget(btn12, 1, 2);
	lay->addWidget(btn33, 3, 3);

	//设置控件之间的间距
    //水平间距
	lay->setHorizontalSpacing(20);
	//垂直间距
	lay->setVerticalSpacing(10);
	//也可以使用setSpacing同时设置水平和垂直间距
	//lay->setSpacing(10);
	
	//设置布局的对齐方式
	lay->setAlignment(Qt::AlignLeft);

	LuoWin->setLayout(lay);

	LuoWin->show();

	return a.exec();
}

QFormLayout:

以下示例,实现遍历FormLayout布局所有元素,并实现空验证和清除.

luoqt.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#pragma once
#include <QtWidgets/QWidget>
#include "ui_luoqt.h"
#include <QDebug>
#include <QFile>

#include <QFormLayout>
#include <QPushButton>
#include <QLineEdit>
#include <QLabel>
class luoqt : public QWidget
{
    Q_OBJECT

public:
    luoqt(QWidget *parent = Q_NULLPTR);

public slots:
	//设置皮肤样式
    static void SetStyle(const QString& styleName);

    void Save();
    void Clear();

private:
    Ui::luoqtClass ui;
};

luoqt.cpp:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "luoqt.h"

luoqt::luoqt(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

    //新建一个FormLayout布局
	QFormLayout* lay = new QFormLayout;
	QLineEdit* edtName = new QLineEdit;
    //创建一个带有给定文本的QLabel及QWidget控件行
	lay->addRow("&Name", edtName);

	QLineEdit* edtEmail = new QLineEdit;
	lay->addRow("&Email", edtEmail);

	QLineEdit* edtAge = new QLineEdit;
	//插入到下标1的位置, 从0开始
	lay->insertRow(1, "&Age", edtAge);

	//显示出错信息
	QLabel* labelInfo = new QLabel;
	labelInfo->setText("Input");
	labelInfo->setStyleSheet("color:red");
	//插入到下标0的位置, 从0开始
	lay->insertRow(0, "", labelInfo);

	//添加Save clear按钮
	QPushButton* btnSave = new QPushButton("Save");
	QPushButton* btnClear = new QPushButton("Clear");

	//信号槽绑定
	QObject::connect(btnSave, SIGNAL(clicked()), this, SLOT(Save()));
	QObject::connect(btnClear, SIGNAL(clicked()), this, SLOT(Clear()));

	//添加一个平行布局
	QHBoxLayout* hLay = new QHBoxLayout;
	hLay->addWidget(btnSave);
	hLay->addWidget(btnClear);
	lay->addRow(hLay);

	this->setLayout(lay);
}

void luoqt::SetStyle(const QString& styleName)
{
	QFile file(QString("./image/%1.qss").arg(styleName));
	bool b = file.open(QFile::ReadOnly);
	QString qss = QLatin1String(file.readAll());
	qApp->setStyleSheet(qss);
	qApp->setPalette(QPalette(QColor("#F0F0F0")));
}

void luoqt::Save()
{
	//扎到layout
	QFormLayout* lay = (QFormLayout*)this->layout();

	//找到显示错误信息的Label
	QLabel* label = (QLabel*)lay->itemAt(0, QFormLayout::FieldRole)->widget();
	//存放错误信息
	QString qstrErr = "";

	//遍历FormLayout的所有元素
	for (int i = 0; i < lay->rowCount(); i++)
	{
		//Label
		QLayoutItem* LabelItem = lay->itemAt(i, QFormLayout::LabelRole);
		if (!LabelItem)
		{
			continue;
		}
		QLabel* titleLabel = (QLabel*)LabelItem->widget();
		if (!titleLabel)
		{
			continue;
		}

		//Field
		QLayoutItem* fieldItem = lay->itemAt(i, QFormLayout::FieldRole);
		QLineEdit* pWidget = (QLineEdit*)fieldItem->widget();
		if (!pWidget)
		{
			continue;
		}
		QString qstrName = pWidget->metaObject()->className();
		if (qstrName == "QLineEdit")
		{
			if (pWidget->text().trimmed() == "")
			{
				pWidget->setFocus();
				qstrErr += titleLabel->text();
				qstrErr += "is Empty\n";
			}
		}
	}

	label->setText(qstrErr);
}

void luoqt::Clear()
{
	//扎到layout
	QFormLayout* lay = (QFormLayout*)this->layout();

	//遍历所有LineEdit
	//遍历FormLayout的所有元素
	for (int  i = 0; i < lay->rowCount(); i++)
	{
		QLayoutItem* fieldItem = lay->itemAt(i, QFormLayout::FieldRole);
		QLineEdit* pWidget = (QLineEdit*)fieldItem->widget();
		if (!pWidget)
		{
			continue;
		}
		QString qstrName = pWidget->metaObject()->className();
		if (qstrName == "QLineEdit")
		{
			pWidget->setText("");
		}

	}
}

main.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include "luoqt.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	//设置全局字体
	QFont f("Yahei Mono", 12);
	a.setFont(f);

	luoqt w;
	w.show();

	return a.exec();
}

QCheckBox

默认多选.

常用函数:

1
2
3
4
5
6
7
8
9
//文本获取与设置
QString text() const;
void setText(const QString &text);
//状态获取与设置
bool isChecked() const;
void setChecked(bool);
//设置自动排他,单选属性
//若同Widget上的两个QCheckBox设置该属性,则每次只能选择其中一个
void setAutoExclusive(bool);

事件信号:

1
2
void QAbstractButton::clicked(bool checked = false);//按钮点击,就会触发该信号
void QAbstractButton::toggled(bool checked);         //状态发生变化,就会触发该信号

QButtonGroup

将一组按钮放在ButtonGroup上,点击时,可以知道哪个按钮被点击了.

常用信号:

1
2
3
4
5
6
7
8
void buttonClicked(QAbstractButton *button);
void buttonClicked(int id);
void buttonPressed(QAbstractButton *button);
void buttonPressed(int id);
void buttonReleased(QAbstractButton *button);
void buttonReleased(int id);
void buttonToggled(QAbstractButton *button, bool checked);
void buttonToggled(int id, bool checked);

示例:

luoqt.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <QCheckBox>
#include <QButtonGroup>
class luoqt : public QWidget
{
    Q_OBJECT

public:
    luoqt(QWidget *parent = Q_NULLPTR);

public slots:
    void LuoClicked(QAbstractButton* button);
    void LuoToggled(QAbstractButton* button, bool checked);

private:
    Ui::luoqtClass ui;
};

luoqt.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "luoqt.h"

luoqt::luoqt(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

	QButtonGroup* btnGroup = new QButtonGroup(this);
	//加组后,默认变为单选
	btnGroup->addButton(ui.checkBox1);
	btnGroup->addButton(ui.checkBox2);
	btnGroup->addButton(ui.checkBox3);
	//改为多选
	btnGroup->setExclusive(false);

	//信号槽绑定
	QObject::connect(btnGroup, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(LuoClicked(QAbstractButton*)));
	QObject::connect(btnGroup, SIGNAL(buttonToggled(QAbstractButton* , bool)), this, SLOT(LuoToggled(QAbstractButton*, bool)));
}

void luoqt::LuoClicked(QAbstractButton* button)
{
	qDebug() << "LuoClicked:" << button->text() << button->isChecked();
}

void luoqt::LuoToggled(QAbstractButton* button, bool checked)
{
	qDebug() << "LuoToggled:" << button->text() << button->isChecked();
}

QRadioButton

类似QCheckBox, 默认单选

示例:

luoqt.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <QVBoxLayout>
#include <QButtonGroup>
class luoqt : public QWidget
{
    Q_OBJECT

public:
    luoqt(QWidget *parent = Q_NULLPTR);

public slots:
    void LuoSave();

private:
    Ui::luoqtClass ui;
};

luoqt.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "luoqt.h"

luoqt::luoqt(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

	//单选按钮
	QRadioButton* btnRadio1 = new QRadioButton("btnRadio1");
	QRadioButton* btnRadio2 = new QRadioButton("btnRadio2");
	QRadioButton* btnRadio3 = new QRadioButton("btnRadio3");

	//按钮组
	QButtonGroup* btnGroup = new QButtonGroup(this);
	btnGroup->setObjectName("btnGroup");//这里设置ObjectName, 方便下面查找
	btnGroup->addButton(btnRadio1);
	btnGroup->addButton(btnRadio2);
	btnGroup->addButton(btnRadio3);

	//垂直布局
	QVBoxLayout* layVbox = new QVBoxLayout(this);
	//遍历QButtonGroup
	for (int i = 0; i < btnGroup->buttons().size(); i++)
	{
		layVbox->addWidget(btnGroup->buttons()[i]);
	}
	
	//保存按钮
	QPushButton* btnSave = new QPushButton("Save");
	layVbox->addWidget(btnSave);

	QObject::connect(btnSave, SIGNAL(clicked()), this, SLOT(LuoSave()));
}

void luoqt::LuoSave()
{
	//获取btnGroup
	QButtonGroup* btnGroup = this->findChild<QButtonGroup*>("btnGroup");
	if (!btnGroup)
	{
		return;
	}

	//获取被选中的按钮
	QRadioButton* btnSelRadio = (QRadioButton*)btnGroup->checkedButton();
	if (!btnSelRadio)
	{
		QMessageBox::warning(this, "", "Please checked!");
	}
	else
	{
		QMessageBox::information(this, "", btnSelRadio->text());
	}
}

QComboBox

常用函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
//新增数据
void addItem(const QString &text, const QVariant &userData = QVariant());
void addItem(const QIcon &icon, const QString &text, const QVariant &userData = QVariant());
void addItems(const QStringList &texts);
//插入数据
void insertItem(int index, const QString &text, const QVariant &userData = QVariant());
void insertItem(int index, const QIcon &icon, const QString &text, const QVariant &userData = QVariant());
void insertItems(int index, const QStringList &list);
//QVariant 用户自定义数据

//获取当前下标
int currentIndex() const
//获取当前文本
QString currentText() const
    
//删除数据
void removeItem(int index);
void clearEditText(); //可编辑模式时,清空
void clear();

事件信号:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//用户选中
void activated(int index); 
void activated(const QString &text);
//状态发生变化
void currentIndexChanged(int index);
void currentTextChanged(const QString &text);
//只读模式没有
void editTextChanged(const QString &text);
//选择下拉框,滑过,高亮某行时,就会触发该信号
void highlighted(int index)
void highlighted(const QString &text)

示例:

luoqt.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <QIcon>
#include <QComboBox>
class luoqt : public QWidget
{
    Q_OBJECT

public:
    luoqt(QWidget *parent = Q_NULLPTR);

public slots:
    void LuoClick();

private:
    Ui::luoqtClass ui;
};

luoqt.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "luoqt.h"

struct LuoType
{
	int x;
	int y;
};

//使Qt支持此类型
Q_DECLARE_METATYPE(LuoType)

luoqt::luoqt(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);

	ui.comboBox->clear();
	//添加用户自定义数据
	LuoType luoType;
	luoType.x = 100;
	QVariant var;
	var.setValue(luoType);
	ui.comboBox->addItem("001", var);

	QIcon icon(":/luoqt/kenan.png");
	ui.comboBox->addItem(icon, "002");
	
	ui.comboBox->insertItem(1, "003");
}

void luoqt::LuoClick()
{
    //获取当前行下标
	qDebug() << ui.comboBox->currentIndex();;

	//打印第0行的自定义数据
	qDebug() << ui.comboBox->itemText(0);
	QVariant var = ui.comboBox->itemData(0);
	qDebug() << var.value<LuoType>().x;
}

QSlider

属性:

1
2
3
4
5
6
7
8
9
setRange(int min, int max);
//键盘,方向键控制
void setSingleStep(int);
//鼠标, 这里通过鼠标点击,并不是点到哪里,就拖动到哪里
void setPageStep(int);
//方向
void setOrientation(Qt::Orientation);
//Qt::Horizontal
//Qt::Vertical

事件信号:

1
2
3
4
void sliderMoved(int value);//拖动
void sliderPressed();//点击滑块
void sliderReleased();//松开滑块
void valueChanged(int value);//点击或者设置

重载鼠标事件:

实现鼠标点击到哪里,滑块就滑动到哪里.

  1. 新建一个类LuoSlider,继承QSlider,重载mousePressEvent

LuoSlider.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include <QSlider>
#include <QWidget>
#include <QMouseEvent>
#include <QDebug>
class LuoSlider : public QSlider
{
public:
	LuoSlider(QWidget* p = NULL);
	~LuoSlider();

public:
	virtual void mousePressEvent(QMouseEvent* e);
};

LuoSlider.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include "LuoSlider.h"

LuoSlider::LuoSlider(QWidget* p /*= NULL*/):QSlider(p)
{
}

LuoSlider::~LuoSlider()
{
}

void LuoSlider::mousePressEvent(QMouseEvent* e)
{
	double dbl = (double)e->pos().x() / (double)width();
	int nVal = dbl * (maximum() - minimum()) + minimum();
	setValue(nVal);

	QSlider::mousePressEvent(e);
	qDebug() << e->pos().x();
}
  1. 将新建的类LuoSlider与界面上的QSlider关联

LuoSlider提升1

LuoSlider提升2

QListWidget

属性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
//单选,多选
QAbstractItemView::SelectionMode selectionMode() const;
void setSelectionMode(QAbstractItemView::SelectionMode mode);
enum SelectionMode {
		NoSelection,
		SingleSelection,    //单选
		MultiSelection,     //多选
		ExtendedSelection,  //Ctrl + 鼠标 多选, Shift + 鼠标 连续选
		ContiguousSelection //Ctrl + 鼠标 以及 Shift + 鼠标 都是连续选
};
//从上到下或从左到右排列
flow
//每一行的行高
gridSize
//图标的宽高
iconSize

QListWidget属性

常用函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//新增数据
void addItem(const QString &label);
void addItem(QListWidgetItem *item);
void addItems(const QStringList &labels);
//添加数据
void insertItem(int row, QListWidgetItem *item);
void insertItem(int row, const QString &label);
void insertItems(int row, const QStringList &labels);
//获取ListWidget, item个数
int count() const;
//获取当前行数据
QListWidgetItem *currentItem() const;
int currentRow() const;
 
//设置列表控件的编辑策略 
void setEditTriggers(QAbstractItemView::EditTriggers triggers);
enum EditTrigger {
        NoEditTriggers = 0,
        CurrentChanged = 1,
        DoubleClicked = 2,
        SelectedClicked = 4,
        EditKeyPressed = 8,
        AnyKeyPressed = 16,
        AllEditTriggers = 31
};

//排序
void sortItems(Qt::SortOrder order = Qt::AscendingOrder);

//将列表控件的某一项,设置为控件
void setItemWidget(QListWidgetItem *item, QWidget *widget)

//Public Slots
void clear();

事件信号:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
//鼠标键盘选中
void currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
void currentRowChanged(int currentRow);
void currentTextChanged(const QString &currentText);
//激活, 双击
//可编辑状态下,双击不会触发该信号
void itemActivated(QListWidgetItem *item);
//列表内容改变
//通过代码修改或者手动修改列表项显示的文字,会触发该信号
//通过代码新增列表数据,该信号并不会触发
void itemChanged(QListWidgetItem *item);
//鼠标左键松开  
void itemClicked(QListWidgetItem *item);
//鼠标左键或右键双击
void itemDoubleClicked(QListWidgetItem *item);
//在设置鼠标跟踪后,鼠标移上去,才会触发该信号
//setMouseTracking(true);
void itemEntered(QListWidgetItem *item);
//鼠标左键或右键按下
void itemPressed(QListWidgetItem *item);
//选择改变
void itemSelectionChanged();

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <QListWidget>
#include <QIcon>
#include <QLineEdit>

luoqt::luoqt(QWidget* parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	//清空数据
	ui.listWidget->clear();

	//插入数据方式一
	QListWidgetItem* item1 = new QListWidgetItem;
	item1->setText("item1");
	ui.listWidget->addItem(item1);
	//插入数据方式二
	new QListWidgetItem("item2", ui.listWidget);
	//插入数据方式三
	ui.listWidget->addItem("item3");

	//插入包含图标的数据
	QListWidgetItem* item4 = new QListWidgetItem;
	item4->setText("item4");
	item4->setIcon(QIcon(":/luoqt/kenan.png"));
	ui.listWidget->addItem(item4);

	//插入其他控件, 如LineEdit
	QListWidgetItem* item5 = new QListWidgetItem("12", ui.listWidget);
	QLineEdit* edtLine = new QLineEdit("item5 LineEdit");
	ui.listWidget->setItemWidget(item5, edtLine);

	//设置鼠标跟踪
	//ui.listWidget->setMouseTracking(true);

	//设置编辑策略, 双击启用编辑状态
	ui.listWidget->setEditTriggers(QAbstractItemView::DoubleClicked);
	//遍历listWidget中的每个item,设置属性
	for (int i = 0; i < ui.listWidget->count(); i++)
	{
		ui.listWidget->item(i)->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled);
	}

	//设置排序, 升序
	ui.listWidget->sortItems(Qt::AscendingOrder);
}

QTableWidget

属性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//标题显示(上方、左侧) 
horizontalHeader() verticalHeader()
//滚动条显示
setVerticalScrollBarPolicy
//选择模式,跟QListWidget一样
selectionMode
//选择行、列、一项
//常用的是行选择
setSelectionBehavior
//左上角全选按钮 标题上方和左侧都显示的时候,可以看到这个按钮
setCornerButtonEnabled
//网格显示
setShowGrid setGridStyle
//排序按钮
setSortingEnabled

QTableWidget属性

事件信号:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//在设置鼠标跟踪后,鼠标移上去,才会触发该信号,自定义widget不一定有效(Bug)
//setMouseTracking(true);
void cellEntered(int row, int column);

void cellChanged(int row, int column);
void cellClicked(int row, int column);
void cellDoubleClicked(int row, int column);

//仅 QTableWidgetItem 可触发下述信号
//在设置鼠标跟踪后,鼠标移上去,才会触发该信号,自定义widget无效
//setMouseTracking(true);
void itemEntered(QTableWidgetItem *item);    
    
void itemChanged(QTableWidgetItem *item);
void itemClicked(QTableWidgetItem *item);
void itemDoubleClicked(QTableWidgetItem *item);

//标题栏点击信号
//QTableWidget标题栏的类型为QHeaderView
//可在QT手册中查看QHeaderView的信号事件
void sectionClicked(int logicalIndex);
//代码进行绑定
QObject::connect(ui.tableWidget->horizontalHeader(),
                 SIGNAL(sectionClicked(int)), 
                 this, 
                 SLOT(SectionClicked(int)));

清空内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <QTableWidget>
#include <QDebug>
#include <QIcon>
#include <QLabel>
#include <QPixmap>
#include <set>
#include <QMessageBox>

ui.tableWidget->setColumnCount(0);
ui.tableWidget->setRowCount(0);

插入标题:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class LuoHeader :public QTableWidgetItem
{
public:
	LuoHeader::LuoHeader(QString qstr) : QTableWidgetItem(qstr)
	{
	}

	LuoHeader::~LuoHeader()
	{
		qDebug() << this->text() << "removed";
	}
};

//插入列标题
ui.tableWidget->setColumnCount(5);
//方式1
ui.tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("Col1"));
//方式2
ui.tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem);
ui.tableWidget->horizontalHeaderItem(1)->setText("Col2");
//方式3
ui.tableWidget->setHorizontalHeaderItem(2, new LuoHeader("C3"));
//在同样的位置插入标题,会清理之前的对象,一会查看控制台,就会发现LuoHeader的析构函数会被调用
ui.tableWidget->setHorizontalHeaderItem(2, new LuoHeader("Col2"));

//设置标题列的宽度
ui.tableWidget->setColumnWidth(0, 200);

//插入行标题
ui.tableWidget->setRowCount(3);
//设置方式跟上面一样, 只不过要将Horizontal换成Vertical
//这里展示一种不一样的玩法
QStringList qstrList = { "Row1", "Row2", "Row3" };
ui.tableWidget->setVerticalHeaderLabels(qstrList);

插入数据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
int nRow = 0;
int nCol = 0;
//上面设置了 3行5列
//在0行0列、0行1列、0行2列添加内容
ui.tableWidget->setItem(0, 0, new QTableWidgetItem("Item 0, 0"));
ui.tableWidget->setItem(0, 1, new QTableWidgetItem("Item 0, 1"));
ui.tableWidget->setItem(0, 2, new QTableWidgetItem("Item 0, 2"));

//结尾添加一行
nRow = ui.tableWidget->rowCount();
ui.tableWidget->insertRow(nRow);
ui.tableWidget->setItem(nRow, 0, new QTableWidgetItem("ItemEnd"));

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

//插入QIcon图片
nRow = 0;
nCol = 1;
ui.tableWidget->setItem(nRow, nCol, new QTableWidgetItem);
ui.tableWidget->item(nRow, nCol)->setIcon(QIcon(":/luoqt/kenan.png"));
//设置行高
ui.tableWidget->setRowHeight(nRow, 80);
//设置图标显示大小
ui.tableWidget->setIconSize(QSize(ui.tableWidget->rowHeight(nRow), ui.tableWidget->rowHeight(nRow)));

//插入Widget图片
nRow = 2;
nCol = 0;
QLabel* qLabel = new QLabel;
QPixmap qPix(":/luoqt/kenan.png");
//缩放到和表格单元的宽高一致
qPix = qPix.scaled(ui.tableWidget->columnWidth(nCol), ui.tableWidget->rowHeight(nRow));
qLabel->setPixmap(qPix);
ui.tableWidget->setCellWidget(nRow, nCol, qLabel);

//插入空数据
ui.tableWidget->insertRow(0);
ui.tableWidget->insertRow(0);

//设置每次选择以行为单位
ui.tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);

获取选中数据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//方式一
//这种方式,无法选择空行
qDebug() << QStringLiteral("方式一--------------------------------");
QList<QTableWidgetItem*> qTableItems = ui.tableWidget->selectedItems();
for (int i = 0; i < qTableItems.size(); i++)
{
	qDebug() << qTableItems[i]->row()
		<< ":"
		<< qTableItems[i]->column()
		<< " text="
		<< qTableItems[i]->text();
}

//方式2
//这种方式,可以选择空行
qDebug() << QStringLiteral("方式二--------------------------------");
//选择模式器
QItemSelectionModel* qItemSelModel = ui.tableWidget->selectionModel();
//获取所有的选择索引
QModelIndexList qModelIndexLst = qItemSelModel->selectedIndexes();
//获取所有被选中的行号
std::set<int> stdRows;
for (int i = 0; i < qModelIndexLst.size(); i++)
{
	//重复的插入会失败
	stdRows.insert(qModelIndexLst[i].row());
}

删除数据:

1
2
3
//Slot
void removeColumn(int column)
void removeRow(int row)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//给用户提示
QString qstrMsg = QStringLiteral("您确认删除:");

for (std::set<int>::iterator itr = stdRows.begin(); itr != stdRows.end(); itr++)
{
	QTableWidgetItem* item = ui.tableWidget->item(*itr, 0);
	qstrMsg += "[";
	qstrMsg += QString::number(*itr + 1);
	qstrMsg += ":";
	if (item)
	{
		qstrMsg += item->text();
	}
	qstrMsg += "]";
}

int nRet = QMessageBox::information(this, "",
	qstrMsg, QStringLiteral("确认"),
	QStringLiteral("取消"));

//用户点击了确认按钮, nRet == 0
//用户点击了取消按钮, nRet == 1
if (nRet == 0)
{
	//删除多行
	while (true)
	{
		//获取所有的选择索引
		QModelIndexList s = qItemSelModel->selectedIndexes();
		if (s.size() <= 0)
		{
			break;
		}

		//每次删除一行
		ui.tableWidget->removeRow(s[0].row());
	}
}
QTableWidget.7z

QTreeWidget

属性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//标题显示与隐藏
header()->setVisible(true)
//排序
setSortingEnabled
//动画
setAnimated
//滚动条显示
setVerticalScrollBarPolicy
serHorizontalScrollBarPolicy
//选择模式,跟QListWidget一样
selectionMode
//选择行、列、一项
setSelectionBehavior

QTreeWidget属性

常用函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//QTreeWidget
//插入顶部节点
void insertTopLevelItem(int index, QTreeWidgetItem *item);
void insertTopLevelItems(int index, const QList<QTreeWidgetItem *> &items);
void QTreeWidget::addTopLevelItem(QTreeWidgetItem *item);
void QTreeWidget::addTopLevelItems(const QList<QTreeWidgetItem *> &items);
//获取顶部节点
QTreeWidgetItem *QTreeWidget::topLevelItem(int index) const;
//获取顶部节点数量
int topLevelItemCount() const;
//插入Widget控件
void QTreeWidget::setItemWidget(QTreeWidgetItem *item, int column, QWidget *widget);
//获取选中节点
QList<QTreeWidgetItem *> QTreeWidget::selectedItems() const;
//设置列数量
void setColumnCount(int columns);

//QTreeWidgetItem
//插入子节点
void addChild(QTreeWidgetItem *child);
void addChildren(const QList<QTreeWidgetItem *> &children);
//设置文本
void setText(int column, const QString &text);
//获取父节点
QTreeWidgetItem* QTreeWidgetItem::parent() const;
//获取treeWidget
QTreeWidget* treeWidget() const;

槽函数:

1
2
3
4
5
void clear();
//收缩
void collapseItem(const QTreeWidgetItem *item);
//展开
void expandItem(const QTreeWidgetItem *item);

事件信号:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
void currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void itemActivated(QTreeWidgetItem *item, int column);
void itemChanged(QTreeWidgetItem *item, int column);
void itemClicked(QTreeWidgetItem *item, int column);
void itemCollapsed(QTreeWidgetItem *item);
void itemDoubleClicked(QTreeWidgetItem *item, int column);
void itemEntered(QTreeWidgetItem *item, int column);
void itemExpanded(QTreeWidgetItem *item);
void itemPressed(QTreeWidgetItem *item, int column);
void itemSelectionChanged();

清空内容:

1
2
3
4
5
6
7
8
9
#include <QTreeWidget>
#include <QPushButton>

//清理标题,不清理数据
//ui.treeWidget->setColumnCount(0);//设置为0,不会清理
ui.treeWidget->setHeaderItem(new QTreeWidgetItem);

//清空数据
ui.treeWidget->clear();

插入标题:

1
2
3
4
5
6
//设置4列
QTreeWidgetItem* pTreeHeader = ui.treeWidget->headerItem();
pTreeHeader->setText(0, "head1");
pTreeHeader->setText(1, "head2");
pTreeHeader->setText(2, "head3");
pTreeHeader->setText(3, "head4");

插入数据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//顶部节点插入
//在结尾处插入
//方式一
ui.treeWidget->addTopLevelItem(new QTreeWidgetItem());
ui.treeWidget->topLevelItem(0)->setText(0, "tree node1");
ui.treeWidget->topLevelItem(0)->setText(1, "tree node2");
//方式二
ui.treeWidget->addTopLevelItem(new QTreeWidgetItem({"tree node11", "tree node22"}));

//在指定位置插入
ui.treeWidget->insertTopLevelItem(0, new QTreeWidgetItem({ "tree node1-1", "tree node2-2" }));
//在结尾插入
ui.treeWidget->insertTopLevelItem(ui.treeWidget->topLevelItemCount(), new QTreeWidgetItem({ "tree node End" }));

//子节点插入
//方式一
ui.treeWidget->topLevelItem(0)->addChild(new QTreeWidgetItem({ "child1" ,"child2", "child3" }));
/ ui.treeWidget->topLevelItem(1)->addChild(new QTreeWidgetItem({ "child11" }));
//方式二
QTreeWidgetItem* pTreeItem = ui.treeWidget->topLevelItem(1);
ui.treeWidget->addTopLevelItem(new QTreeWidgetItem(pTreeItem, { "child110012" }));

//插入图标
ui.treeWidget->setIconSize(QSize(60, 60));
ui.treeWidget->topLevelItem(0)->setIcon(0, QIcon(":/luoqt/ke nan.png"));

//插入Widget控件
QPushButton* btn = new QPushButton("test");
ui.treeWidget->setItemWidget(ui.treeWidget->topLevelItem(1), 0, btn);

QDialog

常用函数:

1
2
//拿Dialog的返回值,与exec的返回值一样
int QDialog::result() const;

槽函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//默认显示的是非模态对话框.
//可在show前调用setModal(true),或者setWindowModality(Qt::ApplicationModal),将其设置为模态对话框.
void QWidget::show();
//阻塞,有返回值, 显示的是模态对话框.
virtual int exec();

//可将一个按钮的点击信号与下述槽函数绑定
//exec的返回值为 QDialog::Accepted
virtual void accept();
//exec的返回值为 QDialog::Rejected
virtual void reject();
//可在与按钮点击信号绑定的槽函数中调用,这样就可以自定义exec的返回值为 r
virtual void done(int r);

自定义MessageBox:

  1. 新建一个Qt类继承QDialog

自定义MessageBox1

自定义MessageBox2

  1. 自定义界面

可以弄一个QLabel控件用来显示要提示的信息,

将确认按钮与QDialog的槽函数accept绑定,

将取消按钮与QDialog的槽函数reject绑定.

QProgressBar应用:

新建一个线程类,模拟做事:

LuoThread.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <QThread>

class LuoThread : public QThread
{
	Q_OBJECT

public:
	LuoThread();
	~LuoThread();
protected:
	void run();

signals:
	///0~1000
	void SetPos(int pos);
};

LuoThread.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include "luothread.h"

LuoThread::LuoThread()
{
}

LuoThread::~LuoThread()
{
}

void LuoThread::run()
{
	//模拟做事
    //这个地方需要设置QProgressBar的范围为0-1000
	for (int i = 0; i <= 1000; i++)
	{
		SetPos(i);
		msleep(5);
	}
}

新建一个对话框类,显示进度:

LuoProgressDialog.h:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <QDialog>
#include <QThread>
#include "ui_LuoProgressDialog.h"

class LuoProgressDialog : public QDialog
{
	Q_OBJECT

public:
	LuoProgressDialog(QWidget *parent = Q_NULLPTR);
	~LuoProgressDialog();

public slots:
	//0~1000
	void SetPos(int pos);

private:
	Ui::LuoProgressDialog ui;
};

LuoProgressDialog.cpp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include "LuoProgressDialog.h"

LuoProgressDialog::LuoProgressDialog(QWidget *parent)
	: QDialog(parent)
{
	ui.setupUi(this);

	//为了实现圆角效果,在QDialog上面放一个QWidget控件
	//在QWidget控件上面放一个QProgressBar控件

	//去掉标题栏
	this->setWindowFlags(Qt::FramelessWindowHint);

	//设置背景透明
	this->setAttribute(Qt::WA_TranslucentBackground, true);

}

LuoProgressDialog::~LuoProgressDialog()
{
}

void LuoProgressDialog::SetPos(int pos)
{
	ui.progressBar->setValue(pos);
	if (pos == 1000)
	{
		for (int i = 100; i > 0; i--)
		{
			//透明度 1.0 0.0
			this->setWindowOpacity((float)i / 100.0);
			QThread::msleep(10);

			//界面上有一个QLabel控件
			//这个地方的setText只是发出信号,需要等待槽函数进行处理
			//LuoProgressDialog::SetPos(int pos)这个槽函数不退出,setText的槽函数是不会处理的
			ui.label->setText(QString::number(i));
			//这一步会将消息队列中的消息都处理下,会立即调用槽函数
			QEventLoop loop;
			loop.processEvents();
		}
		this->close();
	}
}

为了实现圆角效果,需要设置QWidget的样式为:

1
2
3
4
5
#widget{
	background-color: qlineargradient(spread:reflect, x1:0.999896, y1:0.494136, x2:1, y2:1, stop:0 rgba(0, 0, 0, 255), stop:1 rgba(255, 255, 255, 255));
	border:1px groove rgb(232, 232, 232);
	border-radius:20;
}

Main中调用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include "luothread.h"
#include "LuoProgressDialog.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    //进度条
    LuoProgressDialog luoPro;
    //线程
    LuoThread luoThread;
    //信号槽绑定
    QObject::connect(&luoThread, SIGNAL(SetPos(int)), &luoPro, SLOT(SetPos(int)));
    //启动线程
    luoThread.start();
    //显示对话框
    luoPro.exec();
    
    return a.exec();
}
QDialog.7z

Qt菜单

Widget创建菜单:

  1. 添加菜单
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
LuoWidget::LuoWidget(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	//插入菜单栏
	QMenuBar* m = new QMenuBar(this);

    //设置菜单栏大小
	m->resize(width(), m->height());

	//一级菜单
	QMenu* m1 = m->addMenu(QStringLiteral("菜单1"));

	//二级菜单
	QAction* a1 = m1->addAction(QStringLiteral("二级菜单1.1"));
	QAction* a2 = m1->addAction(QStringLiteral("二级菜单1.2"));
	QAction* a3 = m1->addAction(QStringLiteral("二级菜单1.3"));
	//设置图标
	a3->setIcon(QIcon(":/LuoMenu/ke nan.png"));

	//三级菜单
	QMenu* m14 = m1->addMenu(QStringLiteral("二级菜单1.4"));
	m14->addAction(QStringLiteral("三级菜单1.4.1"));
	//设置图标
	m14->setIcon(QIcon(":/LuoMenu/ke nan.png"));

	//一级菜单
	QMenu* m2 = m->addMenu(QStringLiteral("菜单2"));
	QMenu* m3 = m->addMenu(QStringLiteral("菜单3"));
}
  1. 事件信号
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//QMenuBar
void hovered(QAction *action);
void triggered(QAction *action);

//QMenu
void hovered(QAction *action);
void triggered(QAction *action);

//QAction
void changed();
void hovered();
void toggled(bool checked);
void triggered(bool checked = false);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//槽函数
public slots:
	void Hover()
	{
		qDebug() << "Hover";
	}
	void Action1()
	{
		qDebug() << "Action1";
	}
	void Action(QAction* act)
	{
		qDebug() << "Action " << act->text();
	}

//进行绑定
//一级菜单
m1 = m->addMenu(QStringLiteral("菜单1"));
//QMenu所有子节点(子节点的子节点)点击后,都会触发该信号
connect(m1, SIGNAL(triggered(QAction*)), this, SLOT(Action(QAction*)));

//二级菜单
QAction* a1 = m1->addAction(QStringLiteral("二级菜单1.1"));
//QAction 触发信号
connect(a1, SIGNAL(triggered()), this, SLOT(Action1()));

QAction* a2 = m1->addAction(QStringLiteral("二级菜单1.2"));
//QAction 鼠标悬停信号
connect(a2, SIGNAL(hovered()), this, SLOT(Hover()));
  1. 动态产生菜单
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
//槽函数
void Hovered(QAction* act) 
{
	//动态菜单
	if (act->text() == QStringLiteral("菜单3"))
	{
		act->menu()->clear();
		act->menu()->addAction(QStringLiteral("菜单3.1"));
		act->menu()->addAction(QStringLiteral("菜单3.2"));
		act->menu()->addAction(QStringLiteral("菜单3.3"));
	}
}

//信号槽绑定
//插入菜单栏
QMenuBar* m = new QMenuBar(this);
//悬停,动态菜单生成
connect(m, SIGNAL(hovered(QAction*)), this, SLOT(Hovered(QAction*)));
  1. 菜单单选和多选
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//槽函数
void Action1(bool b)
{
	qDebug() << "Action1 " << b;
}

//二级菜单
QAction* a1 = m1->addAction(QStringLiteral("二级菜单1.1"));
QAction* a2 = m1->addAction(QStringLiteral("二级菜单1.2"));
QAction* a3 = m1->addAction(QStringLiteral("二级菜单1.3"));

//设置可选
a1->setCheckable(true);
a2->setCheckable(true);
a3->setCheckable(true);

//添加到组
QActionGroup* ag = new QActionGroup(this);
ag->addAction(a2);
ag->addAction(a3);
//单选
ag->setExclusive(true);
//是否选中
connect(a1, SIGNAL(triggered(bool)), this, SLOT(Action1(bool)));
//添加快捷键
a1->setShortcut(QString("A"));
  1. 按钮菜单
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
//准备一个按钮,响应点击事件
//按钮点击事件
void Click() 
{
	//鼠标位置显示菜单
    //m1的类型是QMenu
	m1->exec(QCursor::pos());
}

QMenuBar* m = new QMenuBar(this);
//设置菜单栏大小
m->resize(width(), m->height());
//一级菜单
m1 = m->addMenu(QStringLiteral("菜单1"));

//二级菜单
QAction* a1 = m1->addAction(QStringLiteral("二级菜单1.1"));
QAction* a2 = m1->addAction(QStringLiteral("二级菜单1.2"));
QAction* a3 = m1->addAction(QStringLiteral("二级菜单1.3"));
//三级菜单
QMenu* m14 = m1->addMenu(QStringLiteral("二级菜单1.4"));
m14->addAction(QStringLiteral("三级菜单1.4.1"));

按钮菜单

点击按钮的时候,就会弹出菜单.

  1. 工具栏
1
2
3
4
5
6
#include <QToolBar>

QToolBar* tBar = new QToolBar(this);
tBar->setGeometry(0, m->height(), width(), 30);
tBar->setIconSize(QSize(30, 30));
tBar->addAction(a1);

工具栏

  1. 状态栏
1
2
3
4
5
#include <QStatusBar>

QStatusBar* sBar = new QStatusBar(this);
sBar->setGeometry(0, height() - 30, width(), 30);
sBar->showMessage(QStringLiteral("测试消息3秒消失!"), 3000);

状态栏

QMainWindow:

QMainWindow继承QWidget,封装了很多操作.

1
2
3
4
5
6
7
QMainWindow
  
├─QMenuBar
  └─QMenu
     └─QAction
├─QToolBar
└─QStatusBar

菜单栏:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//一级菜单
QMenu* m1 = this->menuBar()->addMenu(QStringLiteral("菜单1"));
//二级菜单
QAction* a11 = m1->addAction(QStringLiteral("菜单1.1"));
QAction* a12 = m1->addAction(QStringLiteral("菜单1.2"));
QAction* a13 = m1->addAction(QStringLiteral("菜单1.3"));

//添加图标
a12->setIcon(QIcon(":/LuoMenu/ke nan.png"));

//一级菜单
QMenu* m2 = this->menuBar()->addMenu(QStringLiteral("菜单2"));
QMenu* m3 = this->menuBar()->addMenu(QStringLiteral("菜单3"));

工具栏:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
ui.mainToolBar->addAction(a11);
ui.mainToolBar->addAction(a12);
ui.mainToolBar->addAction(a13);

//设置ToolBar样式, 文件名显示在图标下面
ui.mainToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);

//工具栏换行
this->addToolBarBreak();

//默认顶部插入工具栏
//可调用下面的重载函数,调整插入位置
//void addToolBar(Qt::ToolBarArea area, QToolBar * toolbar)
QToolBar* tBar2 = this->addToolBar("toolBar2");
tBar2->addAction(QStringLiteral("顶部"));

状态栏:

1
this->statusBar()->showMessage("Status Bar");
Qt菜单.7z

Qt事件

重载Qt事件有2种方式:

  • 重载event这个虚函数,在里面判断event的类型,
  • 重载各自的事件虚函数(如 keyPressEvent).
  1. QEvent

重载事件:

1
virtual bool event(QEvent *event) override;

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//声明
public:
    //重载event
    bool event(QEvent* ev);

//实现
bool LuoEvent::event(QEvent* ev)
{
	switch (ev->type())
	{
	case QEvent::KeyPress: {
		//键盘事件
		//推荐重载keyPressEvent或keyReleaseEvent
		QKeyEvent* keyEv = (QKeyEvent*)ev;
		//判断是否是自动触发的
		if (!keyEv->isAutoRepeat())
		{
			//这个输出的是大写
			qDebug() << (char)keyEv->key();
			//这个可以区分大小写
			qDebug() << keyEv->text();

			if (keyEv->key() == 'A')
			{
                //返回true表示已被处理
				return true;
			}
		}
	}
	case QEvent::MouseButtonPress: {
		//鼠标事件
		QMouseEvent* me = (QMouseEvent*)ev;
		//相对坐标(本地坐标)
		qDebug() << "QEvent::MouseButtonPress "
			<< QStringLiteral("相对坐标 ")
			<< me->x()
			<< me->y();
		//程序窗口坐标
		qDebug() << "QEvent::MouseButtonPress "
			<< QStringLiteral("程序窗口坐标 ")
			<< me->windowPos().x()
			<< me->windowPos().y();
		//屏幕坐标
		qDebug() << "QEvent::MouseButtonPress "
			<< QStringLiteral("屏幕坐标 ")
			<< me->screenPos().x()
			<< me->screenPos().y();

		//本地坐标转屏幕坐标
		QPoint gPos = mapToGlobal(me->pos());
		qDebug() << "QEvent::MouseButtonPress "
			<< QStringLiteral("本地坐标转屏幕坐标 ")
			<< gPos.x()
			<< gPos.y();

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

		//鼠标按钮事件
		if (me->buttons() & Qt::LeftButton)
		{
			qDebug() << "LeftButton";
		}
		if (me->buttons() & Qt::RightButton)
		{
			qDebug() << "RightButton";
		}
		if (me->buttons() & Qt::MiddleButton)
		{
			qDebug() << "MiddleButton";
		}
	}
    case QEvent::Resize: {
		//窗口大小改变事件
		QResizeEvent* re = (QResizeEvent*)ev;
		qDebug() << "Resize Old " << re->oldSize()
			<< "Resize New " << re->size();
	}
	default:
		break;
	}

	return QWidget::event(ev);
}
  1. 键盘事件

重载事件:

1
2
virtual void keyPressEvent(QKeyEvent *event);
virtual void keyReleaseEvent(QKeyEvent *event);

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//声明
public:
    //键盘事件
    void keyPressEvent(QKeyEvent* ev);
    void keyReleaseEvent(QKeyEvent* ev);

//实现
void LuoEvent::keyPressEvent(QKeyEvent* ev)
{
	//键盘按下某个按键后,会多次响应
	//解决键盘按钮连发现象,判断是否是自动触发的,若是则返回
	if (ev->isAutoRepeat())
	{
		return;
	}

	qDebug() << "keyPressEvent " << ev->key();
}

void LuoEvent::keyReleaseEvent(QKeyEvent* ev)
{
	if (ev->isAutoRepeat())
	{
		return;
	}
	qDebug() << "keyReleaseEvent " << ev->key();
}
  1. 鼠标事件

重载事件:

1
2
3
4
5
6
7
8
9
//鼠标移进来
virtual void enterEvent(QEvent *event);
//鼠标移出去
virtual void leaveEvent(QEvent *event);
virtual void mouseDoubleClickEvent(QMouseEvent *event);
//鼠标移动事件,需要开启鼠标跟踪,setMouseTracking(true)
virtual void mouseMoveEvent(QMouseEvent *event);
virtual void mousePressEvent(QMouseEvent *event);
virtual void mouseReleaseEvent(QMouseEvent *event);

坐标:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//相对坐标(本地坐标)
//相对于Widget的位置
int QMouseEvent::x() const;
int QMouseEvent::y() const;
//程序窗口坐标
//相对于程序窗口的位置
const QPointF &QMouseEvent::windowPos() const;
//屏幕坐标
//相对于屏幕的位置
const QPointF &QMouseEvent::screenPos() const;

//本地坐标转屏幕坐标
QPoint mapToGlobal(const QPoint &pos) const;
//获取鼠标的屏幕坐标
[static] QPoint QCursor::pos();

按键:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//获取按键状态,鼠标的哪个键被按下
Qt::MouseButtons QMouseEvent::buttons() const;
enum MouseButton {
        NoButton         = 0x00000000,
        LeftButton       = 0x00000001,
        RightButton      = 0x00000002,
        MidButton        = 0x00000004, // ### Qt 6: remove me
        MiddleButton     = MidButton,
        ...
    };
  1. 窗口大小改变

可重载该事件来解决不同电脑屏幕分辨率不同,而导致的控件显示异常的现象.

重载事件:

1
virtual void resizeEvent(QResizeEvent *event);

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//声明
public:
    //窗口大小改变事件
    void resizeEvent(QResizeEvent* re);

//实现
void LuoEvent::resizeEvent(QResizeEvent* re)
{
	qDebug() << "resizeEvent";

	//窗口改变前的大小
	//re->oldSize()
	//窗口改变后的大小
	//re->size()
}
Qt事件.7z

QPainter

重载事件:

1
virtual void paintEvent(QPaintEvent *event);

绘制文本:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//声明
public:
//重载这个虚函数
    void paintEvent(QPaintEvent* event);

//实现
void LuoPaint::paintEvent(QPaintEvent* event)
{
    //设置绘制设备 (Widget)
    QPainter p(this);

    //设置画笔颜色
    p.setPen(QColor(255, 0, 0, 200));

    //设置字体
    //p.setFont(QFont(QStringLiteral("黑体"), 30));
    //这样设置之后,我们在字体选中控件中选择字体后,界面的绘制的字体没有改变
    //我们需要调用update这个槽函数,来刷新界面
    QFont font = ui.fontComboBox->currentFont();
    font.setPixelSize(30);
    p.setFont(font);

    //绘制文本
    p.drawText(100, 100, QStringLiteral("测试文字"));
}
注意
我们通过字体选择控件选择字体后,需要调update这个槽函数来刷新界面.

字体选择控件绑定槽函数

绘制线:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//声明
public:
//重载这个虚函数
    void paintEvent(QPaintEvent* event);

//实现
void LuoPaint::paintEvent(QPaintEvent* event)
{
    //设置绘制设备 (Widget)
    QPainter p(this);

    //绘制线
    //设置画笔样式
    QPen pen;
    //实线
    pen.setStyle(Qt::SolidLine);
    //线粗
    pen.setWidth(30);
    //线刷子
    pen.setBrush(Qt::red);

    //结尾端样式
    pen.setCapStyle(Qt::RoundCap);

    //连接处样式
    pen.setJoinStyle(Qt::RoundJoin);

    p.setPen(pen);

    QVector<QLine> lines;
    lines.push_back(QLine(0, 0, 350, 350));
    lines.push_back(QLine(350, 350, 0, 450));
    lines.push_back(QLine(0, 450, 550, 550));
    p.drawLines(lines);

    p.end();
}

Qt配置

VS2019dark.xml
  1. 将上述黑色方案放到Qt目录\Tools\QtCreator\share\qtcreator\styles.
  2. 在QtCreator中工具->选项->环境->theme,选择dark.
  3. 在QtCreator中工具->选项->文本编辑器,选择VS2019.

控制台:

方便调试,看输出信息.

QtCreator:

Qt开启控制台

VS:

VS控制台

VS番茄插件设置:

VSQt代码提示

环境变量:

添加环境变量: Qt_INCLUDEPATH_ = D:\QT\5.12.10\msvc2017_64\include

Qt环境变量

按上述设置后,可解决某些情况下在VS中写Qt代码不提示,工程标红等现象.

VS工程标红:

  1. 右键.ui文件,编译.
  2. 右键解决方案,重新扫描解决方案.

Qss

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//声明
public slots:
	//设置皮肤样式
	static void SetStyle(const QString& styleName);

//实现
void luoQt::SetStyle(const QString& styleName)
{
	QFile file(QString("./image/%1.qss").arg(styleName));
	bool b = file.open(QFile::ReadOnly);
	QString qss = QLatin1String(file.readAll());
	qApp->setStyleSheet(qss);
	qApp->setPalette(QPalette(QColor("#F0F0F0")));
}
Qss.7z

Qt程序打包

将Qt程序单独放到一个文件夹中,cmd到该文件夹,执行下面的命令.

1
windeployqt 程序名

相关内容

0%