C++ QT入门1——记事本基础功能实现(基本控件布局+信号与槽+文件类操作)

C++ QT入门1——记事本基础功能实现(基本控件布局+信号与槽+文件类操作)

  • 一、UI界面的基础设置
    • 样式表通用配置
    • 通过样式表设置按钮三态
    • 以图片作为按钮背景
  • 二、按键响应——☆信号与槽
    • 信号与槽基本概念
    • 按键QPushButton设置信号与槽
    • 自定义信号与槽
    • 自定义信号与槽的实际应用——页面的跳转
  • 三、文件类操作QFile
    • 文件的直接读写
    • 通过文件流读写数据
    • QFileDialog 文件选择框
      • 打开文件
      • 创建 / 保存文件
  • 四、记事本基本功能整合
    • 行编辑器与文本编辑器
    • 文件的打开
    • 文件的保存
    • 关闭按钮的实现

一、UI界面的基础设置

  关于UI界面的设计与美化须通过不断熟悉与操作,具体可参考:白月黑羽-页面设计与布局 系列教程进行实操锻炼。

样式表通用配置

font-size:40px;			/*字体大小*/
font: 10pt "微软雅黑";	/* 字体大小及格式*/
border:0px solid white;	/*边框粗细及颜色*/
border-radius:0px;		/*边框半径*/
/*设置字体颜色方式*/
color: red;	
color: #FF00FE;			
color: rgba(255, 0, 255, 255);	/*其中a表示透明度*/
/*设置背景颜色方式*/
background-color: blue
background-color: #00FFEE
background-color: rgba(255, 255, 0, 255);	

  可通过模拟设计一个自带的计算器来练手UI设计,后续也可继续优化计算机具体功能。

通过样式表设置按钮三态

/*按钮正常状态*/
QPushButton{background-color: rgba(220, 250, 220, 255);border:0px solid white;border-radius:0px;font-size:60px;
}
/*按钮悬停状态*/
QPushButton:hover{ background-color: rgba(255, 255, 0, 255);border:0px solid white;border-radius:0px;color:#FF00FE;font-size:60px;
}
/*按钮按下状态*/
QPushButton:pressed{background-color: rgba(255, 255, 0, 255);border:0px solid white;border-radius:0px;color: #FF00FE;font-size:60px;
} 

以图片作为按钮背景

资源文件:
  如果你的程序需要加载特定的资源(图标、文本翻译等),那么,将其放置在资源文件中,就再也不需要担心这些文件的丢失。

加载图片资源

设置窗口标题及图标

添加图片
样式表->添加资源->border-image

将图片资源放入按钮三态

二、按键响应——☆信号与槽

信号与槽基本概念

  在Qt中,信号和槽是一种非常强大的事件通信机制,理解信号与槽对于编写Qt程序至关重要
概要:
1. 信号(Signals): 是由对象在特定事件发生时发出的消息。例如,QpushButton 有一个 clicked()信号,当用户点击按钮时发出。
2. 槽(Slots): 是用来响应信号的方法。一个槽可以是任何函数,当其关联的信号被发出时,该槽的函数被调用。
3. 连接信号和槽:使用 Qobject::connect()方法将信号连接到槽。当信号发出时,关联的槽函数会自动执行。

按键QPushButton设置信号与槽

连接方式描述示例
自动连接(使用UI文件)在使用Qr Designer时,可以通过命名约定自动连接信号和槽。当UI文件自动加载 时,以on_ objectName_ signalName 命名的槽会自动连按到相应的信号在Qt Designer中命名按钮为pushButton,然后在代码中定义on_pushButton_clicked().
使用QObject::connect最常用的方式,直接通过 QObject::connect 函数连接信号和槽QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(s1ot()));
使用C++11 Lambda表达式利用C++11引入的Lambda表达式进行信号与槽的连接。这种方式可以直接在连接点使用匿名函数,使代码更加简洁QObject::connect(sender, &Sender::signal, = { /* lambda body */ });
使用函数指针Qt5中引入,允许使用函数指针直接连接信号和槽,这种方式类型安全,且可以利用IDE的代码不全和错误检测QObject::connect(sender, &Sender::signal, receiver, &Receiver::s1ot);

