Qt学习笔记

Qt学习笔记

Qt教程,Qt5编程入门教程(非常详细) (biancheng.net)

B站视频:最新QT从入门到实战完整版——传智教育

Qt帮助文档路径:E:\Qt\Qt5.9.9\5.9.9\mingw53_32\bin assistant.exe

1.1 分析第一个Qt程序

main.cpp:与C++程序固定格式一致

#include "IFT_platform_for_C_program.h"
#include 
//main中定义了QApplication,IFT_platform_for_C_program类的对象,因此引入QApplication和IFT_platform_for_C_program.h头文件
int main(int argc, char *argv[])
{
    //a为应用程序对象,有且仅有一个
    QApplication a(argc, argv);
    //窗口对象,IFT_platform_for_C_program父类->Qweight
    IFT_platform_for_C_program w;
    //默认情况下,Qt提供的所有组件都是隐藏的,调用窗口类的show()方法即可显示w窗口
    w.show();
    //使应用程序对象进入消息循环机制
    //让代码阻塞到这一行
    return a.exec();
}

IFT_platform_for_C_program.h和IFT_platform_for_C_program.cpp

//IFT_platform_for_C_program.h
#include 
#include "ui_IFT_platform_for_C_program.h"

//继承自QMainWindow窗口类
//初始状态下IFT_platform_for_C_program类由Q——OBJECT、构造函数和析构函数组成
class IFT_platform_for_C_program : public QMainWindow
{
    //Q_OBJECT宏,允许类种使用信号和槽的机制
    Q_OBJECT
public:
    //构造函数:QWidget是所有组件的基类,借助parent指针,可以为当前窗口指定父窗口
    IFT_platform_for_C_program(QWidget *parent = Q_NULLPTR);
private:
    Ui::IFT_platform_for_C_programClass ui;
};
//IFT_platform_for_C_program.cpp
#include "IFT_platform_for_C_program.h"
IFT_platform_for_C_program::IFT_platform_for_C_program(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
}

命名规范:

  • 类名:首字母大写、单词单词之间首字母大写
  • 函数名:变量名称首字母小写,单词和单词之间首字母大写

问题:中文乱码

出现中文乱码问题的解决方案:要用到中文字符的头文件和源文件开头加上MSVC的一个宏。

#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif

1.2 Qt QPushButton按钮

  • 头文件:#include < QPushButton>
  • QPushButton 类,间接继承自 QWidget 类,继承关系:QPushButton -> QAbstractButton -> QWidget

在IFT_platform_for_C_program.cpp中进行创建按钮:

#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
#include "IFT_platform_for_C_program.h"
#include  

IFT_platform_for_C_program::IFT_platform_for_C_program(QWidget* parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    //创建第一个按钮,构造函数:QPushButton(const QString &text, QWidget *parent = Q_NULLPTR)
    //parent指针指向this当前窗口,也可通过btn->setParent(this)指定,btn->setText()设置文字
    QPushButton* btn = new QPushButton("第一个按钮", this);
    //创建第二个按钮
    QPushButton* btn2 = new QPushButton("第二个按钮", this);
    //移动第二个按钮:btn2->mov
    btn2->move(100, 100);
    //重新设置第二个按钮大小
    btn2->resize(50, 50);
    //重置窗口大小
    resize(600, 400);
    //设置固定窗口大小
    setFixedSize(600, 400);
    //设置窗口标题
    setWindowTitle("设置第一个窗口大小");
}

运行效果:
Qt学习笔记_第1张图片

对象模型(对象树)

在Qt中创建对象时会提供一个Parent对象指针,下面解释这个Parent指针到底是干什么的。

  • QObject是以对象树的形式组织的,创建QObject派生下的对象时,构造函数接受一个QObject类型的指针作为参数,这个参数就是parent,即父对象指针,创建的对象会自动添加到其父对象的children()列表
  • 父对象析构时,这个列表中的所有对象都会被析构,如一个按钮被析构,其快捷方式也会被析构。无需管理其释放操作,对象会放入对象树中,简化了内存回收机制。

添加自定义的Qt类——MyPushButton

右键项目名称->添加->Add Qt Class->Qt Widgets Class,填写Class Name,Base class处没有QPushButton,填写默认QWidgt。
Qt学习笔记_第2张图片
查看新增的mypushbutton.cpp与bypushbutton.h

//MyPushButton.h
#pragma once
//修改1 #include ->#include 
#include 
#include "ui_mypushbutton.h"
//修改2 class MyPushButton : public QWidget->public QPushButton
class MyPushButton : public QPushButton
{
	Q_OBJECT

public:
	//构造函数和析构函数
	MyPushButton(QWidget *parent = Q_NULLPTR);
	~MyPushButton();

private:
	Ui::MyPushButton ui;
};


//MyPushButton.cpp
#include "MyPushButton.h"
//QDebug模块观察构造函数与析构函数的调用情况
#include 
//修改1 QWidget(parent)->QPushButton(parent)
MyPushButton::MyPushButton(QWidget *parent)
	: QPushButton(parent)
{
	ui.setupUi(this);
    qDebug() << "我的按钮类构造调用";
}
MyPushButton::~MyPushButton()
{
    qDebug() << "我的按钮类析构调用";
}
//IFT_platform_for_C_program.cpp: 
//添加头文件
#include "mypushbutton.h"

//创建一个自己的按钮的对象
    MyPushButton* myBtn = new MyPushButton;
    myBtn->setText("我自己的按钮");
    myBtn->move(200, 0);
    myBtn->setParent(this);//设置对象树中

运行:可以看到成功创建了新的按钮,且消息栏中提示构造函数与析构函数被调用
在这里插入图片描述在这里插入图片描述
myBtn->setParent(this);将myBtn设置在对象树中,关闭主窗口,myBtn也被析构。此外,局部对象的实际析构顺序是创建顺序的反顺。

Qt的窗口坐标系

左上角(0,0),X向右增加,Y向下增加。

1.3 信号槽机制

信号和槽:点击按钮关闭窗口

  • 信号和槽是 Qt 特有的消息传输机制,它能将相互独立的控件关联起来。
  • Qt用户与控件的每次交互都是一个事件,每个事件都会发出一个信号,每个控件都可以接收信号并相应,对信号做出的响应动作就称为槽。
  • 信号槽的优点:松散耦合,发送端与接收端本身无关联,通过connect连接将两端耦合。

关联某个信号函数和槽函数,需要搞清楚以下 4 个问题:

  • 信号发送者是谁?——>按钮
  • 哪个是信号函数?——>点击 clicked()
  • 信号的接收者是谁?——>窗口
  • 哪个是接收信号的槽函数?——>关闭窗口close()

Qt5 版本中,connect() 函数的语法格式是:

QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)

connect() 函数指定信号函数和槽函数的语法格式是**&函数所在类::函数名**,信号和槽查找signal和slot

//IFT_platform_for_C_program.cpp:  
//需求,点击我自己的按钮,关闭窗口
connect(myBtn, &QPushButton::clicked, this, &QWidget::close);

自定义的信号和槽

新建项目Widget

自定义功能:下课后,老师->饿了->学生->请客

首先定义Teacher,Student两个类,将其设为QObject类型。

设置信号函数:自定义信号写到signals下,无返回值有参数,只需声明无需实现。

//teacher.h声明
#pragma once
#include 
class Teacher : public QObject
{
	Q_OBJECT
signals:
	//自定义信号,写到signals下
	//没有返回值void,只需要声明不需要实现
	//可以有参数,可以重载
	void hungry();

public:
	Teacher(QObject *parent);
	~Teacher();
};

设置槽函数:写在Public或全局下,无返回值有参数,既需声明又需实现

//student.h声明
#pragma once
#include 
class Student : public QObject
{
	Q_OBJECT
public:
	//槽函数,写在public下,或全局下
	//返回值void,需要声明也需要实现
	//可以有参数,可重载
	void treat();
	
	Student(QObject *parent);
	~Student();
};
//student.c实现
#include "student.h"
#incldue 
void Student::treat()
{
	qDebug() << "请老师吃饭";
}

创建老师、学生对象,connect连接信号槽

//Widget.h
#pragma once
#include 
#include "ui_Widget.h"
//头文件
#include "teacher.h"
#include "student.h"
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = Q_NULLPTR);

private:
    Ui::WidgetClass ui;
    //定义Teacher类、Student类的对象指针
    Teacher* t;
    Student* s;
    //定义触发函数
    void classIsOver();
};

创建老师学生对象并连接,设置下课函数,emit触发饿了信号

//Witget.c
#include "Widget.h"

//Teacher类
//Student类
//场景,下课后老师触发信号->饿了,学生响应->请客吃饭

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    //创建老师对象,学生对象
    this->t = new Teacher(this);
    this->s = new Student(this);
    //连接:老师饿了,学生请客
    connect(t, &Teacher::hungry, s, &Student::treat);
    //调用下课
    classIsOver();
}
void Widget::classIsOver()
{
    //下课函数,调用后触发老师饿了的信号,emit触发
    emit t->hungry();
}

运行后:
在这里插入图片描述
可以看到classIsOver函数被调用后,触发信号槽,学生执行qDebug,输出字符串。

自定义信号和槽重载的解决

对hungry()和treat()函数重载:带参数foodName

//teacher.h
void hungry(QString foodName);

//student.h
void treat(QString foodName);
//student.cpp
void Student::treat(QString foodName)
{
	qDebug() << "请老师吃饭,老师要吃" << foodName;
}

//Widget.cpp
Widget::Widget(QWidget *parent) : QWidget(parent)
{
    //指针->地址 函数指针->函数地址  !!!重载后,设置函数指针使connect区分原函数与重载函数!!!
    //定义函数指针需要添加作用域
    void(Teacher:: * teacherSignal)(QString) = &Teacher::hungry;
    void(Student:: * studentSlot)(QString) = &Student::treat;
    connect(t, teacherSignal, s, studentSlot);
    classIsOver();
}

void Widget::classIsOver()
{
    //下课函数,调用后触发老师重载后带参数的饿了信号,emit触发
    emit t->hungry("宫保鸡丁");
}

运行后可以看到成功调用了重载函数,传输了参数foodName:
在这里插入图片描述
这里有一个问题,输出的foodName加了引号,将QString转化成cahr *类型可以去掉引号

//Qstring->char *,先转成QByteArray(.toUtf8),查看帮助文档QByteArray通过data()转成cahr*
qDebug() << "请老师吃饭,老师要吃" << foodName.toUtf8().data();

在这里插入图片描述

信号连接信号

需求:添加一个按钮,点击按钮触发下课,触发老师饿了

//widget.cpp
    //点击下课按钮,再触发下课
    QPushButton* btn = new QPushButton("下课",this);
    this -> resize(600, 400);
    connect(btn, &QPushButton::clicked, this, &Widget::classIsOver);

Qt学习笔记_第3张图片
继续尝试调用无参信号和槽,同时去除classIsOver,直接信号连接信号:下课按钮->hungry

//widget.cpp
	//无参信号和槽
    void(Teacher:: * teacherSignal2)(void) = &Teacher::hungry;
    void(Student:: * studentSlot2)(void) = &Student::treat;
    connect(t, teacherSignal2, s, studentSlot2);
    
    //点击按钮,触发信号,信号连接信号
    connect(btn, &QPushButton::clicked, t,teacherSignal2);

在这里插入图片描述
断开信号连接:disconnect();

扩展:

  • 信号可以连接信号
  • 一个信号可以连接多个槽函数
  • 多个信号可以连接一个槽函数
  • 信号和槽函数的参数必须 类型 一一对应
  • 信号的参数个数可以 多于 槽函数的参数个数

分析信号和槽函数的参数必须类型一一对应:前文信号连接信号时间,将clicked信号与hungry(void)连接无异常,但将其与hungry(QString)连接报错,这是因为clicked的函数原型有一个bool型参数,只能与无参hungry连接,要与有参hungry连接,需要经过classIsOver()

void clicked(bool checked = false)

1.4 Lamada表达式(待补充)

看不懂,得看一下C++再写,弹幕说可以简化代码结构,有些场景无需重新定义。

//widget.cpp
    //用lamada表达式实现点击按钮关闭窗口,使用参槽函数无需调用classIsOver
    QPushButton* btn2 = new QPushButton("关闭",this);
    btn2->move(100, 0);
    connect(btn2, &QPushButton::clicked, this, [=]() {
        this->close();
        emit t->hungry("宫保鸡丁");

练习01

两个按钮:open,close,点击open弹出一个窗口,点击close,关闭窗口。

  • 创建MyWindow类
  • 在Widget.h与Widget.cpp添加头文件#include “mywindow.h”
  • 设置槽函数
//Widget.h
#pragma once
#include 
#include "ui_Widget.h"
#include "mywindow.h"//头文件
class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = Q_NULLPTR);
    void open_new_win();//槽函数:打开窗口
    void close_new_win();//槽函数:关闭窗口

private:
    Ui::WidgetClass ui;
    MyWindow *new_win;//声明Window类对象指针
};
  • 实现槽函数,设置button并连接信号槽
