QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现

news2025/3/12 18:11:21

一、编码问题

        在计算机编程中,Stream)是一种抽象的概念,用于表示数据的输入或输出。根据处理数据的不同方式,可以分为字节流Byte Stream)和字符流Character Stream)两大类。

1. 字节流(Byte Stream)

        字节流是处理数据的基本单位是字节(8位二进制数据)的流。它不考虑数据的具体内容,只是简单地将数据视为字节序列进行读取或写入。字节流主要用于处理二进制数据,例如图片、视频、音频文件等,或者当你不确定数据的内容时(比如,当你正在读取一个可能是文本也可能是其他格式的文件时)。

        Qt通过QByteArray为我们提供了一个字节数组容器(它是可变长的)。主要用来存储原始的字节流。

QByteArray仍可以表示字符串,类似与unsigned char buf[ ],但是QT中多用QString来表示字符串。

QByteArray一般结合其它类使用,比如QIODevice类的QByteArray QIODevice::readAll()

QByteArray(const char *data, int size = -1)  //构造
char   at(int i) const //返回第i个元素
void   clear()  //清空
bool   contains(const char * str) const  //是否包含字符串  ==strstr
bool   contains(char ch) const //是否包含字符
char   *data()  //从QByteArray类型转化为char *

//查找从from开始第一次匹配str的位置
int indexOf(const char *str, int from = 0)
QByteArray & append(char ch)  //尾部增加
QByteArray & prepend(char ch) //头部增加
int length() const //返回长度
QByteArray &remove(int pos, int len)  //删除

2.字符流(Character Stream)

1) 概念

        字符流则是处理数据的基本单位是字符。字符流主要用于处理文本数据。QT通过QString类为我们提供了字符串类。

2) QString相关方法
//数字转字符串, QString静态方法
QString   number(long n, int base = 10) [static]
QString   number(double n, char format = 'g', int precision = 6) [static]

例:

long a = 63;
QString s = QString::number(a, 10);             // s == "63"
QString t = QString::number(a, 16).toUpper();     // t == "3F"
//字符串转为数字
short	toShort(bool * ok = 0, int base = 10) const
float	toFloat(bool * ok = 0) const
long	toLong(bool * ok = 0, int base = 10) const

例:

QString str1 = "1234.56";
str1.toFloat();             // returns 1234.56
//从 QString 转化到 QByteArray
QByteArray toLocal8Bit() const //转成本地编码的字节流
QByteArray toUtf8() const//转成utf8编码的字节流

例:把一个QString转为char *(QString没有直接转换为char *的方法,需要中间经过一层QByteArray的过渡)

QString str1 = "hello";
char *s = str1.toLocal8Bit().data();

总结:字符流一定是字节流, 而字节流不一定是字符流。


问题:有时候数据写入文件,打开文件会出现乱码的情况,这是为什么,如何解决呢?

答:这个是涉及到编码的问题, 如果字节流的编码是UTF8, 而文件中按照GBK编码解析,可能就是乱码。


二、字符集

字符编码的集合


三、字符编码

1. 概念

        我们已经讲过了,字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题。

        因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制11111111 = 十进制255),如果要表示更大的整数,就必须用更多的字节。比如两个字节可以表示的最大整数是65535,4个字节可以表示的最大整数是4294967295

        由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122

        但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突,所以,中国制定了GB2312编码,用来把中文编进去。

        你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。

        因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间

注意:QT界面的编码是UTF8的


2. QString转为字节流相关的方法

QByteArray   toLocal8Bit() //把QString按照本地编码转换成QByteArray
QByteArray   toUtf8() //把QString按照utf-8编码转换成QByteArray

QString   fromLocal8Bit(const QByteArray & str)  //将QByteArray按照本地编码转换为QString
QString    fromUtf8(const QByteArray & str) //将QByteArray按照utf-8编码转换为QString


四、其他容器

QList

QVector

QMap

... ...


五、定时器

QTime: 时间类

QTimer: 定时器类

QDateTime: 日期时间类


1. 常用方法

//parent可以传界面的指针,但是没有父子窗体关系,作用仅剩内存管理
QTimer(QObject * parent = 0) 
void   start(int msec)  //参数为ms  定时一次,永久生效
void   stop()  //停止定时器
Signal:
Void  timeout();

//一次定时
void QTimer::singleShot(int msec, const QObject * receiver, const char * member) [static]
    receiver:接收者
    member:执行函数     

1s=1000ms 1ms=1000us  1us=1000ns

每次时间到达后会发出 timeout() 信号


2. 编程步骤

QTimer *timer = new QTimer(this);  //实例化
connect(timer, SIGNAL(timeout()), this, SLOT(update()));  //绑定超时处理函数
timer->start(1000);
...
timer->stop();  //停止定时器