1. 自动连接
  在UI文件内选择按钮右键->转到槽,选择触发信号即可自动连接到槽函数

2. 使用QObject::connect

//头文件声明槽函数
private slots:void pushButton5_clicked();//构造函数内信号连接槽
//QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(s1ot()));
QObject::connect(ui->pushButton5, SIGNAL(clicked()), this, SLOT(pushButton5_clicked()));//2. 第2种方式 槽函数 .cpp外部声明
void Widget::pushButton5_clicked()
{cout << "button5 ckicked()" << endl;
}

3. 使用Lambda表达式

//3. 第3种方式 lambda表达式  QObject::connect(sender, &Sender::signal, [=]() { /* lambda body */ });
QObject::connect(ui->pushButton6, &QPushButton::clicked,[=](){cout << "button6 ckicked()" << endl;
});

4. 使用函数指针

//头文件声明槽函数
private slots:void on_pushButton7_clicked();
//构造函数内信号连接槽
//4. 第4种方式 QObject::connect(sender, &Sender::signal, receiver, &Receiver::s1ot);
QObject::connect(ui->pushButton7, &QPushButton::clicked, this, &Widget::on_pushButton7_clicked);//4. 第4种方式 外部实现槽函数
void Widget::on_pushButton7_clicked()
{cout << "button4 ckicked()" << endl;
}

自定义信号与槽

  在Qt中,自定义信号与槽是实现对象间通信的一种机制。信号与槽Qt对象通信的核心特性,使得一个对象能够在发生某种事件时通知其他对象。自定义信号与槽的实现步骤如下:
1. 定义信号: 在Qt中,信号是由 signals 关键字声明类的成员函数,不需要实现,只需要声明

class Widget : public QWidget
{Q_OBJECT
public:Widget(QWidget *parent = nullptr);~Widget();signals:void mysignal();            //自定义信号void mysignalPara(int val);//自定义信号带参数
};

在上述程序中,Widget 类中有两个信号 mysignal()mysignalPara(int val),其中mysignalPara(int val)信号带参数

2. 定义槽: 槽函数可以是任何普通的成员函数,但通常在定义类中用 slots 关键字标识。槽函数可以有返回类型,也可以接受参数,但他们的参数类型需要与发出信号的参数类型匹配。例如:

class Widget : public QWidget
{Q_OBJECT
public:Widget(QWidget *parent = nullptr);~Widget();private slots:void myslot();                  //自定义槽void myslotPara(int val);       //自定义槽带参数private:Ui::Widget *ui;
};

3. 连接信号与槽: 使用 QObject::connect 函数将信号与槽连接起来。当信号被发射时,连接到这个信号的槽被调用,通常在构造函数内进行连接

 //绑定信号与槽
connect(this, SIGNAL(mysignal()), this, SLOT(myslot()));
connect(this, SIGNAL(mysignalPara(int)), this, SLOT(myslotPara(int)));

这段代码分别将信号 mysignalmysignalPara 连接到槽函数 myslotmyslotPara

4. 发射信号: 使用 emit 关键字发射信号。当信号被发射时,所有连接到这个信号的槽会被调用。

emit mysignal();    //发送信号
emit mysignalPara(123);    //发送信号

这将触发所有连接到这两个信号上的槽
自定义信号和槽是Qt编程中非常强大的特性,他们似的组件之间的通信变得灵活而松耦合。通过信号和槽,可以方便实现各种复杂的事件驱动逻辑。

自定义信号与槽的实际应用——页面的跳转

  对于从页面A跳转到页面B,只需要点击页面A上的按钮,隐藏页面A,打开页面B即可,而对于如何从页面B切换回页面A则可通过自定义信号和槽实现。
   页面B上的按钮点击后发射信号,页面A实时检测自定义信号,检测到到页面B中的按钮发出的自定义信号时,隐藏页面B,显示页面A。