//Widget.cpp
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
#include "Widget.h"
#include 
#include "mywindow.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    QPushButton* btn1 = new QPushButton("open", this);
    connect(btn1, &QPushButton::clicked, this, &Widget::open_new_win);//打开窗口
    QPushButton* btn2 = new QPushButton("close", this);
    btn2->move(100, 0);
    connect(btn2, &QPushButton::clicked, this, &Widget::close_new_win);//关闭窗口
}


void Widget::open_new_win() {
    this->new_win = new MyWindow();//构造函数,构造窗口
    new_win->show();//显示窗口
}
void Widget::close_new_win() {
    new_win->close();//关闭窗口
}

一个按钮:初始为open,点击open弹出窗口,变为close;点击close关闭窗口,变为open。

  • 其余实现不变,将两个按钮置于同一个位置,初始隐藏btn2
  • 添加信号槽,点击open时,btn1隐藏,btn2出现;点击close时,btn2隐藏,btn1出现
//Widget.cpp
    QPushButton* btn1 = new QPushButton("open", this);
    QPushButton* btn2 = new QPushButton("close", this);
    btn2->hide();//初始状态btn2隐藏
    connect(btn1, &QPushButton::clicked, this, [=]() {
        open_new_win();
        btn1->hide();
        btn2->show();
        });
    connect(btn2, &QPushButton::clicked, this, [=]() {
        close_new_win();
        btn2->hide();
        btn1->show();
        });

2.1 QMainWindow

菜单栏和工具栏

QMainWindow是一个为用户提供主窗口程序的类,包含一个菜单栏(menu bar)、多个工具栏(tool bars)、多个铆接部件(dock widgets)、一个状态栏(status bar)以及一个中心部件(central widgets),是许多应用程序的基础,如文本编辑器、图片编辑器等。

新建Qt项目,类型选择QMainWindow

#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
#include "My_window.h"
#include 
#include 
#include 
#include 

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

    //重置窗口大小
    resize(600, 400);
    
    //--------------------菜单栏 最多只能有一个-----------------------------
    //创建菜单栏
    QMenuBar* bar = menuBar();
    //菜单栏放入窗口中
    setMenuBar(bar);
      
    //创建菜单:QMenu接收
    QMenu *fileMenu = bar->addMenu("文件");
    QMenu* editMenu = bar->addMenu("编辑");
    
    //创建菜单项:QAction接收
    QAction *newAction = fileMenu->addAction("新建");
    //添加分割线
    fileMenu->addSeparator();
    QAction *openAction = fileMenu->addAction("打开");

    //---------------------工具栏 可以有多个-------------------------------
    QToolBar* toolbar = new QToolBar(this);//挂在对象树上
    //设置工具栏默认停靠区域
    addToolBar(Qt::LeftToolBarArea,toolbar);
      
    //后期设置:只允许左右停靠
    toolbar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
    //设置浮动
    toolbar->setFloatable(false);
    //设置移动(总开关)
    toolbar->setMovable(false);

    //创建工具项,和菜单项共用QAction
    toolbar->addAction(newAction);
    //添加分割线
    toolbar->addSeparator();
    toolbar->addAction(openAction);

    //工具栏中添加控件,如QPushButton
    QPushButton* btn = new QPushButton("aa",this);
    toolbar->addWidget(btn);
}

效果如下:点击【文件】菜单,出现【新建】、【打开】菜单项
Qt学习笔记_第4张图片

状态栏、铆接部件、核心部件

#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
#include "My_window.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

My_window::My_window(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
	...
    //----------------------------状态栏 最多有一个---------------------------
    QStatusBar* stBar = statusBar();
    //设置到窗口中
    setStatusBar(stBar);
    //添加标签控件
    QLabel* label = new QLabel("提示信息", this);
    stBar->addWidget(label);
    QLabel* label2 = new QLabel("右侧提示信息", this);
    stBar->addPermanentWidget(label2);

    //----------------------铆接部件(浮动窗口) 可以有多个--------------------
    QDockWidget* dockwidget = new QDockWidget("浮动",this);
    addDockWidget(Qt::BottomDockWidgetArea, dockwidget);
    //设置后期停靠区域:只允许上下停靠
    dockwidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);

    //---------------------------中心部件 只有一个----------------------------
    QTextEdit* edit = new QTextEdit(this);
    setCentralWidget(edit);   
}

效果如下:【浮动】窗口可以独立与主窗口。
Qt学习笔记_第5张图片

小结一下

  • 只能有一个的——菜单栏、状态栏、核心部件:set

    //菜单栏
    QMenuBar* bar = menuBar();
    setMenuBar(bar);
    //状态栏
    QStatusBar* stBar = statusBar();
    setStatusBar(stBar);
    //核心部件
    QTextEdit* edit = new QTextEdit(this);
    setCentralWidget(edit);  
    
  • 可以有多个——工具栏、铆接部件:add//工具栏 可以有多个

    //工具栏
    QToolBar* toolbar = new QToolBar(this);//挂在对象树上
    addToolBar(Qt::LeftToolBarArea,toolbar);
    //铆接部件(浮动窗口)
    QDockWidget* dockwidget = new QDockWidget("浮动",this);
    addDockWidget(Qt::BottomDockWidgetArea, dockwidget);
    

2.2 资源文件添加

打开.ui进行界面设计,通过简单拖拽实现2.1中界面
Qt学习笔记_第6张图片
保存后,返回VS界面,右键.ui文件点击编译,可以看到成功运行。

接下为设计添加资源文件:为QAction类型的新建添加icon图标

//My_window.cpp 
ui.actionnew->setIcon(QIcon("C:/Users/lenovo/Desktop/Qt学习/test.png"));

编译运行可以看到成功添加了图标:
Qt学习笔记_第7张图片
接下来需要将本地资源上传工程,才能实现其他用户正常读取。

工程下新建Image文件夹->将图标文件导入->点击工程目录.qrc->Add添加文件->添加后双击图片查看Resource URL->推出后编译.qrc,此时成功导入。Qt添加资源格式: ":+前缀名+文件名"

//My_window.cpp
//使用Qt添加资源 ":+前缀名+文件名"
ui.actionnew->setIcon(QIcon(":/My_window/Image/test.PNG"));
ui.actionfile->setIcon(QIcon(":/My_window/Image/test.PNG"));

可以看到成功导入了icon:
Qt学习笔记_第8张图片

2.3 对话框

模态和非模态对话框创建

//My_window.cpp
My_window::My_window(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    //点击新建按钮弹出对话框
    connect(ui.actionnew, &QAction::triggered, [=]() {
        //对话框有两种分类:模态、非模态
        //模态:不可以对其他窗口操作
        //非模态:可以对其他窗口操作

        //模态创建
        /*QDialog dlg(this);
        dlg.resize(400, 200);
        dlg.exec();//阻塞
        qDebug() << "模态对话框弹出来";*/

        //非模态创建
        QDialog *dlg2 = new QDialog(this);
        dlg2->resize(400, 200);
        dlg2->show();
        dlg2->setAttribute(Qt::WA_DeleteOnClose);//55号属性 关闭即释放对象
        qDebug() << "非模态对话框弹出来";
        });
}