实例需求:做一个时间显示Label,增加“开始”和“结束”按钮,点击开始,lab每1s记录一次时间。(或者通过数码管显示)

QTime:可以获取到系统当前时间

QDateTime:获取系统时间和日期

提示:时间处理用QDateTime

QDateTime time = QDateTime::currentDateTime();//获取系统现在的时间
QString str = time.toString("yyyy-MM-dd hh:mm:ss dddd");//设置系统时间显示格式  

代码:

mytime.h

#ifndef MYTIME_H
#define MYTIME_H

#include <QObject>
#include <QDebug>
#include <QThread>
#include <QDateTime>
class MyTime : public QObject
{
    Q_OBJECT
public:
    explicit MyTime(QObject *parent = nullptr);
    void thread_time();
    void set_flag(int flag);
signals:
    void my_signal(QString datatime);
public slots:

private:
    int flag = 1;
};

#endif // MYTIME_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QDebug>
#include <QThread>
#include "mytime.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::Widget *ui;
    QThread *thread;
    MyTime *time;
};

#endif // WIDGET_H

mytime.cpp

#include "mytime.h"

MyTime::MyTime(QObject *parent) : QObject(parent)
{

}

void MyTime::thread_time()
{
    while(flag){
        QDateTime currentTime = QDateTime::currentDateTime();
        QString formattedTime = currentTime.toString("hh:mm:ss");
        qDebug() << formattedTime;
        emit my_signal(formattedTime);
        QThread::sleep(1);
    }
}

void MyTime::set_flag(int flag)
{
    this->flag = flag;
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    thread = new QThread(this);
    time = new MyTime; // 不能指定父对象
    ui->lcdNumber->setDigitCount(8);
    time->moveToThread(thread); // 移动到thread线程中
    connect(thread,&QThread::started,time,&MyTime::thread_time);
    connect(this,&Widget::destroyed,this,&Widget::on_pushButton_2_clicked); // 直接点击 X 也能销毁线程
    connect(time,&MyTime::my_signal,this,[=](QString datatime){ // 只能在主线程对界面进行操作
        this->ui->lcdNumber->display(datatime);
    });
}
Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    thread->start();
}

void Widget::on_pushButton_2_clicked()
{
         thread->quit();
         time->set_flag(0);
         thread->wait();
}

输出:


六、事件

        由窗口系统或QT自身以及外部外设产生的动作,称为事件。

        比如当按下鼠标或释放鼠标时,会产生鼠标事件,按下键盘时,出现按键事件。

        当某个事件发生时,某个控件要做出响应实现具体业务逻辑,这个操作可以在对应的事件处理函数中实现。


捕捉并处理一个事件的步骤

总目标:所有的事件处理都是通过重写某个事件方法来实现的,可按照如下步骤实现

1. 从逻辑角度判断事件类型,比如你要处理鼠标动作,那肯定是鼠标事件

2. 查找QEvent类的帮助文档,找到enum QEvent::Type中对应的事件,比如QEvent::KeyPress

3. 根据帮助文档,找到相应的事件属于的类,比如QKeyEvent

4. 通过帮助文档的详细介绍部分,找到应该重写的方法,比如QWidget::keyPressEvent()

5. 分析是否可以直接重写事件方法(看能不能修改类的源代码),如果不能,自定义一个类,继承于某个控件类,然后在自定义类中重写其事件方法。

6. void QWidget::​keyPressEvent(QKeyEvent * event),根据具体的需求,通过参数event所属的类,具体分析需要获取的数据,然后进行业务逻辑处理

7. 不需要的事件,交由父类做默认处理(如调用父类的keyPressEvent()方法


案例需求:

1、完善原登录模块。要求用户输入完后按回车键触发登录事件,ESC键退出登录界面

2、界面中添加一个单行输入框,当输入字符为某些特殊字符时候,提示用户并禁止输入。

提示小技巧:QToolTip::showText(this->mapToGlobal(this->pos()), "不能使用特殊字符", this);

代码:

myline.h

#ifndef MYLINE_H
#define MYLINE_H

#include <QWidget>
#include <QtWidgets>

class myline : public QLineEdit
{
    Q_OBJECT
public:
    explicit myline(QWidget *parent = nullptr);
    void keyPressEvent(QKeyEvent *event);
signals:

public slots:
};

#endif // MYLINE_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtWidgets>
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_exit_button_clicked();

private:
    Ui::Widget *ui;
    void keyPressEvent(QKeyEvent *event);
};

#endif // WIDGET_H

myline.cpp

#include "myline.h"

myline::myline(QWidget *parent) : QLineEdit (parent)
{

}