思路流程图及伪代码实现:

切换到新窗口:

    //页面切换//创建新窗口SecondWindow *secondWindow = new SecondWindow();connect(ui->pushButton8,&QPushButton::clicked,this,[=](){secondWindow->show();this->hide();});

切换回原窗口:
secondwindow.h

signals:void btn_clicked();         //按键按下发送的自定义信号

secondwindow.cpp: 按下返回按钮,发送返回信号供主窗口接收

//按下返回按钮,发送返回信号供主窗口接收
connect(ui->pushButton, &QPushButton::clicked,[=](){//emit 窗口发信号emit btn_clicked();
});

firstwindow.cpp: 接收返回按钮发送的返回信号

//接收B窗口发送的信号
connect(secondWindow,&SecondWindow::btn_clicked,[=](){secondWindow->hide();this->show();
});

三、文件类操作QFile

主要功能:

  • 文件读取: QFile 支持打开文件进行读取或写入操作
  • 文件信息: 可以检索有关文件的信息,如大小、修改日期等
  • 文件操作: 提供了对文件进行重命名、移动、 删除等操作的能力
  • 错误处理: QFile 在操作文件时提供了错误处理机制,可以通过相应的函数检查和获取错误信息

文件的直接读写

常用方法功能
open(flags)打开一个文件,需要指定模式(如只读、只写、 读写等)
close()关闭文件
read(char *data, qint64 maxlen) 和 write(char *data, qint64 maxlen)用于读取和写入数据
exists()检查文件是否存在
remove()删除文件
copy()复制文件
size()文件大小,字符数

文件读取:

void Widget::on_pushButton1_clicked()
{//1. 打开文件//加载文件 这里要加绝对路径QFile file("E:/qtProject/00_QT_CLC/notebook2/data.txt");//打开文件 只读 TXT类型 if(!file.open(QIODevice::ReadOnly | QIODevice::Text))    qDebug() << "file open error" << endl;//2. 读取文件int size = file.size();char* context = new char(size);int ret = file.read(context,100);if(ret == -1){qDebug() << "file read error" << endl;return;}//3. 输出文件内容并关闭cout << context << endl;file.close();
}

文件写入:

//保存文件按钮
void Widget::on_pushButton3_clicked()
{//1. 打开文件//加载文件 这里要加绝对路径QFile file("E:/qtProject/00_QT_CLC/notebook2/data.txt");  //打开文件 可读可写 文本模式 覆盖写  if(!file.open(QIODevice::ReadWrite | QIODevice::Text| QIODevice::Truncate))      qDebug() << "file open error" << endl;//2. 写入文件char context[] = "hello world";int ret = file.write(context,strlen(context));if(ret == -1){qDebug() << "file write error" << endl;return;}//3. 关闭文件file.close();
}

通过文件流读写数据

文件的读取:

void Widget::on_pushButton1_clicked()
{//加载文件 这里要加绝对路径QFile file("E:/qtProject/00_QT_CLC/notebook2/data.txt");//打开文件 只读 TXT类型 if(!file.open(QIODevice::ReadOnly | QIODevice::Text))    qDebug() << "file open error" << endl;//读取文件数据流QTextStream in(&file);	//绑定文件与流in.setCodec("UTF-8");while(!in.atEnd()){QString line = in.readLine();qDebug() << line << endl;}file.close();   //关闭文件
}

文件的写入:

//保存文件按钮
void Widget::on_pushButton3_clicked()
{//1. 打开文件//加载文件 这里要加绝对路径QFile file("E:/qtProject/00_QT_CLC/notebook2/data.txt");  //打开文件 可读可写 文本模式 覆盖写  if(!file.open(QIODevice::ReadWrite | QIODevice::Text| QIODevice::Truncate))      qDebug() << "file open error" << endl;//以数据流写数据QTextStream out(&file);	//绑定文件与流out.setCodec("UTF-8");out << "abcdef" << "\n";file.close();   //关闭文件
}

