Qt入门教程系列之三 第一个Qt项目:记事本 您所在的位置:网站首页 notepad源码 Qt入门教程系列之三 第一个Qt项目:记事本

Qt入门教程系列之三 第一个Qt项目:记事本

2023-07-27 03:40| 来源: 网络整理| 查看: 265

一、成果演示

这就是我们的记事本

看完这篇博客可能还有许多不懂,不过别急,我后面还会更新博客来讲Qt。你可以先百度来解决自己的问题。 

二、编写记事本

所有新增的代码都应该自己敲一遍。不懂的,可以先略过。C++要是不懂,先补补C++。

创建项目Notpad

notepad.pro - 项目文件

main.cpp - 主文件

notepad.cpp - Notepad主界面的源码

notepad.h - Notepad主界面的头文件

notepad.ui - Notepad 的UI文件

main.cpp #include "notepad.h" #include int main(int argc, char *argv[]) { /** * @brief a QApplication对象 * 管理Qt应用的资源,每个使用了Widget的应用都需要QApplication的对象 */ QApplication a(argc, argv); /** * @brief w Notepad 的对象 * Notepad也是一个Widget */ Notepad w; // 显示Notepad的界面 w.show(); // 进入应用的事件循环,当程序在运行时,事件(键盘点击、鼠标点击等很多事件)会发送到 // 本应用的所有Widget,比如在本应用中,事件就会发送给w。 return a.exec(); } notepad.ui

notepad.ui是定义用户界面的文件,实际上是一个XML文件。它包含了有什么控件、控件的位置、控件之间的所属关系等等。当构建(编译)项目时,编译程序会调用“Qt User Interface Compiler (uic)”来把notepad.ui编译为一个C++头文件ui_notepad.h;ui_notepad.h包含了有什么控件、控件的位置、控件之间的所属关系等等。

双击notepad.ui,会进入UI编辑器界面。截取出我们感兴趣的部分,如下,左右同种颜色的框一一对应

 Notepad类继承QMainWindow,一个QMainWindow包含菜单栏(menuBar)、工具栏(mainToolBar)、状态栏(statsuBar)和centralWidget(可用来放入其他控件,中文不知如何翻译)。

添加Text Edit控件。

控件的周围会出现8个深蓝色小方块,把鼠标移动到这些方块上,并拖动,就可以改变控件的大小。界面如下图所示

点击运行,程序的界面如下

 

 设计菜单项。双击UI中的“在这里输入”,在输入框中输入“文件”,敲回车。然后同理,再双击后面的“在这里输入”,输入“编辑”,

得到如下界面

 点击“文件”或者“编辑”,会出现一个下拉菜单,点击下拉菜单中中的“在这里输入”,就可以输入子菜单项。“文件”应该包含的子菜单项为“新建”、“打开”、“保存”、“另存为”;“编辑”应当包含的子菜单项为“粘贴”、“重做”、“撤销”。添加子菜单的时候,我发现不能输入中文,目前的解决方案是在别的地方输入中文,然后复制粘贴进去。添加完子菜单之后,界面如下

 红色框内就是控件之间的关系。Notepad包含centralWidget、menuBar、mainToolBar和statusBar;centralWidget包含一个textEdit;menuBar包含menu和menu_2;依次类推。双击红色框内控件的名字,可以更改控件的名字。控件名应该代表这个控件的作用,而不应该是action、action_2、action_3这样无意义的控件名。改完控件名之后,如下图所示

红色框内是Action Editor(我翻译为动作编辑器) ,每一行为一个Action,也就是一个子菜单项。双击一行中的任意一个位置,会打开一个Action的属性窗口如下

点击一下红色框内的输入框,按下组合键,输入框里面就会出现你刚才按下的组合键。这个组合键就是这个Action的快捷键。修改所有Action的组合键,修改完成后如下图所示;每完成一步都要按Ctrl+S保存!

 此时在编译运行程序,菜单已经已经有了。但是,这时候点击菜单,是没有任何反应的。

notepad.h

下面就是notepad.h的定义,添加了详细的注释。在Qt中,按住Ctrl,然后再点击宏或者类名,就会转到宏或者类的定义;点击变量名的时候,会转到变量的定义;点击函数名的时候,会在函数定义(函数声明)和函数实现之间来回跳转。

#ifndef NOTEPAD_H #define NOTEPAD_H #include namespace Ui { class Notepad;//这个类是ui_notepad.h中的UI界面类,和下面的Notepad不是同一个类 } class Notepad : public QMainWindow { /** * 每个UI相关的类(或者其他继承自QObject的类)都需要有下面这一行。 * Q_OBJECT是一个宏,暂且不需要了解是什么。 */ Q_OBJECT public: /** * @brief Notepad 构造函数。 * 这个Notepad类是应用的功能实现,上面的Ui::Notepad是一个定义UI的类。 * @param parent 父类指针 */ explicit Notepad(QWidget *parent = 0); ~Notepad(); private: // 界面指针 Ui::Notepad *ui; }; #endif // NOTEPAD_H