void myline::keyPressEvent(QKeyEvent *event)
{
    qDebug("mylineedit: %x",event->key());
    if(event->key() == Qt::Key_Slash)
        QToolTip::showText(this->mapToGlobal(this->pos()), "不能使用特殊字符", this);
    else{
        QLineEdit::keyPressEvent(event);
    }
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include "myline.h"
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    qDebug("%x",event->key());
    if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter){ // <CR>
        QString name = ui->name_edit->text();
        QString passwd = ui->passwd_edit->text();
        if(name == "wanghan" && passwd == "123456"){
            qDebug()<<"ok"<<endl;
        }
    }

    if(event->key() == Qt::Key_Escape){ // esc
        this->close();
    }
}

void Widget::on_exit_button_clicked()
{
    this->close();
}

输出:

起始页面

输入特殊字符时


七、绘图事件

void QWidget::paintEvent(QPaintEvent *event);

注意:绘图事件不能直接调用, 当窗口发生变化时,QT内部会自动调用绘图事件,或者调用update方法,也会间接调用。


绘图相关的类

//构造方法, 设置绘制设备
QPainter(QPaintDevice *device)
//设置画笔
void setPen(const QPen &pen)
//设置画刷
void setBrush(const QBrush &brush)
//绘制直线
void drawLine(int x1, int y1, int x2, int y2)
//绘制矩形
void drawRect(const QRectF &rectangle)
void drawRect(int x, int y, int width, int height)
//绘制图片  x,y相对绘制设备的原点, 一般直接传0, 0
void drawPixmap(int x, int y, const QPixmap &pixmap)
void drawPixmap(const QRect &rectangle, const QPixmap &pixmap)
void drawPixmap(int x, int y, int width, int height, const QPixmap &pixmap)
//绘制圆形 或者椭圆
void drawEllipse(int x, int y, int width, int height)
//绘制文本
void drawText(int x, int y, const QString &text)

//画笔构造方法
QPen(const QColor &color)
QPen(Qt::PenStyle style)
void setWidth(int width)//设置画刷的宽度

//画刷构造方法
QBrush(const QColor &color, Qt::BrushStyle style = Qt::SolidPattern)
QBrush(Qt::BrushStyle style)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hive基础面试-如何理解复用率的

1. 模型的复用率你们是怎么做的&#xff1f; 简单直白的说就是你的模型复用率如何&#xff0c;在业务方是否认可该模型&#xff0c;也是衡量模型建设的一个标准&#xff0c;复用率数&#xff1a;数仓模型涉及的核心是追求模型的复用和共享&#xff0c;引用系数越高&#xff0c;…

如何使用 Python 开发一个简单的文本数据转换为 Excel 工具

目录 一、准备工作 二、理解文本数据格式 三、开发文本数据转换为Excel工具 读取CSV文件 将DataFrame写入Excel文件 处理其他格式的文本数据 读取纯文本文件&#xff1a; 读取TSV文件&#xff1a; 四、完整代码与工具封装 五、使用工具 六、总结 在数据分析和处理的…

知识中台:提升企业知识管理的智能化水平

在数字化转型的浪潮中&#xff0c;企业知识管理的智能化水平成为提升竞争力的关键。HelpLook知识中台通过集成先进的AI技术&#xff0c;为企业提供了一个智能化的知识管理平台。 一、知识管理智能化的重要性 智能化的知识管理不仅能够提高信息检索的效率&#xff0c;还能通过…

MAC借助终端上传jar包到云服务器

前提&#xff1a;保证工程本地已打包完成&#xff1a;图中路径即为项目的target目录下已准备好的jar包 第一步&#xff1a;打开终端&#xff08;先不要连接自己的服务器&#xff09;&#xff0c;输入下面的上传命令&#xff1a; scp /path/to/local/app.jar username192.168.1…

生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件

我们知道MPSOC或者ZYNQ的启动文件BOOT.BIN 通常由三最少三部分组成 1&#xff0c;FSBL 第一阶段引导加载器 2&#xff0c;BIT流文件 3&#xff0c;用户APP文件 用户使用这个三个文件生成BOOT.BIN时候往往用SDK的用户界面&#xff0c;分别选择这三个文件之后生成。其实这种方…

【机器学习】——朴素贝叶斯模型

&#x1f4bb;博主现有专栏&#xff1a; C51单片机&#xff08;STC89C516&#xff09;&#xff0c;c语言&#xff0c;c&#xff0c;离散数学&#xff0c;算法设计与分析&#xff0c;数据结构&#xff0c;Python&#xff0c;Java基础&#xff0c;MySQL&#xff0c;linux&#xf…

html+js实现图片的放大缩小等比缩放翻转,自动播放切换,顺逆时针旋转

效果图&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>图片预览</title><sty…

数据结构 ——— 快速排序算法的实现(hoare版本)