QFileDialog 文件选择框

打开文件

使用QFileDialog的基本流程步骤通常如下:
实例化对象: 首先,创建一个 QFileDialog 的对象实例

//1. 实例化对象
QFileDialog dialog;

设置模式: 根据需要设置对话框的模式,如打开文件、保存文件等

//设置模式 setFileMode
//QFileDialog::AnyFile 			任何文件  
//QFileDialog::ExistingFile  	存在的文件  
//QFileDialog::Directory 		文件夹
//QFileDialog::ExistingFiles 	存在的多个文件
dialog.setFileMode(QFileDialog::ExistingFiles);

设置过滤器: 如果需要,可以设置文件类型过滤器,以限制用户可以选择的文件夹类型

//设置文件类型过滤器 setNameFilter
//dialog.setNameFilter("*.txt");
dialog.setNameFilter(tr("Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"));

显示对话框: 通过调用 exec() 方法显示对话框,并在用户作出选择后执行相应的操作

//显示对话框
dialog.exec();
//选择文件
//选择的文件名称存入列表
QStringList  qstrings = dialog.selectedFiles(); 
for(QString str : qstrings) // 迭代器遍历qstrings
{qDebug() << str << endl;
}

程序实例:

//分步骤打开
//1. 实例化对象
QFileDialog dialog;
//设置模式 setFileMode
//QFileDialog::AnyFile 任何文件  ExistingFile :存在的文件  Directory 目录 ExistingFiles 存在的多个文件
dialog.setFileMode(QFileDialog::ExistingFile);
//设置文件类型过滤器 setNameFilter
//dialog.setNameFilter("*.txt");
dialog.setNameFilter(tr("Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"));
//显示对话框
dialog.exec();
//选择文件
QStringList  fileName = dialog.selectedFiles(); //1. 打开文件
QFile file(fileName[0]);   //加载文件
//后续文件读写操作 同上

通过 selectedFiles 方法获取用户选择的文件路径列表,然后对这些文件进行相应的处理。

当然读取一个文件夹名称也可以通过帮助手册中的getOpenFileName方法给出的示例进行修改程序参数即可。

//通过QFileDialog 弹窗选择txt文件 调用手册例程
QString fileName;
fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"E:/qtProject/00_QT_CLC/notebook2",tr("Text (*.txt)"));

创建 / 保存文件

   创建 / 保存文件相对于打开文件而言较为简单,通过调用 getSaveFileName 方法即可实现,通过修改帮助手册中的示例程序即可。

void Widget::on_pushButton3_clicked()
{//通过文件选择框创建一个文件QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),"E:/qtProject/00_QT_CLC/notebook2/data.txt",tr("Text (*.txt)"));//以文件流方式读写//1. 打开创建的文件QFile file(fileName);if(!file.open(QIODevice::ReadWrite | QIODevice::Text| QIODevice::Truncate))    //打开文件qDebug() << "file open error" << endl;//将数据写入创建的文件中QTextStream out(&file);out.setCodec("UTF-8");out << "write data from QFileDialog" << "\n";file.close();   //关闭文件
}

四、记事本基本功能整合

  因为涉及文件的打开,保存与关闭,因此需要将文件对象file和文件名fileName设置为类的成员属性,供成员函数的共同访问。

行编辑器与文本编辑器

行编辑器:

常用方法功能
setText(QString context)覆盖的形式设置行编辑器内容
clear()清空行编辑器内容
QString text()获取行编辑器内容

文本编辑器:
  与行编辑器不同的是,文本编辑器支持追加写数据,但没有text()方法,文本编辑器需要通过toPlainText 方法来获取编辑器的内容。