分类:

  • 模态(不可以对其他窗口操作):QDialog dlg(this);dlg.exec();
  • 非模态(可以对其他窗口操作):QDialog *dlg2 = new QDialog(this);dlg2->show();

注意

  • exec()实现了对模态窗口的阻塞,使得无法操作其他窗口。
  • 对于非模态窗口,show()正常显示会造成一闪而过,因此将其new到堆区,此外为了防止内存泄漏,setAttribute()设置属性关闭即释放

Qt内置对话框:消息对话框

Qt内置对话框:选择颜色(QCloloeDialog)、选择文件目录(QFileDialog)、选择字体(QFontDialog)、用户输入值返回(QInputDialog)、模态对话框(QMessageBox)等。

静态成员函数的访问:通过类名直接调用、创建对象访问。

Qt助手搜索QMessageBox,查看静态成员函数Static Public Members,通过静态成员函数创建对话框。
Qt学习笔记_第9张图片

//My_window.cpp  消息对话框QMessageBox
#include 
...
        //错误对话框
        QMessageBox::critical(this, "critial", "错误");
        //信息对话框
        QMessageBox::information(this, "info", "信息");
        //问题对话框
        //参数4:选项类型,跟进question->StandardButtons查看可选参数  参数5:默认关联回车的按键
        if (QMessageBox::Save == QMessageBox::question(this, "ques", "提问", QMessageBox::Save | QMessageBox::Cancel, QMessageBox::Cancel)) {
            qDebug() << "选择的是保存";
        }
        else {
            qDebug() << "选择的是取消";
        }
        //警告对话框
        QMessageBox::warning(this, "warning", "警告");

效果如下:
Qt学习笔记_第10张图片
每一类对话框对应不同图标:

  • 错误(critical)、信息(information)、问题(question)、警告(warning)
  • 参数1:父亲 参数2:标题 参数3:显示内容 参数4:按键类型 参数5:默认关联回车按键
  • 问题(question)对话框:返回值为StandardButton类型,用来捕获用户的选择

Qt内置对话框:其他对话框

颜色对话框

  • 返回值是选择的颜色QColor
//颜色对话框
QColor color = QColorDialog::getColor(QColor(255, 0, 0), this, "color");
qDebug() << "r = " << color.red() << "g = " << color.green() << "b = " << color.blue();

Qt学习笔记_第11张图片
文件对话框

  • 参数1:父亲 参数2:标题 参数3:默认打开路径 参数4:过滤文件类型
  • 返回值是选取的路径QString
//文件对话框
QString str = QFileDialog::getOpenFileName(this, "打开文件", "E:\Qtprojcets\code\02My_window", "(*.txt)");
qDebug() << "目标路径: " << str;

Qt学习笔记_第12张图片
字体对话框

  • 返回值是字体格式QFont
//字体对话框
bool flag;
QFont font = QFontDialog::getFont(&flag, QFont("宋体", 36), this, "字体选择");
qDebug() << "字体:" << font.family() << " 字号:" << font.pointSize() << " 是否加粗:" << font.bold() << " 是否倾斜:" << font.italic();

Qt学习笔记_第13张图片

2.4 登录窗口布局

用户名:Label;输入框:Line Edit;登录/取消:Push Button

对界面布局

水平对齐:

  • Horizontal Layout,将控件用户名与输入框拖拽进去,不太灵活(不推荐)
  • Widget,将控件用户名与输入框拖拽进去,上侧水平布局

垂直布局:

  • 对整个MainWidget窗口布局,点击上方垂直布局
    Qt学习笔记_第14张图片
    调节登录/取消按钮大小:

  • Horizontal Spacer:水平弹簧,在登录左侧,取消右侧,登录/取消之间添加弹簧

  • 设置登录/取消之间的弹簧大小固定,sizeType->fixed,宽度->30
    Qt学习笔记_第15张图片
    用户名/密码布局:距过远,对话框未对齐

  • 打破布局,删除弹簧和Widget

  • 添加Widget,将要素拖拽进去,选择上方栅格布局

  • 对整个MainWidget窗口垂直布局

  • 在用户名/密码左右两侧添加弹簧

  • 去除Widget上下边缘间隙,选择Widget,sizePolicy,垂直策略->fixed

  • 去除Wigdget窗口与弹簧间隙,选择Widget,Layout,layoutLeftMaegin->0

  • 密码输入框不显示:echoMode->password

主窗口大小:设置不可拖拽

  • 设置minimumSize与maximumSize相同

最终效果如下:
Qt学习笔记_第16张图片

2.5 控件

按钮组

  • QPushButton 常用按钮
  • QToolButton 工具按钮:用于显示图片,凸起风格autoRaise,文字按钮同时显示,ToolButtonStyle->ToolButtonTextBesideIcon,
  • radioButton 单选按钮 设置默认值:ui.radioButton->setChecked(true);
  • checkBox 多选按钮 监听状态:0未选 1半选 2选中
    Qt学习笔记_第17张图片
//My_window.cpp
//单选按钮
//设置默认值
ui.radioButton->setChecked(true);
//获取选择结果,选中后触发信息,可以使用一个bool值接收选择
connect(ui.radioButton, &QRadioButton::clicked, [=]() {
    qDebug() << "选择radioButton1";});

//多选按钮,选中state=2,未选中state=0,半选state=1
connect(ui.checkBox_3, &QCheckBox::stateChanged, [=](int state) {
    qDebug() << state;});

QListWidget控件

  • QListWidgetItem * item;一行内容
  • ui.listWidget->addItem(item);添加一行内容
  • item->setTextAlignment(Qt::AlignHCenter);设置居中方式
  • addItems一次添加多行内容,输入参数类型为QStringList
    Qt学习笔记_第18张图片
//My_window.cpp
//利用listWidget写诗,listWidget每行都是一个QListWidgetItem
QListWidgetItem* item = new QListWidgetItem("锄禾日当午");
ui.listWidget->addItem(item);
//设置水平居中
item->setTextAlignment(Qt::AlignHCenter);

//QStringList QList
QStringList list;
list << "锄禾日当午" << "汗滴禾下土" << "谁知盘中餐" << "粒粒皆辛苦";
ui.listWidget->addItems(list);

QTreeWidget树控件

  • 设置头:ui.treeWidget->setHeaderLabels(QStringList()<<“英雄”<<“英雄介绍”);

  • 设置根:QTreeWidgetItem* item1 = new QTreeWidgetItem(QStringList() << “力量”);

    添加根到树控件:ui.treeWidget->addTopLevelItem(item1);

  • 追加子节点:item1->addChild(item11);
    Qt学习笔记_第19张图片

