QT记事本
- 1.概述
- 2.界面
- 2.1 界面布局
- 2.2 UI美化stylesheet
- 2.2.1 准备
- 2.2.2 stylesheet
- 2.2.3 效果
- 2.3 窗口大小调整与子控件自适应
- 3.信号与槽
- 3.1 简述
- 3.2 信号与槽设置
- 3.2.1 UI控件设置
- 3.2.2 UI转到槽(自动连接)
- 3.2.3 使用QObject::connect设置
- 3.2.4 Lambda表达式设置
- 3.2.5 使用函数指针
- 3.2.6 自定义信号与槽
- 3.2.7 自定义带参数信号与槽
- 4.文件操作类
- 4.1 介绍(所用)
- 4.2 QFileDialog文件选择对话框
- 4.3 文件读入操作
- 4.4 文件保存操作
- 4.5 文件关闭操作
- 4.6 comboBox字符编码改变后操作
- 4.7 设置行高亮显示行列号
- 4.8 设置快捷方式创建和打开文件
- 4.9 设置快捷方式放大缩小文字
- 5.事件处理
- 5.1 介绍
- 5.2 事件处理(重写事件处理)
- 5.3 鼠标滚轮实现textEdit文本字体放大缩小
- 5.4 用事件自定义按键
- 5.3.1 为自定义按键设置信号与槽
- 5.5 将ui的textEdit控件提升为自定义MytextEdit
- 5.6注:5.3QWidget与5.5将TextEdit提升为MyTextEdit事件处理的区别
- 5.事件过滤(从事件过滤除修改而不改变事件处理方式)
- 5.1 事件过滤器
1.概述
- 支持文本创建、打开、关闭、保存功能
- 添加打开快捷键、添加保存快捷键
- 底部显示行列号及文本字符 编码
- ctrl+鼠标滚轮支持字体放大缩小
2.界面
2.1 界面布局
2.2 UI美化stylesheet
2.2.1 准备
- 首先添加资源包
- 创建好后添加Prefix 前缀不要
- 添加文件并选择自己所需的文件
2.2.2 stylesheet
QPushButton { color: red } //正常情况显示红色
QPushButton:hover { color: white } //悬停后白色
QPushButton:pressed { color: black } //按下后黑色
将其内容改为图片
1.选择按钮右键
2.选择样式表
3.点击添加资源旁倒三角,选择border-image
4.选择自己添加的图片资源,并将其自动生成的内容剪切到{}中
QPushButton { border-image: url(:/icon/o1.png); }
QPushButton:hover { border-image: url(:/icon/o2.png); }
QPushButton:pressed { border-image: url(:/icon/o3.png); }
2.2.3 效果
2.3 窗口大小调整与子控件自适应
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
//实现窗口大小调整与子控件自适应
ui->setupUi(this); //加载ui组件 this是Widget窗体的对象,ui是UI界面widget窗体的对象
//虽然上面一行代码进行widget和ui窗口的关联,但如果窗口大小发生变化时,里面布局不会随之改变
//通过下面这行代码进行显示说明,让窗口变化时,布局及其子控件随之调整
this->setLayout(ui->verticalLayout); //设置ui->verticalLayout与拉伸同步
ui->widgetButtons->setLayout(ui->hlhorizontalLayout); //设置ui->hlhorizontalLayout与拉伸同步
ui->widgetButton->setLayout(ui->horizontalLayout); //设置ui->horizontalLayout与拉伸同步
}
Widget::~Widget()
{
delete ui;
}
3.信号与槽
3.1 简述
1.信号(Signals):是由对象在特定事件发生时发出的消息。例如, QPushButton 有一个clicked() 信号,当用户点击按钮时发出。
2.槽 (Slots):是用来响应信号的方法。一个槽可以是任何函数,当其关联的信号被发出时,该槽函数将被调用。
3连接信号和槽:使用 QObject::connect() 方法将信号连接到槽。当信号发出时,关联的槽函数会自动执行。
3.2 信号与槽设置
3.2.1 UI控件设置
发送者:btnClose---自己定义的名字:关闭按钮
信号:clicked() ---点击操作,点击发送信号
接受者:Widget ---- UI界面
槽: close() ----- Widget执行槽函数close()进行关闭操作
流程:鼠标点击btnClose,btnClose发送clicked()信号,Widget接收到信号,执行槽函数close() 关闭Widget
3.2.2 UI转到槽(自动连接)
当我们需要点击操作之后不是关闭而是要执行我们所需要的操作时,此时从UI控件点击右键转到槽
会自动生成一个槽函数,我们可以在生成的槽函数中写自己所需要的操作
在头文件中生成
在widget.cpp中生成
槽函数
void Widget::on_btnClose_clicked()
{
qDebug() << " Close clicked";
}
此时点击关闭按钮会在运行程序输出栏中显示:Close clicked
3.2.3 使用QObject::connect设置
最常用的方式,在构造函数中直接通过QObject::connect 函数连接信号和槽。
QObject::connect(sender,SIGNAL(signal()),receiver, SLOT(slot()));
根据3.2.1的设置相应的代码是
QObject::connect(ui->btnClose,SIGNAL(clicked()),this,SLOT(close()));
此种方法灵活多变,可将不同的发送者接入到同一种槽函数如:
QObject::connect(ui->btnOpen,SIGNAL(clicked()),this,SLOT(on_btnClose_clicked()));
将打开按键连接到已存在的槽函数on_btnClose_clicked()中。
若需要自定义新的槽函数,需在头文件中声明该函数,并自己写相应的槽函数。
在widget.h中自定义,然后再widget.cpp文件中添加自定义
3.2.4 Lambda表达式设置
此种方式不需要如3.2.3一样声明槽函数,只需要在lambda函数体中进行操作即可,
注意的是第二位置不是用SIGNAL宏操作,而是用引用某个类里的函数
QObject::connect(sender,&Sender::signal, [=]() {/* lambda body */ });
将其函数体内改成某个槽函数也可
QObject::connect(ui->btnSave,&QPushButton::clicked,[=](){
on_btnOpen_clickedMySelf();
});
3.2.5 使用函数指针
QObject::connect(ui->btnOpen,&QPushButton::clicked,this,&Widget::on_btnOpen_clickedMySelf);
QObject::connect(ui->btnOpen,&QPushButton::clicked,this,&Widget::on_btnOpen_clickedMySelf);
3.2.6 自定义信号与槽
在Qt中,自定义信号与槽是实现对象间通信的一种机制。信号和槽是Qt对象通信的核心特性,使得一个对象能够在发生某种事件时通知其他对象。自定义信号与槽的实现步骤如下:
1.定义信号:在Qt中,信号是由signals关键字声明的类成员函数。它们不需要实现,只需要声明
2.定义槽::槽可以是任何普通的成员函数,但通常在类定义中用 slots 关键字标识。槽可以有返回类型,也可以接受参数,但它们的参数类型需要与发出信号的参数类型匹配。
在widget.h文件中自定义信号与槽
3.连接信号与槽:使用 QObject::connect 函数将信号与槽连接起来。当信号被发射时,连接到这个信号的槽将被调用。
4.发射信号:使用 emit 关键字发射信号。当信号被发射时,所有连接到这个信号的槽都会被调用。
3.2.7 自定义带参数信号与槽
过程与3.2.7一致,区别在于连接信号与槽时需要在括号内加入形参,且形参一致。
4.文件操作类
4.1 介绍(所用)
- QFile
- QTextStream
- QFileDialog
- QMessageBox
- QTextCursor
- QList
- QTextEdit::ExtraSelection
- QShortcut
- QFont
4.2 QFileDialog文件选择对话框
QString fileName = QFileDialog::getOpenFileName(this,tr("Open Text"), "C:/Users/qzh/Desktop", tr("Text (*.txt)"));
/*
tr("Open Text") 这个是设置对话框的标题是Open Text
"C:/Users/qzh/Desktop"-打开的文件路径
"Text (*.txt)" - 过滤的文件格式
*/
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
"C:/Users/qzh/Desktop",
tr("Text (*.txt *.doc)"));
类似于4.1.1
4.3 文件读入操作
在头文件中创建QFile实例对象用于判断其打开或关闭状态
/*
点击打开按钮后操作的内容
1.弹出选择打开的文件对话框
2.创建一个所选的打开文件的对象实例
3.设置文件可读可写的模式打开 并判断是否成功
成功则:
5.创建一个QTextStream对象的实例
6.设置该实例的内容按comboBox显示的文本编码
7.按行读取打开文本的内容
8.追加写入ui控件TextEdit上并显示
*/
void Widget::on_btnOpen_clicked()
{
/*
tr("Open Text") 这个是设置对话框的标题是Open Text
"C:/Users/qzh/Desktop"-打开的文件路径
"Text (*.txt)" - 过滤的文件格式
QFileDialog qFileDialog;
qFileDialog.setFileMode(QFileDialog::AnyFile);
qFileDialog.setNameFilter("*.txt");
qFileDialog.exec();
QStringList qstrings = qFileDialog.selectedFiles();
for(QString str : qstrings){
qDebug() << str;
} //过滤选择多个文件
*/
QString fileName = QFileDialog::getOpenFileName(this,tr("Open Text"), "C:/Users/qzh/Desktop", tr("Text (*.txt)"));
file.setFileName(fileName);
if(file.open(QIODevice::ReadWrite | QIODevice::Text)){
ui->textEdit->clear();
QTextStream in(&file); //创建一个QTextStream对象的实例
//ui->comboBox->currentText().toStdString().c_str(); 将QString类型转化为Char * 型
in.setCodec(ui->comboBox->currentText().toStdString().c_str()); //修改字符编码
while(!in.atEnd()){
QString context = in.readLine(); //对打开的文件按行读取
//ui->textEdit->setText(context); //复写文本,会将已存文本覆盖
ui->textEdit->append(context); //对textEdit控件进行追加添加打开文件的内容
}
} //以可读可写的方式打开,同时以Text文本的方式打开
}
4.4 文件保存操作
/*
保存按钮按下后
1.判断文件是否打开
若未被打开--文件是否存在
2.弹出保存对话框并选择路径
3.打开选择路径的文件
若已打开
4.实例化QTextStream对象
5.设置该对象字符编码
6.获取ui中TextEdit控件中的内容
7.将获取的内容写入文实例化的对象中
*/
void Widget::on_btnSave_clicked()
{
//1.判断文件是否打开
if(!file.isOpen()){
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),
"C:/Users/qzh/Desktop",
tr("Text (*.txt *.doc)"));
file.setFileName(fileName);
if(!file.open(QFile::WriteOnly | QFile::Truncate)){
qDebug() << "Open Error";
};
}
QTextStream out(&file); //实例化对象
out.setCodec(ui->comboBox->currentText().toStdString().c_str()); //设置字符编码
QString context = ui->textEdit->toPlainText(); //以纯文本的形式返回文本编辑文本
out << context;
}
4.5 文件关闭操作
void Widget::on_btnClose_clicked()
{
int ret = QMessageBox::warning(this, tr("My Application"),
tr("The document has been modified.\n"
"Do you want to save your changes?"),
QMessageBox::Save | QMessageBox::Discard
| QMessageBox::Cancel,
QMessageBox::Save);
switch (ret) {
case QMessageBox::Save:
on_btnOpen_clicked();
break;
case QMessageBox::Discard:
ui->textEdit->clear();
if(file.isOpen()){
file.close();
}
break;
case QMessageBox::Cancel:
// Cancel was clicked
break;
default:
// should never be reached
break;
}
}
4.6 comboBox字符编码改变后操作
首先将comboBox文本内容改变信号与自定义槽onCurrentTextChanged()连接
connect(ui->comboBox,SIGNAL(currentTextChanged(QString)),this,SLOT(onCurrentTextChanged()));
/*
comboBox内字符编码改变后
1.清空当前ui控件textEdit文本框内容
2.判断文件是否打开
3.若打开则实例化QTextStream对象
4.设置字符编码
5.将光标移动重新读取文件内容并写入ui的textEdit控件中
*/
void Widget::onCurrentTextChanged()
{
ui->textEdit->clear();
if(file.isOpen()){
QTextStream in(&file);
in.setCodec(ui->comboBox->currentText().toStdString().c_str());
in.seek(0); // 移动光标至开头
while(!in.atEnd()){
QString context = in.readLine();
//qDebug() << context;
//ui->textEdit->setText(context); //复写
ui->textEdit->append(context); //追加
}
}
}
4.7 设置行高亮显示行列号
设置行高亮函数:
void QTextEdit::setExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
void Widget::onCursorPositionChanged()
{
QTextCursor cursor = ui->textEdit->textCursor();
/*
cursor.blockNumber(); //返回行号 int 型
cursor.columnNumber(); //返回列号 int 型
QString::number(); //将数值型强制转成QString型
*/
QString row = QString::number(cursor.blockNumber() + 1);
QString col = QString::number(cursor.columnNumber() + 1);
QString LabelMes = "行:" + row + ",列:" + col;
ui->label->setText(LabelMes);
//设置当前行高亮
QList<QTextEdit::ExtraSelection> extraSelection; //对extraSelection集合进行设置
QTextEdit::ExtraSelection ext; // QTextEdit::ExtraSelection成员cursor format
//1.知道当前行
ext.cursor = ui->textEdit->textCursor();
//2.颜色
QBrush qBrush(Qt::yellow);
//void QTextFormat::setBackground(const QBrush &brush)
ext.format.setBackground(qBrush); //设置背景色
ext.format.setProperty(QTextFormat::FullWidthSelection,true); //设置属性整行选择
//3.设置
extraSelection.append(ext); //将ext加到extraSelection中
ui->textEdit->setExtraSelections(extraSelection);
}
4.8 设置快捷方式创建和打开文件
使用QShortcut
shortcut = new QShortcut(QKeySequence(tr("Ctrl+O", "File|Open")),
parent);
QShortcut *shortcutOpen = new QShortcut(QKeySequence(tr("Ctrl+n", "File|Open")),
this);
QShortcut *shortcutSave = new QShortcut(QKeySequence(tr("Ctrl+s", "File|Open")),
this);
connect(shortcutOpen,&QShortcut::activated,[=](){
on_btnOpen_clicked();
}); //使用匿名函数信号由QShortcut::activated()发送
connect(shortcutSave,&QShortcut::activated,[=](){
on_btnSave_clicked();
});
4.9 设置快捷方式放大缩小文字
void setFont(const QFont &)
QShortcut *shortcutZoomIn = new QShortcut(QKeySequence(tr("Ctrl+Shift+=", "File|Open")),
this);
QShortcut *shortcutZoomOut = new QShortcut(QKeySequence(tr("Ctrl+Shift+-", "File|Open")),
this);
connect(shortcutZoomIn,&QShortcut::activated,[=](){
ZoomIn();
});
connect(shortcutZoomOut,&QShortcut::activated,[=](){
ZoomOut();
});
void Widget::ZoomIn()
{
//获取textEdit字体信息
QFont font = ui->textEdit->font();
//获取当前文字的大小
int currentSize = font.pointSize();
if(currentSize == -1){
return;
}
//改变字体的大小并设置
int newSize = currentSize + 1;
font.setPointSize(newSize);
ui->textEdit->setFont(font);
}
void Widget::ZoomOut()
{
//获取textEdit字体信息
QFont font = ui->textEdit->font();
//获取当前文字的大小
int currentSize = font.pointSize();
if(currentSize == -1){
return;
}
//改变字体的大小并设置
int newSize = currentSize - 1;
font.setPointSize(newSize);
ui->textEdit->setFont(font);
}
5.事件处理
5.1 介绍
- 事件派发
- 事件过滤
- 事件分发
- 事件处理
众所周知Qt是一个基于C++的框架,主要用来开发带窗口的应用程序(不带窗口的也行,但不是主流)。
我们使用的基于窗口的应用程序都是基于事件,其目的主要是用来实现回调(因为只有这样程序的效率
才是最高的)。所以在Qt框架内部为我们提供了一些列的事件处理机制,当窗口事件产生之后事件会
经过: 事件派发 -> 事件过滤->事件分发->事件处理几个阶段。
Qt窗口中对于产生的一系列事件都有默认的处理动作,如果我们有特殊需求就需要在合适的阶段重写事件的处理动作,比如信号与槽就是一种事件(event)是由系统或者 Qt 本身在不同的场景下发出的。当用户按下/移动鼠标、敲下键盘,或者是窗口关闭/大小发生变化/隐藏或显示都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,
如鼠标/键盘事件等;另一些事件则是由系统自动发出,如计时器事件。
每一个Qt应用程序都对应一个唯一的 QApplication 应用程序对象,然后调用这个对象的 exec() 函数,这样Qt框架内部的事件检测就开始了( 程序将进入事件循环来监听应用程序的事件 )。
5.2 事件处理(重写事件处理)
在事件的四个步骤中,当我们需要对事件的处理结果进行操作时,只需要重写事件处理函数,在头文件中重写事件处理,重写enterEvent事件,
过程:
1.当鼠标进入事件产生后,qt使用应用程序调用notify()函数将事件发送到指定窗口
2.在发送过程中可通过事件过滤器过滤,默认不过滤
3.事件发送到指定窗口后,窗口的事件分发器会对收到的事件进行分类
4.分类之后的事件(如鼠标事件,键盘事件)分发给对应的函数进行处理
5.3 鼠标滚轮实现textEdit文本字体放大缩小
1.当ctrl按下后,事件产生
2.过滤事件默认不过滤
3.鼠标按下事件被分发
4.事件分发给keyPresseEvent函数(重写的)进行处理
5.将keyFlag标志为人为置1
void Widget::keyPressEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key_Control){
KeyFlag = 1;
};
}
void Widget::keyReleaseEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key_Control){
KeyFlag = 0;
};
}
void Widget::wheelEvent(QWheelEvent *e)
{
if(KeyFlag == 1){
if(e->angleDelta().y() > 0){ //返回滚轮的y轴数值
ZoomIn();
}else{
ZoomOut();
}
e->accept();
}
}
5.4 用事件自定义按键
1.首先自定义一个类Mybutton,继承于QWidget
2.对相应的事件进行重写
3.将widget控件提升为Mybutton,提升后其类为Mybutton
绘图时:
使用QPainter,先加载图片然后更新,触发painterEvent事件
具体代码如下
#include "mybutton.h"
#include <QPainter>
Mybutton::Mybutton(QWidget *parent) : QWidget(parent)
{
//load(const QString &fileName, const char *format = nullptr, Qt::ImageConversionFlags flags = Qt::AutoColor)
//c++ 的好处调用函数形参列表可以不用传完可以帮助我们进行默认的填充
pic.load(":/icon/o1.png"); //加载图片
setFixedSize(pic.size()); //设置图片的大小
update();
}
void Mybutton::mousePressEvent(QMouseEvent *event)
{
pic.load(":/icon/o3.png"); //加载图片
update();
}
void Mybutton::leaveEvent(QEvent *event)
{
pic.load(":/icon/o1.png"); //加载图片
update();
}
void Mybutton::enterEvent(QEvent *event)
{
pic.load(":/icon/o2.png"); //加载图片
update();
}
void Mybutton::paintEvent(QPaintEvent *event) //paintEvent 当updata的时候才会刷新
{
QPainter painter(this);
painter.drawPixmap(rect(),pic);
//rect() 获取当前绘画的矩形区域
}
5.3.1 为自定义按键设置信号与槽
1.首先为自定义信号自定义一个信号和槽,在Mybutton.h中添加clicked()信号,
2.然后在widget.cpp中进行信号与槽的连接connect
3.在鼠标按下事件中人为的发送自定义信号clicked -- emit clicked();
5.5 将ui的textEdit控件提升为自定义MytextEdit
1.首先创建一个类,继承于QTextEdit
2.将自定义MytextEdit与整个控件相关联
3.重写事件
4.将重写事件返回其正常状态
#include "mytextedit.h"
#include <QWheelEvent>
MyTextEdit::MyTextEdit(QWidget *parent) : QTextEdit(parent) //初始化列表构造函数进行与ui控件的关联
{
}
void MyTextEdit::wheelEvent(QWheelEvent *e)
{
if(CtrlKeyPressFlag == 1){
if(e->angleDelta().y() > 0){ //返回滚轮的y轴数值
zoomIn();
}else{
zoomOut();
}
e->accept();
}else{
QTextEdit::wheelEvent(e); //对wheelEvent重写后使其返回正常状态
}
}
void MyTextEdit::keyPressEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key_Control){
CtrlKeyPressFlag = 1;
};
QTextEdit::keyPressEvent(e); //对keyPressEvent重写后使其返回正常状态
}
void MyTextEdit::keyReleaseEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key_Control){
CtrlKeyPressFlag = 0;
};
QTextEdit::keyReleaseEvent(e); //对keyReleaseEvent重写后使其返回正常状态
}
5.6注:5.3QWidget与5.5将TextEdit提升为MyTextEdit事件处理的区别
在QWidget中事件为virtual虚函数,对其重写并不影像其子类
在QTextEdit中其继承于QWidget,
其虚函数有其自己的内容,重写QTextEdit中的虚函数需要使其复原,
因此在MyQTextEdit中重写其虚函数后需使MyQTextEdit重写的虚构函数复原返回其原本的功能
即当对某一控件事件进行自定义重写时,当重写完自己的需求后需将其原本的功能复原。
5.事件过滤(从事件过滤除修改而不改变事件处理方式)
5.1 事件过滤器
1.定义事件过滤器
2.安装事件过滤器
3.事件过滤器逻辑
4.事件分发
5.决定是否传递事件
5.目标对象处理事件
事件过滤器设置
1.声明
bool eventFilter(QObject *watched, QEvent *event);//公有
2.安装事件过滤器
ui->textEdit->installEventFilter(this); //为textEdit安装事件过滤器,窗口的事件过滤器安装到textEdit上
3.编写事件过滤器
/*
当ctrl和滚轮事件同时发生时返回true
否则返回false
*/
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
/* //Qt::ControlModifier
QKeyEvent *keyEvent = (QKeyEvent *)event;
if(keyEvent->key() == Qt::Key_Control){
qDebug() << "ctrl";
}
*/
//event是单一事件,只能检测一种
//因此若想要按键按下和滚轮滚动同事被检测需要用两种不同的方式
//QGuiApplication::keyboardModifiers() == Qt::ControlModifier //事件过滤keyboard事件
if(QGuiApplication::keyboardModifiers() == Qt::ControlModifier){ //ctrl被按下事件
if(event->type() == QEvent::Wheel){ //滚轮事件
qDebug() << "ctrl+wheel";
//QEvent事件中没有angleDelta,所以将QEvent事件强制转换成QWeelEvent事件
QWheelEvent *wheelEvent = dynamic_cast<QWheelEvent *>(event);//QWheelEvent *wheelEvent = (QWheelEvent *)event; //强制转换
if(wheelEvent->angleDelta().y() > 0){
ZoomIn();
}else if(wheelEvent->angleDelta().y()<0){
ZoomOut();
}
return true;
}
return false;
}
}
链接:https://pan.baidu.com/s/15ZfAfkYXAnDl6kOMPSy6YA
提取码:v23d
--来自百度网盘超级会员V5的分享