常用方法功能
setText(QString context)覆盖的形式设置文本编辑器内容
append(QString context)以行的形式往文本编辑器中追加数据,行编辑器不能追加数据
clear()清空文本编辑器内容
QString toPlainText()获取文本编辑器内容

文件的打开

  对于打开文件,只需将上述通过文件选择框选择文件 + 文件数据的读取 + 文本框显示内容三段代码进行合并即可,具体实现如下:

void Widget::on_pushButton1_clicked()
{/******1. 通过QFileDialog 弹窗选择txt文件*****///通过QFileDialog 弹窗选择txt文件 调用手册例程fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"E:/qtProject/00_QT_CLC/notebook2",tr("Text (*.txt)"));/*****2. 通过数据法读取txt文件内容*******///以文件流方式读写//1. 打开文件//可读可写打开文件file.setFileName(fileName);if(!file.open(QIODevice::ReadWrite| QIODevice::Text))    //打开文件qDebug() << "file open error" << endl;//读取文件数据流QTextStream in(&file);in.setCodec("UTF-8");//在往文本编辑器中写数据前 先清空文本编辑器的数据 防止文件重复显示ui->textEdit->clear();while(!in.atEnd()){QString line = in.readLine();//qDebug() << line << endl;/******3. 将txt文件内容输出至文本编辑器******///3. 输出文件内容//cout << line << endl;ui->textEdit->append(line);}//关闭文件//file.close();  //后续优化 在关闭按钮内关闭
}

注:

  • 分步骤打开一个文件选项框代码冗余,但打开多个文件需要这样写
  • 读取文件使用文件流较可靠,因为使用直接法会存在一些编码问题

文件的保存

  同理,对于文件的保存与文件的打开类似,主要也分为三个步骤,读取文本编辑器数据 + 通过选择文件选项框创建文件 + 数据写入新文件进行保存。

//保存文件按钮
void Widget::on_pushButton3_clicked()
{//文件未打开的情况 弹窗新建文件if(!file.isOpen()){//通过文件选择框创建一个文件QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),"E:/qtProject/00_QT_CLC/notebook2/data.txt",tr("Text (*.txt)"));      //以文件流方式读写//1. 打开创建的文件file.setFileName(fileName);//可读可写打开文件if(!file.open(QIODevice::ReadWrite | QIODevice::Text| QIODevice::Truncate))    qDebug() << "file open error" << endl;}//清空原文件夹中的数据 存入文本编辑器数据file.resize(0);//将数据写入创建的文件中QTextStream out(&file);out.setCodec("UTF-8");//获取文本编辑器内容QString context = ui->textEdit->toPlainText();out << context;//关闭文件//file.close();  //后续优化 在关闭按钮内关闭
}

关闭按钮的实现

  在点击关闭按钮时需要通过isOpen方法检测文件是否打开

//设计关闭按钮 用于关闭文件
void Widget::on_pushButton2_clicked()
{ui->textEdit->clear();if(file.isOpen()){file.close();}
}

基础功能展示:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/439717.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

快速理解MoE模型

最近由于一些开源MoE模型的出现&#xff0c;带火了开源社区&#xff0c;为何&#xff1f;因为它开源了最有名气的GPT4的模型结构&#xff08;OPEN AI&#xff09;&#xff0c;GPT4为何那么强大呢&#xff1f;看看MoE模型的你就知道了。 MoE模型结构&#xff1a; 图中&#xff0…

【总线接口】3.常见总线、接口GPIO、I2C、SPI、I2S、Modbus

初接触硬件&#xff0c;五花八门的总线、接口一定会让你有些疑惑&#xff0c;我尝试用一系列文章来解开你的疑惑。 系列文章 【总线接口】1.以Xilinx开发板为例&#xff0c;直观的认识硬件接口 【总线接口】2.学习硬件这些年接触过的硬件接口、总线 大汇总 【总线接口】3.常见…

ES6.8.6 Java客户端发起 增删改查 query (bool)、update、delete