//My_window.cpp Tree Widget控件使用
//设置头
ui.treeWidget->setHeaderLabels(QStringList()<<"英雄"<<"英雄介绍");

//设置根节点
QTreeWidgetItem* item1 = new QTreeWidgetItem(QStringList() << "力量");
QTreeWidgetItem* item2 = new QTreeWidgetItem(QStringList() << "敏捷");
QTreeWidgetItem* item3 = new QTreeWidgetItem(QStringList() << "智力");
//加载顶层节点
ui.treeWidget->addTopLevelItem(item1);
ui.treeWidget->addTopLevelItem(item2);
ui.treeWidget->addTopLevelItem(item3);

//为根节点追加子节点
QTreeWidgetItem* item11 = new QTreeWidgetItem(QStringList()<< "猪八戒" << "前排坦克,能在吸收伤害的同时造成可观的范围输出");
item1->addChild(item11);

Table Widget控件

  • 设置列数:ui.tableWidget->setColumnCount(3);
  • 设置水平表头:ui.tableWidget->setHorizontalHeaderLabels(QStringList() << “姓名” << “性别” << “年龄”);
  • 设置行数:ui.tableWidget->setRowCount(5);
  • 设置正文:ui.tableWidget->setItem(0, 0, new QTableWidgetItem(“亚瑟”));
    Qt学习笔记_第20张图片
//My_window.cpp Table Widget控件使用
//设置列数
ui.tableWidget->setColumnCount(3);
//设置水平表头
ui.tableWidget->setHorizontalHeaderLabels(QStringList() << "姓名" << "性别" << "年龄");
//设置行数
ui.tableWidget->setRowCount(5);
//设置正文,0行0列
ui.tableWidget->setItem(0, 0, new QTableWidgetItem("亚瑟"));

QStringList nameList;
nameList << "亚瑟" << "赵云" << "张飞" << "曹操" << "妲己";
QList sexList;
sexList << "男" << "男" << "男" << "男" << "女";
for (int i = 0; i < 5; i++) {
    int col = 0;
    ui.tableWidget->setItem(i, col++, new QTableWidgetItem(nameList[i]));
    ui.tableWidget->setItem(i, col++, new QTableWidgetItem(sexList.at(i)));
    //int转QString
    ui.tableWidget->setItem(i, col++, new QTableWidgetItem(QString::number(i+18)));
}

其他控件

  • GroupBox:分组,单选多选Button时使用

  • Scroll Area:滚动区域

  • Tool Box:类似QQ好友分组列表

  • Tab Widget:类似浏览器网页切换

  • Stacked Widget:窗口切换,需要通过PushButton设置信号槽切换,ui.stackedWidget->setCurrentIndex(0);

  • Widget:设置对齐

  • DockWidget:浮动窗口

  • ComboBox:下拉框,ui.comboBox->addItems();

  • Line Edit:单行输入框,可修改输入模式(密码)

  • Text Edit:可编辑的文本框,类似记事本

  • Label:标签,可显示文本/图片/动图,ui.label->setPixmap(“图片”);

    显示动图:QMovie* movie = new QMovie(“动图”);ui.label_2->setMovie(movie);movie->start();

    Qt学习笔记_第21张图片

//My_window.cpp 其他控件
//栈控件使用
//设置默认到Scroll Area
ui.stackedWidget->setCurrentIndex(0);
//Scroll Area按钮
connect(ui.btn_scrollArea, &QPushButton::clicked, [=]() {
    ui.stackedWidget->setCurrentIndex(0);
    });
//Tool Box按钮
connect(ui.btn_toolBox, &QPushButton::clicked, [=]() {
    ui.stackedWidget->setCurrentIndex(2);
    });
//Tab Widget按钮
connect(ui.btn_tabWidget, &QPushButton::clicked, [=]() {
    ui.stackedWidget->setCurrentIndex(1);
    });

//comnoBox下拉菜单
ui.comboBox->addItems(QStringList() << "奔驰" << "宝马" << "拖拉机");
//点击按钮选中拖拉机
connect(ui.btn_select, &QPushButton::clicked, [=]() {
    ui.comboBox->setCurrentIndex(2);
    //ui.comboBox->setCurrentText("拖拉机");
    });
//QLabel标签
//利用QLabel显示图片
ui.label->setPixmap(QPixmap(":/My_window/Image/test.PNG"));
//利用QLabel显示gif动图
QMovie* movie = new QMovie(":/My_window/Image/test.PNG");
ui.label_2->setMovie(movie);
//播放动图
movie->start();

3.1 自定义控件封装

封装Spin Box和Horizontal Slider控件

添加设计器界面类:添加->add Qt Class->Qt Widgets Class->命名smallwidget即可。

  • 在smallwidget.ui中拖拽控件,生成所需的组合控件
  • 在主窗口拖拽Widget控件,右侧选中控件->右键->提升为->添加->输入提升的类名称:smallwidget->添加->提升。可以看到此时右侧控件类型由Widget变为smallwidget。
    Qt学习笔记_第22张图片
    设置QSpinBox与QSlider同步移动:
//smallwidget.cpp
//QSpinBox移动 QSlider跟着移动
void(QSpinBox::* spSignal)(int) = &QSpinBox::valueChanged;//发生重载定义函数指针
connect(ui.spinBox, spSignal, ui.horizontalSlider, &QSlider::setValue);

//QSlider滑动 QSpingBox数字跟着改变
connect(ui.horizontalSlider, &QSlider::valueChanged, ui.spinBox, &QSpinBox::setValue);

新增两个button:获取当前值、设置到一半

//smallwidget.h
//设置数字
void setNum(int num);
//获取数字
int getNum();
//smallwidget.cpp 函数实现
void smallwidget::setNum(int num){
	ui.spinBox->setValue(num);
}

int smallwidget::getNum(){
	return ui.spinBox->value();
}
//My_widget.cpp
//点击获取当前值 获取控件当前值
connect(ui.btn_get, &QPushButton::clicked, [=]() {
    qDebug() << ui.widget->getNum();
    });
//点击设置到一半 设置到一般
connect(ui.btn_set, &QPushButton::clicked, [=]() {
    ui.widget->setNum(50);
    });

运行效果如下:点击设置到一般均变为50,点击获取当前值打印当前值。
Qt学习笔记_第23张图片

问题:添加设计器界面类编译显示无法打开头文件

!!!问题:运行报错无法打开包含文件"smallwidget.h"

!!!解决方案:双击错误跳转到ui_My_window.h,修改头文件,将尖括号改为双引号