目录 快速排序的思想 单趟排序逻辑的实现 快速排序算法的实现 快速排序的思想 任取待排序元素序列中的某元素作为基准值&#xff0c;按照该排序码将待排序集合分割成两子序列&#xff0c;左子列中所有元素均小于基准值&#xff0c;右子席列中所有元素均大于基准值&#xff0…

Nmap识别MongoDB 6.0指纹

Nmap识别MongoDB 6.0指纹 朋友反馈一个问题&#xff0c;说使用Nmap扫描MongoDB服务时对于6.0以上的版本默认无法识别到服务版本信息。 如上图所示&#xff0c;对应的VERSION信息是空的&#xff0c;在提示信息中可以看到&#xff0c;官方推荐将指纹信息上传以帮助更新服务指纹&…

论文阅读:A fast, scalable and versatile tool for analysis of single-cell omics data

Zhang, K., Zemke, N.R., Armand, E.J. et al. A fast, scalable and versatile tool for analysis of single-cell omics data. Nat Methods 21, 217–227 (2024). 论文地址&#xff1a;https://doi.org/10.1038/s41592-023-02139-9 代码地址&#xff1a;https://github.com…

飞凌嵌入式旗下教育品牌ElfBoard与西安科技大学共建「科教融合基地」

近日&#xff0c;飞凌嵌入式与西安科技大学共同举办了“科教融合基地”签约揭牌仪式。此次合作旨在深化嵌入式创新人才的培育&#xff0c;加速科技成果的转化应用&#xff0c;标志着双方共同开启了一段校企合作的新篇章。 出席本次签约揭牌仪式的有飞凌嵌入式梁总、高总等一行…

2024年11月21日Github流行趋势

项目名称&#xff1a;twenty 项目维护者&#xff1a;charlesBochet, lucasbordeau, Weiko, FelixMalfait, bosiraphael项目介绍&#xff1a;正在构建一个由社区支持的现代化Salesforce替代品。项目star数&#xff1a;21,798项目fork数&#xff1a;2,347 项目名称&#xff1a;p…

VSCode汉化教程【简洁易懂】

我们安装完成后默认是英文界面。 找到插件选项卡&#xff0c;搜索“Chinese”&#xff0c;找到简体&#xff08;更具你的需要&#xff09;&#xff08;Microsoft提供&#xff09;Install。 安装完成后选择Change Language and Restart。

Leetcode 生命游戏

以下是上述Java代码的算法思想及其逻辑的中文解释&#xff1a; 算法思想 这段代码实现了LeetCode第289题“生命游戏”的解决方案。核心思想是&#xff1a; 利用原地修改的方式&#xff08;in-place&#xff09;存储下一状态的变化&#xff1a; 通过引入额外的状态值&#xff0…

C++【面试重要题目】 只出现一次的数字的集合.

文章目录 前言一、前提要点补充二、题集总结 前言 本篇笔者将会对 cpp 中比较有意思的类型题目进行细致讲解 . 这类题同时也是面试中比较重要的算法题 , 其算法思想需要学者掌握. 以下题目均来自力扣 一、前提要点补充 ● 几个运用运算符 因为笔者介绍的题目均会用到二进制…

麒麟部署一套NFS服务器,用于创建网络文件系统

一、服务端共享目录 在本例中,kyserver01(172.16.200.10)作为客户端,创建一个目录/testdir并挂载共享目录;kyserver02(172.16.200.11)作为服务端,创建一个共享目录/test,设置为读写权限,要求客户端使用root登录时映射为nobody用户、非root登录时保持不变。 服务端启…

VBA技术资料MF228:移动形状并覆盖某单元格区域

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Python 数据分析核心库大全!

&#xff08;欢迎关注我的视频号&#xff09; &#x1f447;我的小册 45章教程:(小白零基础用Python量化股票分析小册) ,原价299&#xff0c;限时特价2杯咖啡&#xff0c;满100人涨10元。 大家好&#xff01;我是菜鸟哥&#xff01; 今天我们来聊点干货&#xff1a;Python 数据…

跨境出海安全:如何防止PayPal账户被风控?

今天咱们聊聊那些让人头疼的事儿——PayPal账户被风控。不少跨境电商商家反馈&#xff0c;我们只是想要安安静静地在网上做个小生意&#xff0c;结果不知道为什么&#xff0c;莫名其妙账户就被冻结了。 但其实每个封禁都是有原因的&#xff0c;今天就来给大家分享分享可能的原…

39页PDF | 毕马威_数据资产运营白皮书(限免下载)

一、前言 《毕马威数据资产运营白皮书》探讨了数据作为新型生产要素在企业数智化转型中的重要性&#xff0c;提出了数据资产运营的“三要素”&#xff08;组织与意识、流程与规范、平台与工具&#xff09;和“四重奏”&#xff08;数据资产盘点、评估、治理、共享&#xff09;…