Qt的信号(signal)和槽(slot)机制简述 。Qt中代替回调函数的机制叫做信号槽,继承自QObject类(Qt库中,很多类都直接或者间接继承自QObject类),都可以有信号和槽。信号和槽都是一个函数,信号只有函数名,没有实现;槽是一个完整的函数,可执行某种功能。信号和槽的参数需要相同;一个信号可以通过connect函数和多个槽相连。当信号被触发时,槽函数会执行,所以,槽函数也可以理解为回调函数;有多个槽函数时,当信号被触发,会按照与信号相连的顺序顺序执行。

在Qt中的类中,定义信号和槽的关键字分别为signals和slots,具体示例如下

#ifndef NOTEPAD_H #define NOTEPAD_H #include namespace Ui { class Notepad;//这个类是ui_notepad.h中的UI界面类,和下面的Notepad不是同一个类 } class Notepad : public QMainWindow { /** * 每个UI相关的类(或者其他继承自QObject的类)都需要有下面这一行。 * Q_OBJECT是一个宏,暂且不需要了解是什么。 */ Q_OBJECT public: /** * @brief Notepad 构造函数。 * 这个Notepad类是应用的功能实现,上面的Ui::Notepad是一个定义UI的类。 * @param parent 父类指针 */ explicit Notepad(QWidget *parent = 0); ~Notepad(); private: // 界面指针 Ui::Notepad *ui; signals: //信号 void opened(); public slots: //公有槽定义区,可关联其他类中信号 void onActionNewTriggered(bool checked); //新建 void onActionOpenTriggered(bool checked);//打开 void onActionSaveTriggered(bool checked);//保存 void onActionSaveasTriggered(bool checked);//另存为 void onActionPasteTriggered(bool checked);//粘贴 void onActionUndoTriggered(bool checked);//撤销 void onActionRedoTriggered(bool checked);//重做 private slots: //私有槽定义区,只能关联本类中的信号 void onEdited(); }; #endif // NOTEPAD_H

需要的注意的是,不管公由槽还是私有槽,都需要实现,否则编译通不过。 

notepad.cpp

按住Ctrl键,鼠标左键点击“explicit Notepad(QWidget *parent = 0)”中的“Notepad”,就会跳转到notepad.cpp中“explicit Notepad(QWidget *parent = 0)”的实现,如下

#include "notepad.h" #include "ui_notepad.h" Notepad::Notepad(QWidget *parent) : QMainWindow(parent), ui(new Ui::Notepad) //实例化ui { ui->setupUi(this);//把ui和本类关联起来,ui中的事件什么的就可以发送到本类 } Notepad::~Notepad() { delete ui; }

把信号和槽相连。信号和槽相连需要使用connect函数,connect有四个参数,第一个参数是sender的指针,第二个参数是sender的一个信号,第三个参数是receiver的指针,第四个参数是receiver的槽。

#include "notepad.h" #include "ui_notepad.h" Notepad::Notepad(QWidget *parent) : QMainWindow(parent), ui(new Ui::Notepad) //实例化ui { ui->setupUi(this);//把ui和本类关联起来,ui中的事件什么的就可以发送到本类 // 当actionNew的信号triggered被触发时,也就是被点击时,槽onActionNewTriggered会被调用 this->connect(ui->actionNew, //sender SIGNAL(triggered(bool)),//sender的信号 this,//receiver SLOT(onActionNewTriggered(bool)));//receiver的槽 // 连接剩下的信号与槽 this->connect(ui->actionOpen,SIGNAL(triggered(bool)),this,SLOT(onActionOpenTriggered(bool))); connect(ui->actionSave,SIGNAL(triggered(bool)),this,SLOT(onActionSaveTriggered(bool))); connect(ui->actionSaveas,SIGNAL(triggered(bool)),this,SLOT(onActionSaveasTriggered(bool))); connect(ui->actionPaste,SIGNAL(triggered(bool)),this,SLOT(onActionPasteTriggered(bool))); connect(ui->actionRedo,SIGNAL(triggered(bool)),this,SLOT(onActionRedoTriggered(bool))); connect(ui->actionUndo,SIGNAL(triggered(bool)),this,SLOT(onActionUndoTriggered(bool))); } Notepad::~Notepad() { delete ui; }

完成上面的代码之后,菜单项发出的信号就能和Notepad类的槽关联起来了。当对应的菜单项被点击时,对应的槽就会被执行。但是槽函数并没有实现,所此时编译无法通过。

转到notepad.h中,左键单击一个槽函数的名字,比如“onActionNewTriggered”,然后Alt+Enter键,会弹出一个菜单,然后在菜单中选择"在notepad.cpp"中添加定义,此时,编辑器会跳转notepad.cpp中,并添加以下代码

void Notepad::onActionNewTriggered(bool checked) { }

在上面的槽中添加一行输出Debug信息的代码

void Notepad::onActionNewTriggered(bool checked) { //输出函数名和checked的值,qDebug()需要包含头文件QDebug qDebug()actionPaste,SIGNAL(triggered(bool)),this,SLOT(onActionPasteTriggered(bool))); connect(ui->actionRedo,SIGNAL(triggered(bool)),this,SLOT(onActionRedoTriggered(bool))); connect(ui->actionUndo,SIGNAL(triggered(bool)),this,SLOT(onActionUndoTriggered(bool))); } Notepad::~Notepad() { delete ui; } void Notepad::onActionNewTriggered(bool checked) { //输出函数名和checked的值 qDebug()


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有