//#include 
#include "smallwidget.h"

问题:点击新建的.ui文件秒退

右键.ui文件->打开方式->添加->路径为Qt安装路径下的bin/designer.exe->自定义名称->设为默认值

3.2 Qt中的鼠标事件

鼠标进入和离开

[virtual protected] void QWidget::enterEvent(QEvent *event)//鼠标进入事件
[virtual protected] void QWidget::leaveEvent(QEvent *event)//鼠标离开事件

新建类myLabel,无需界面选择Qt Class即可,设置基类为QWedget

//mylabel.h
//鼠标进入事件
void enterEvent(QEvent* event);
//鼠标离开事件
void leaveEvent(QEvent* event);
//mylabel.cpp
//鼠标进入事件
void myLabel::enterEvent(QEvent* event) {
	qDebug() << "鼠标进入了";
}
//鼠标离开事件
void myLabel::leaveEvent(QEvent* event) {
	qDebug() << "鼠标离开了";
}

因为要将QLabel升级为myLabel,二者类型需要一致,因此修改myLabel中的QWidget为QLabel(三处)

//mylabel.h
#include 
class myLabel : public QLabel
//mylabel.cpp
myLabel::myLabel(QWidget *parent) : QLabel(parent)

升级QLabel为mylabel,方法与3.1中相同。

修改后运行程序:可以看到成功捕捉鼠标事件
Qt学习笔记_第24张图片

鼠标按下、释放、移动

QLabel中的其他鼠标事件:帮助QLabel->Reimplemented Protected Functions(重新实现保护函数)

//QLabel->Reimplemented Protected Functions中与鼠标相关的事件
virtual void mouseMoveEvent(QMouseEvent *ev)
virtual void mousePressEvent(QMouseEvent *ev)
virtual void mouseReleaseEvent(QMouseEvent *ev)

在头文件中声明:

//mylabel.h
//鼠标按下事件
void mousePressEvent(QMouseEvent* event);
//鼠标释放事件
void mouseReleaseEvent(QMouseEvent* event);
//鼠标移动事件
void mouseMoveEvent(QMouseEvent* event);

在.cpp文件中实现:

  • 判断按下的鼠标键为左/右键:if (event->button() == Qt::LeftButton)

  • 下示代码鼠标移动事件move需要点击鼠标键才能开始捕获,若需直接捕获,在构造函数中声明

    //mylabel.cpp 设置鼠标追踪
    setMouseTracking(true);
    
  • move比较特殊:if (event->buttons() & Qt::LeftButton)

  • 坐标:event->x(),event->y() 全局坐标:event->global_X(),event->global_Y()

  • Qt格式化字符串输出:QString(“x=%1 y=%2”).arg(1),arg(2);

//mylabel.cpp
//鼠标按下事件
void myLabel::mousePressEvent(QMouseEvent* event) {
	//鼠标左键按下时,输出
	if (event->button() == Qt::LeftButton) {
		QString str = QString("鼠标按下了 x = %1 y=%2 globle_x=%3 globle_y=%4").arg(event->x()).arg(event->y()).arg(event->globalX()).arg(event->globalY());
		qDebug() << str;
	}
}
//鼠标释放事件
void myLabel::mouseReleaseEvent(QMouseEvent* event) {
	//鼠标左键按下时,输出
	if (event->button() == Qt::LeftButton) {
		QString str = QString("鼠标释放了 x = %1 y=%2 globle_x=%3 globle_y=%4").arg(event->x()).arg(event->y()).arg(event->globalX()).arg(event->globalY());
		qDebug() << str;
	}
}

//鼠标移动事件
void myLabel::mouseMoveEvent(QMouseEvent* event) {
	//鼠标左键按下时,输出
	if (event->buttons() & Qt::LeftButton) {
		QString str = QString("鼠标移动了 x = %1 y=%2 globle_x=%3 globle_y=%4").arg(event->x()).arg(event->y()).arg(event->globalX()).arg(event->globalY());
		qDebug() << str;
	}
}

运行结果如下:
Qt学习笔记_第25张图片

3.3 定时器

定时器1——事件

  • 利用事件:void timerEvent(QTimerEvent* e);
  • 启动定时器:startTimer(1000);单位是毫秒(ms)
  • startTimer返回值是定时器的唯一标识,可以与e->timerID比较
  • int->QString:QString::number(int num)

定时器事件:

[virtual protected] void QTimer::timerEvent(QTimerEvent *e)

实现两个文本框分别计时,一个间隔1s计数,另一个间隔2s计数。

//My_window.h
//重写定时器事件
void timerEvent(QTimerEvent* e);
int id1;//定时器1的唯一标识
int id2;//定时器2的唯一标识
//My_window.cpp
#include "My_window.h"
#include 

My_window::My_window(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    //启动定时器 参数1:间隔 单位ms
    id1 = startTimer(1000);
    id2 = startTimer(2000);
}

void My_window::timerEvent(QTimerEvent* e) {
    if (e->timerId() == id1) {
        static int num = 1;
        //label_2每个1s加1
        ui.label_2->setText(QString::number(num++));
    }
    if (e->timerId() == id2) {
        //label_3每隔2s加1
        static int num2 = 1;
        ui.label_3->setText(QString::number(num2++));
    }
}

定时器2——定时器类QTimer(推荐)

  • 利用定时器类QTimer,创建定时器类QTimer* timer = new QTimer(this);
  • 启动定时器:timer->start(500); 暂停定时器:timer->stop();
  • 每个一定间隔,定时器发送信号:&QTimer::timeout,进行监听实现所需逻辑
  • timer->isActive()判断定时器是否处于启动状态,启动状态返回true

实现定时器间隔0.5s计数,点击btn计数停止,再次点击恢复计数。

//定时器第二种实现方式
QTimer* timer = new QTimer(this);
//启动定时器
timer->start(500);
connect(timer, &QTimer::timeout, [=]() {
    static int num3 = 1;
    ui.label_4->setText(QString::number(num3++));
    });
//点击btn停止定时,再次点击恢复
connect(ui.btn, &QPushButton::clicked, [=]() {
    if (timer->isActive())timer->stop();
    else timer->start();
    });

效果如下:
Qt学习笔记_第26张图片

3.4 事件分发器与过滤器

Qt学习笔记_第27张图片

event事件分发器

  • event事件分发器用途:事件分发,也可以做事件拦截(如下例),但不建议
  • bool event(QEvent *e);返回值为true时拦截,Type用于判断事件类型
  • 类型转化QEvent->QMouseEvent:QMouseEvent* event = static_cast(e);
//事件分发器
//返回值为true时,代表用户要处理这个事件,不向下分发,起到了过滤作用
[virtual] bool QObject::event(QEvent *e)