文章目录 环境测试数据增单个新增批量新增 删通过delete by api删除通过delete by query api删除删除索引中指定字段&#xff08;script&#xff09; 改单个修改update by api通过_bulk批量修改批量修改update by query api使用script脚本修改 查完全匹配&#xff08;term&…

MySQL原理(一)架构组成(2)逻辑模块组成

总的来说&#xff0c;MySQL可以看成是二层架构&#xff0c;第一层我们通常叫做SQL Layer&#xff0c;在MySQL数据库系统处理底层数据之前的所有工作都是在这一层完成的&#xff0c;包括权限判断&#xff0c;sql解析&#xff0c;执行计划优化&#xff0c;query cache的处理等等&…

【web安全】文件上传漏洞

upload-labs靶场 第一关 绕过前端 先打开哥斯拉&#xff0c;生成木马&#xff0c;选择php 打开brup开浏览器&#xff0c;上传文件&#xff0c;就会发现被阻止了&#xff0c;还没抓到包呢 那就是被前端代码阻止了&#xff0c;那通常前端代码都只能防御后缀名 我们抓到包后直…

vuex store,mutations,getters,actions

文章目录 1.vuex概述2.构建vuex【多组件数据共享】环境Son1.vueSon2.vueApp.vue 3.创建一个空仓库4.如何提供&访问vuex的数据①核心概念 - state状态1.通过store直接访问2.通过辅助函数简化代码 ②核心概念 - mutations&#xff08;粗略&#xff09; 5.核心概念 - mutation…

前端大屏展示可视化——地图的绘制(持续更新)

一、ECharts 1、安装 npm install echarts2、引入 import * as echarts from echarts;3、渲染 3.1、前期准备&#xff0c;基础配置 // 地图实例 const myChart ref(null); // 地图配置 const option reactive({tooltip: {trigger: item,formatter: function (params) {re…

2024年新提出的算法:(凤头豪猪优化器)冠豪猪优化算法Crested Porcupine Optimizer(附Matlab代码)

本次介绍一种新的自然启发式元启发式算法——凤头豪猪优化器(Crested Porcupine Optimizer&#xff0c;CPO)。该成果于2024年1月发表在中科院1区SCI top期刊Knowledge-Based Systems&#xff08;IF 8.8&#xff09;上。 1、简介 受到凤头豪猪&#xff08;CP&#xff09;各种…

使用Hutool工具包解析、生成XML文件

说明&#xff1a;当我们在工作中需要将数据转为XML文件、或者读取解析XML文件时&#xff0c;使用Hutool工具包中的XMLUtil相关方法是最容易上手的方法&#xff0c;本文介绍如何使用Hutool工具包来解析、生成XML文件。 开始之前&#xff0c;需要导入Hutool工具包的依赖 <de…

1688平台商品详情数据的采集|Python实现接口调用【1688平台商品】数据采集

前言 1688平台是阿里巴巴集团推出的B2B电子商务平台。该平台于1999年上线&#xff0c;旨在为国内外买家提供海量优质商品和供应商资源&#xff0c;帮助企业进行采购和销售业务。1688平台主要面向中小型企业和个体工商户&#xff0c;提供了各行各业的产品和服务。 在1688平台上…

编写交互式 Shell 脚本

在日常的系统管理和自动化任务中&#xff0c;使用 Shell 脚本可以为我们节省大量时间和精力。 文章将以输入 IP 为例&#xff0c;通过几个版本逐步完善一个案例。 原始需求 编写一个交互式的 Shell 脚本&#xff0c;运行时让用户可以输入IP地址&#xff0c;并且脚本会将输入…

ASP.NET Core 过滤器 使用依赖项注入

过滤器是 ASP.NET Core 中的特殊组件&#xff0c;允许我们在请求管道的特定阶段控制请求的执行。这些过滤器在中间件执行后以及 MVC 中间件匹配路由并调用特定操作时发挥作用。 简而言之&#xff0c;过滤器提供了一种在操作级别自定义应用程序行为的方法。它们就像检查点&#…