拦截鼠标按下事件

//通过事件分发器拦截鼠标按下事件
//mylabel.h
bool event(QEvent* e);

//mylabel.cpp
bool myLabel::event(QEvent* e) {
	//如果鼠标按下,在event事件分发中做拦截操作
	if (e->type() == QEvent::MouseButtonPress) {
		//将event从QEvent*转为QMouseEvent* 
		QMouseEvent* event = static_cast(e);
		QString str = QString("Events函数中:鼠标按下了 x = %1 y=%2 globle_x=%3 globle_y=%4").arg(event->x()).arg(event->y()).arg(event->globalX()).arg(event->globalY());
		qDebug() << str;
		return true;//trued代表用户自行处理这个事件,不向下分发
	}
	else return QLabel::event(e);
}

效果如下:可以看到成功拦截了鼠标按下事件,其他事件正常分发。
Qt学习笔记_第28张图片

event事件过滤器

  • 在程序将事件分发到事件分发器前,可以利用过滤器拦截

  • 实现步骤1:给控件安装事件过滤器ui.label->installEventFilter(this);

    实现步骤2:重写事件过滤器事件bool eventFilter(QObject* obj, QEvent* e);

  • 重写eventfilter时:obj判断控件类型,event.type()判断控件操作类型

//事件过滤器:可以在程序分发到event事件之前再进行一次高级拦截
//使用:1、给控件安装事件过滤器;2、重写eventfilter事件
[virtual] bool QObject::eventFilter(QObject *watched, QEvent *event)

过滤鼠标按下事件:

//通过事件过滤器过滤鼠标按下事件
//My_window.h
//步骤2:重写事件过滤器事件
bool eventFilter(QObject* obj, QEvent* e);

//My_window.cpp
My_window::My_window(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    //步骤1:给label1安装事件过滤器
    ui.label->installEventFilter(this);
}
//步骤2:重写eventfilter事件
bool My_window::eventFilter(QObject* obj, QEvent* e) {
    if (obj == ui.label) {
        if (e->type() == QEvent::MouseButtonPress) {
            QMouseEvent* event = static_cast(e);
            QString str = QString("事件过滤器中:鼠标按下了 x = %1 y=%2 globle_x=%3 globle_y=%4").arg(event->x()).arg(event->y()).arg(event->globalX()).arg(event->globalY());
            qDebug() << str;
            return true;
        }
        else return false;
    }
    else {
        return QWidget::eventFilter(obj, e);
    }
}

效果如下:可以看到成功过滤了鼠标按下事件,其他事件正常分发。
Qt学习笔记_第29张图片

3.5 绘图相关

绘图事件

  • 绘图事件:void paintEvent(QPaintEvent*);
  • 画线、椭圆、矩形、文字
  • 设置画笔QPen,设置画笔颜色、宽度、风格
  • 设置画刷QBrush,设置画刷颜色、风格
//My_window.h
//绘图事件
void paintEvent(QPaintEvent*);

//My_window.cpp
#include //画家类
void My_window::paintEvent(QPaintEvent*) {
    //实例化画家对象 this->指定绘图设备
    QPainter painter(this);

    //设置画笔
    QPen pen(QColor(255, 0, 0));
    //设置画笔宽度,默认1
    pen.setWidth(5);
    //设置画笔风格,默认:Qt::SolidLine
    pen.setStyle(Qt::DotLine);
    //画家使用画笔
    painter.setPen(pen);

    //设置画刷:封闭图形填充颜色
    QBrush brush(Qt::cyan);
    //设置画刷风格,默认:Qt::SolidPattern
    brush.setStyle(Qt::Dense7Pattern);
    //让画家使用画刷
    painter.setBrush(brush);
    //设置画刷风格,默认:Qt::SolidPattern


    //画直线
    painter.drawLine(QPoint(0, 0), QPoint(100, 100));
    //画(椭)圆
    painter.drawEllipse(QPoint(100, 100), 100, 50);
    //画矩形
    painter.drawRect(QRect(20, 20, 50, 50));
    //画文字
    painter.drawText(QRect(10, 200, 200, 100),"好好学习天天向上");
}

效果如下:
Qt学习笔记_第30张图片

绘图高级设置

  • 抗锯齿,效率低:painter.setRenderHint(QPainter::Antialiasing);
  • 移动画家:painter.translate(100, 0);
  • 保存画家状态:painte.save(); 还原画家状态:painter.restore();
//My_window.cpp
void My_window::paintEvent(QPaintEvent*) {
    //实例化画家对象 this->指定绘图设备
    QPainter painter(this);
    painter.drawEllipse(QPoint(100, 100), 50, 50);
    //设置 抗锯齿能力 效率较低
    painter.setRenderHint(QPainter::Antialiasing);
    painter.drawEllipse(QPoint(250, 100), 50, 50);
}

效果如下:可以看到右侧圆轮廓更清晰
Qt学习笔记_第31张图片

//My_window.cpp
void My_window::paintEvent(QPaintEvent*) {
    //实例化画家对象 this->指定绘图设备
    QPainter painter(this);
    painter.drawRect(QRect(20,20,50,50));
    //移动画家1
    painter.translate(100, 0);
    //保存画家状态
    painter.save();
    painter.drawRect(QRect(20, 20, 50, 50));
    //移动画家2
    painter.translate(100, 0);
    //还原画家状态
    painter.restore();
    painter.drawRect(QRect(20, 20, 50, 50));
}

效果如下:上示代码绘制了三个矩形,第一次移动画家,使得第一二矩形不重合,第二次移动后还原画家状态,导致第三个矩形和第二个矩形重合。
Qt学习笔记_第32张图片

手动调用绘图事件

  • 利用QPainter绘制图片:painter.drawPixmap(pos_X, 0, QPixmap("*.png"));
  • 手动调用绘图事件:update();

利用画家绘制图片,设置按钮,点击按钮图片右移,移动到窗口最右侧后返回

//My_window.h
int pos_X = 0;

//My_window.cpp
#include //画家类
#include 
My_window::My_window(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    //点击移动按钮,移动图片
    connect(ui.pushButton, &QPushButton::clicked, [=]() {
        //如果要手动调用绘图时间,用updata更新
        update();
        });
}

void My_window::paintEvent(QPaintEvent*) {
    //实例化画家对象 this->指定绘图设备
    QPainter painter(this);
    if (pos_X > this->width()) {
        pos_X = 0;
    }
    pos_X += 3;
    painter.drawPixmap(pos_X, 0, QPixmap(":/My_window/Image/test.PNG"));
}

效果如下:
Qt学习笔记_第33张图片

作业:定时器控制图片自动右移
//My_window.cpp
#include //画家类
#include 
My_window::My_window(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    QTimer* timer = new QTimer(this);
    timer->start(500);
    connect(timer, &QTimer::timeout, [=]() {
        update();
        });
}

void My_window::paintEvent(QPaintEvent*) {
    //实例化画家对象 this->指定绘图设备
    QPainter painter(this);
    if (pos_X > this->width()) {
        pos_X = 0;
    }
    pos_X += 20;
    painter.drawPixmap(pos_X, 0, QPixmap(":/My_window/Image/test.PNG"));
}

绘图设备

  • QPaintDeviceQ:Pixmap、QBitmap(黑白色)、QImage、QPicture、QWidget
  • Pixmap:对不同平台做了显示的优化
    • 创建绘图设备QPixmap pix(300, 300);
    • 填充背景颜色:pix.fill(Qt::white);
    • 声明画家向pix上绘图:QPainter painter(&pix);
    • 保存到磁盘:pix.save(“E:\pix.png”);
  • QImage:可以对像素进行访问
    • 创建绘图设备:QImage img(300, 300, QImage::Format_RGB32);
    • 其他与Pixmap类似
    • 修改像素点:QRgb value = qRgb(255, 0, 0);img.setPixel(i, j, value);
  • QPicture:记录和重现绘图指令
    • 开始记录指令:painter.begin(&pic); 结束记录指令painter.end();
    • 保存绘图指令:pic.save("*.自定义后缀");
    • 重现绘图指令:pic.load("*.自定义后缀");painter.drawPicture(0, 0, pic);

Pixmap绘图设备:专门为平台做了显示优化

//My_window.cpp 
QPixmap pix(300, 300);
//填充颜色
pix.fill(Qt::white);
//声明画家
QPainter painter(&pix);
painter.setPen(QPen(Qt::green));
painter.drawEllipse(QPoint(150, 150), 100, 100);
//保存
pix.save("E:\\pix.png");

QImage绘图设备:可以对像素进行访问

//My_window.cpp 
QImage img(300, 300, QImage::Format_RGB32);
img.fill(Qt::white);
QPainter painter(&img);
painter.setPen(QPen(Qt::blue));
painter.drawEllipse(QPoint(150, 150), 100, 100);
img.save("E:\\img.png");

效果如下:
Qt学习笔记_第34张图片

//My_window.h
//public声明绘图事件
void paintEvent(QPaintEvent *);

//My_window.cpp
void My_window::paintEvent(QPaintEvent*) {
    QPainter painter(this);

    //利用QImage对像素进行修改
    QImage img;
    img.load(":/My_window/Image/test.PNG");
    //修改像素点
    for (int i = 50; i < 100; i++) {
        for (int j = 50; j < 100; j++) {
            QRgb value = qRgb(255, 0, 0);
            img.setPixel(i, j, value);
        }
    }
    painter.drawImage(0, 0, img);
}

效果如下:
Qt学习笔记_第35张图片
QPicter绘图设备:可以记录和重现绘图指令

//My_window.cpp
QPicture pic;
QPainter painter;
painter.begin(&pic);//开始在pic上画图
painter.setPen(QPen(Qt::cyan));
painter.drawEllipse(QPoint(150, 150), 100, 100);
painter.end();//结束画图

//记录绘图指令,后缀名可自定义
pic.save("E:\\pic.txt");

void My_window::paintEvent(QPaintEvent*) {
    //重现绘图指令
    QPicture pic;
    pic.load("E:\\pic.txt");
    QPainter painter(this);
    painter.drawPicture(0, 0, pic);
}

效果如下:
Qt学习笔记_第36张图片

3.6 QFile文件相关

QFile文件读写操作

  • QFile进行文件读写操作,文件路径:QFile file(path);

  • 设置打开方式,只读:file.open(QIODevice::ReadOnly);

  • 全部读取:file.readAll(); 按行读:file.readLine();判断是否读到尾file.atEnd()

  • 指定编码格式(默认utf-8):

    QTextCodec* codec = QTextCodec::codecForName(“utf-8”);

    ui.textEdit->setText(codec->toUnicode(array));

  • 关闭文件:file.close();

  • 追加方式写:file.open(QIODevice::Append);file.write("");

点击pushButton弹出文件选择对话框,将文件路径放在lineEdit中,文本内容放在textEdit中。

//My_window.cpp
#include "My_window.h"
#include 
#include 
#include 
#include 
#include 
My_window::My_window(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    //点击文件选择按钮
    connect(ui.pushButton, &QPushButton::clicked, [=]() {
        //弹出对话框
        QString path = QFileDialog::getOpenFileName(this, "选择文件", "E:/QFile");
        //将路径放在lineEdit中
        ui.lineEdit->setText(path);

        //编码格式类:用来对读取内容类型转化
        QTextCodec* codec = QTextCodec::codecForName("utf-8");
        //读取内容放在textEdit中
        QFile file(path);//参数即为读取的文件的路径
        //设置打开方式:只读,默认格式:utf-8
        file.open(QIODevice::ReadOnly);
        QByteArray array;
        while (!file.atEnd()){
            array += file.readLine();//按行读
        }
        //array = file.readAll();//全部读
        ui.textEdit->setText(codec->toUnicode(array));
        file.close();

        //写文件
        file.open(QIODevice::Append);//以追加的方式写
        file.write("aaaaaaaaaaa");
        file.close();
        });
}

效果如下:
Qt学习笔记_第37张图片
查看读取的文件:可以看到文件末尾被添加了预设内容
Qt学习笔记_第38张图片

QFileInfo文件信息读取

  • QFileInfo info(path);
  • 文件大小:info.size();后缀名:info.suffix();名称:info.fileName();路径:info.filePath()
  • 文件创建时间:info.created();最后修改时间:info.lastModified()
  • QDateTime转换为QString:info.lastModified().toString(“yyyy-MM-dd hh:mm:ss”);
//My_window.cpp
#include 
#include 
QFileInfo info(path);
qDebug() << "文件大小:" << info.size() << "文件后缀名:" << info.suffix() << "文件名称:" << info.fileName() << "文件路径:" << info.filePath();
qDebug() << "创建日期:" << info.created().toString("yyyy/MM/dd hh:mm:ss");
qDebug() << "最后修改日期:" << info.lastModified().toString("yyyy-MM-dd hh:mm:ss");

读取结果如下:
在这里插入图片描述

总结

2022-1-19到2022-1-29,比较认真看的时间应该有三四天,课程入门友好型,内容比较基础。
纪念一下第一次看完B站的视频教程,后面考虑完成一下课程后附加的项目实现和额外的一两个项目实现。

(详细记录视频的进度可以有效提高效率,减少摸鱼

你可能感兴趣的:(Qt,qt,ui,开发语言)