Qt秋招必知必会(21-30)

21. Qt 样式表

21.1 定义和一般语法

  • Qt 样式表(Qt Style Sheets, QSS)是 Qt 框架中的一种样式表语言,用于设置和定制控件的外观
    • 样式表使用 CSS 语法,可以定义界面元素的属性、颜色、字体等
    • 样式表主要用于 QWidget 及其子类(如 QPushButton、QLineEdit 等),还可以应用于整个应用程序或特定的控件,使得应用程序的界面可以与众不同
    • Qt 还提供了 QStyle 类和 QStyleFactory 类,用于管理系统默认样式和自定义样式
  • 一般语法
    • 可以设置各种属性,如颜色、背景色、字体、边框等
    QPushButton {
        background-color: blue;
        color: white;
        border: 2px solid black;
    }
    /*
        background-color:背景颜色
        color:文本颜色
        border:边框样式
        font:字体设置
        padding:内边距
        margin:外边距
    */
    

21.2 选择器

  • 选择器:可以根据控件的类型、名称、状态等选择控件进行样式设置
    在这里插入图片描述

21.3 子控件

  • 对于一些组合的界面组件,需要对其子控件进行选择,例如 QComboBox 的下拉按钮,或 QSpinBox 的向上、向下按钮。通过选择器的子控件可以对这些界面元素进行显示效果控制
    QComboBox::drop-down {
        image : url(:/images/images/down.bmp)
    }
    
  • Qt 常用子控件
    在这里插入图片描述

21.4 伪状态

  • 选择器可以包含伪状态,使得样式规则只能应用于界面组件的某个状态,这就是一种条件应用规则
    • 伪状态出现在选择器的后面,用一个冒号 : 隔开
    /* 当鼠标移动到 OLineEdit 上方 (hover) 时,改变 QLineEdit 的背景色和前景色 */
    QLineEdit:hover {
        background-color: black;
        color: yellow;
    }
    
    • 可以对伪状态取反,方法是在伪状态前面加一个感叹号 !
    QLineEdit:!read-only {
        background-color: rgb(235, 255, 251);
    }
    
    • 伪状态可以串联使用,相当于逻辑与运算
    QCheckBox:hover:checked {
        color: red;
    }
    
    • 伪状态可以并联使用,相当于逻辑或运算
    QCheckBox:hover, QCheckBox:checked {
        color: red;
    }
    
  • Qt 常见伪状态
    在这里插入图片描述

21.5 使用方式

  • 方式一:在 QT Designer 设计界面中直接用样式表编辑器
    • 这样设计的样式表会保存在窗口的 UI 文件里,创建窗口时会被自动应用
    • 这样设计的样式表对于应用程序是固定的,而且为每个窗口都设计样式表,重复性工作量大
  • 方式二:使用函数 setStyleSheet() 设置样式表
    • 使用 QApplication::setStyleSheet() 函数可以为应用程序设置全局的样式表,使用 QWidget::setStyleSheet() 可以为一个窗口或一个界面组件设置样式
    • 这样将样式表固定在程序中,无法实现界面主题效果的切换
    qApp->setStyleSheet("QLineEdit {
        background-color: gray
    }")
    
  • 方式三:通过程序给主窗口加载 .qss 文件
    • 为了实现界面主题效果的切换,一般将样式表保存为后缀为 .qss 的纯文本文件,然后在程序中打开文件,读取文本内容,再调用函数 setStyleSheet() 应用样式
    QFile file(":/qss/mystyle.qss");
    file.open(QFile::ReadOnly);
    QString styleSheet = QString::fromLatinl(file.readAll());
    qApp->setStyleSheet(styleSheet);
    

样式表使用注意事项

  • 父控件采用样式表设置属性后,该属性会传递到其子控件上,除非子控件使用同样的方法修改属性
  • 如:利用样式表设置父控件最小高度为 x,则子控件的最小高度也为 x,使用 setFixHeight() 修改也无法消除,只能通过样式表重新设置子控件的高度才有效,因此一般只对子控件使用样式设置

22. 修改 QPushButton 的大小,文字颜色等属性

  • 方法一
    • 使用 Qt Designer:可以使用 Qt Designer 来设置 QPushButton 的大小、文字颜色等属性
  • 方法二
    • 使用 Qt 的 API:例如 setMinimumSize()、setMaximumSize()、setStyleSheet() 等
  • 方法三
    • 使用 QSS 语言设置
    QPushButton {
        background-color: blue;
        color: white;
        border: 2px solid black;
    }
    

23. Qt 窗口圆角如何实现

  • 可以使用 Qt 的样式表实现
    QWidget {
        border-radius: 10px;
    }
    
  • 可以使用如下代码来应用样式表
    QFile file("style.qss");  // style.qss 中已写好窗口圆角样式
    file.open(QFile::ReadOnly);
    QString styleSheet = QLatin1String(file.readAll());
    qApp->setStyleSheet(styleSheet);
    

24. Qt 事件机制

24.1 常见 QT 事件类型

  • 按事件的来源,可以将事件划分为 3 类

    • 自生事件(spontaneous event)
      • 是由窗口系统产生的事件,例如 QKeyEvent 事件、QMouseEvent 事件
      • 自生事件会进入系统队列,然后被应用程序的事件循环逐个处理
    • 发布事件(postedevent)
      • 是由 Qt 或应用程序产生的事件,例如 QTimer 定时器发生定时溢出时 Qt 会自动发布 QTimerEvent 事件
      • 应用程序使用静态函数 QCoreApplication::postEvent() 产生发布事件,发布事件会进入 Qt 事件队列,然后由应用程序的事件循环进行处理
    • 发送事件(sent event)
      • 是由 Qt 或应用程序定向发送给某个对象的事件
      • 应用程序使用静态函数 QCoreApplication::sendEvent() 产生发送事件,由对象的 event() 函数直接处理
  • 常见 QT 事件举例

    • 键盘事件: 按键按下和松开
    • 鼠标事件: 鼠标移动,鼠标按键的按下和松开
    • 拖放事件: 用鼠标进行拖放
    • 滚轮事件: 鼠标滚轮滚动
    • 绘屏事件: 重绘屏幕的某些部分
    • 定时事件: 定时器到时
    • 焦点事件: 键盘焦点移动
    • 进入和离开事件: 鼠标移入 widget 之内,或是移出
    • 移动事件: widget 的位置改变
    • 大小改变事件: widget 的大小改变
    • 显示和隐藏事件: widget 显示和隐藏
    • 窗口事件: 窗口是否为当前窗口

24.2 Qt 事件循环

  • 事件循环(Event Loop)是 Qt 中用于处理事件和消息的机制,它负责接收、分发和处理应用程序接收到的事件,事件循环是一个持续运行的循环结构,不断地监听事件并将其传递给对应的事件接收者进行处理
    • 主事件循环通过调用 QCoreApplication::exec() 启动,随着 QCoreApplication::exit() 结束,本地的事件循环可用利用 QEventLoop 构建
    • 事件来源
      • 事件可以来自多种来源,包括用户操作(如鼠标点击、键盘输入)、系统信号(如定时器事件、网络事件)、系统消息(如窗口管理、程序状态变化)等
    • 事件分发
      • 当应用程序接收到事件时,Qt 会将事件排入事件队列中。事件循环会不断地从事件队列中取出事件,并将其发送给对应的事件接收者(信号接收者)进行处理
    • 事件处理
      • 事件接收者可以是应用程序中的窗口部件(QWidget)、控件(QObject)、线程等。每个事件接收者都有一个事件处理函数(event handler),用于接收和处理特定类型的事件
    • 事件类型
      • Qt 中的事件分为系统事件和用户定义事件。系统事件由 Qt 框架负责生成和传递,用户定义事件则是由开发人员自行创建和处理
    • 事件循环机制
      • Qt 的事件循环是通过 QEventLoop 类实现的,它会在事件队列中有事件时进入循环,不断地等待和处理事件。事件循环的存在保证了应用程序能够响应用户输入、系统消息等各种事件
    • 事件优先级
      • 每个事件都有一个优先级,Qt 会按照事件优先级的顺序来处理事件。高优先级的事件会在低优先级事件之前得到处理

24.3 Qt 事件过滤

  • Qt 中的事件过滤器可以用于对某个对象的事件进行拦截和处理,事件过滤器是一个 QObject 对象,它可以安装到任何 QObject 派生类中,并且可以监听该对象的所有事件。当事件发生时,事件过滤器可以拦截并处理该事件,也可以将该事件转发给原始的事件接收者对象进行处理

  • 事件过滤器的处理流程

    • 1、创建一个 QObject 派生类,实现其 eventFilter() 函数,该函数会在事件发生时被调用
    class MyEventFilter : public QObject {
        Q_OBJECT
    public:
        explicit MyEventFilter(QObject *parent = nullptr);
    protected:
        bool eventFilter(QObject *watched,QEvent *event) override;
    };
    
    • 2、在需要监听的对象中,调用 installEventFilter() 函数安装事件过滤器
    MyEventFilter *eventFilter = new MyEventFilter;
    QLabel *label = new QLabel("Hello,World!");
    label->installEventFilter(eventFilter);
    
    • 3、在 eventFilter() 函数中处理事件,可以通过判断事件类型和事件源来对事件进行不同的处理
    bool MyEventFilter::eventFilter(QObject *watched,QEvent *event) {
        if (watched == label && event->type() == QEvent::MouseButtonPress) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
            // 处理鼠标事件
            return true;
        }
        return false;
    }
    
  • Qt 事件机制有几种级别的事件过滤:5 种级别的事件过滤处理办法,以功能从弱到强排列如下

    • 1. 重载特定事件处理函数
      • 最常见的事件过滤办法就是重载 mousePressEvent(),keyPressEvent() 这样的特定事件处理函数
    • 2. 重载 event() 函数
      • 通过重载 event() 函数,可以在事件被特定的事件处理函数处理之前(如 keyPressEvent())处理它,比如,当想改变 tab 键的默认动作时,一般要重载这个函数
      • 在处理一些不常见的事件(如 LayoutDirectionChange)时,evnet() 也很有用,因为这些函数没有相应的特定事件处理函数
      • 当重载 event() 函数时,需要调用父类的 event() 函数来处理不需要处理或是不清楚如何处理的事件
    • 3. 在 Qt 对象上安装事件过滤器
      • 安装事件过滤器有两个步骤:假设要用 A 来监视过滤 B 的事件
      • 首先调用 B 的 installEventFilter(const QOject *obj),以 A 的指针作为参数,这样所有发往 B 的事件都将先由 A 的 eventFilter() 处理
      • 然后,A 要重载 QObject::eventFilter() 函数,在 eventFilter() 中书写对事件进行处理的代码
    • 4. 给 QAppliction 对象安装事件过滤器
      • 一旦给 qApp(每个程序中唯一的 QApplication 对象)装上过滤器,那么所有的事件在发往任何其他的过滤器时,都要先经过当前这个 eventFilter()
      • 在 debug 的时候,这个办法就非常有用,也常常被用来处理失效了的 widget 的鼠标事件,通常这些事件会被 QApplication::notify() 丢掉(在QApplication::notify() 中,是先调用 qApp 的过滤器,再对事件进行分析,以决定是否合并或丢弃)
    • 5. 继承 QApplication 类,并重载 notify() 函数
      • Qt 是用 QApplication::notify() 函数来分发事件的,想要在任何事件过滤器查看任何事件之前先得到这些事件,重载这个函数是唯一的办法
      • 通常来说事件过滤器更好用一些,因为不需要去继承 QApplication 类,而且可以给 QApplication 对象安装任意个数的事件

25. Qt 对话框

  • 文件对话框(QFileDialog)
    • 用于打开和保存文件的对话框类,它可以让用户选择文件的路径和名称,并且支持多种文件格式的过滤
    QString fileName = QFileDialog::getOpenFileName(this, "Open File", QDir::homePath(), "Text Files (*.txt)");
    if(!fileName.isEmpty()) {
        QFile file(fileName);
        if(file.open(QIODevice::ReadOnly)) {
            // 读取文件内容
            file.close();
        }
    }
    
  • 字体对话框(QFontDialog)
    • 用于选择字体的对话框类,它可以让用户选择字体的名称、大小、颜色等属性
    bool ok;
    QFont font = QFontDialog::getFont(&ok, QFont("Helvetica [Cronyx]", 10), this);
    if(ok) {
        // 应用选择的字体
        setFont(font);
    }
    
  • 输入对话框(QInputDialog)
    • 用于输入文本、数字、列表等的对话框类,它可以让用户输入各种类型的数据,并且支持自定义对话框标题、提示信息等
    QString text = QInputDialog::getText(this, "Input Dialog", "Enter your name:", QLineEdit::Normal, "", &ok);
    if(ok && !text.isEmpty()) {
        // 处理用户输入的文本
    }
    
  • 消息对话框(QMessageBox)
    • 用于显示消息、提示、警告等的对话框类,它可以让用户选择不同的按钮选项,并且支持自定义对话框标题、提示信息等
    QMessageBox::StandardButton reply;
    reply = QMessageBox::question(this, "Message Box", "Are you sure to quit?", QMessageBox::Yes | QMessageBox::No);
    if(reply == QMessageBox::Yes) {
        // 处理用户选择
    }
    
    // 显示一个警告框,提示用户用户名或密码错误
    QMessageBox::warning(this, tr("警告"), tr("用户名或密码错误!"), QMessageBox::Yes);
    

26. Qt 中的 show 和 exec 区别

  • show 和 exec 都是用来显示对话框的方法,它们的主要区别在于它们的运行机制和返回值
    • show 方法是在当前线程中显示对话框并立即返回,该方法不会阻塞当前线程,因此当对话框显示后,程序会继续执行后续代码
      • 如果在对话框显示期间需要执行一些其他操作,可以在对话框关闭事件中处理,或者使用 Qt 的事件循环机制(如 QEventLoop)来阻塞程序执行
      • show 方法通常用于显示模态对话框和非模态对话框
    • exec 方法是在当前线程中显示对话框,并且阻塞当前线程,直到用户关闭对话框为止
      • 在执行 exec 方法后,程序会进入一个事件循环(QEventLoop),直到对话框关闭事件被触发。因此,如果需要在对话框关闭之前执行一些其他操作,需要在对话框关闭事件之前处理
      • exec 方法通常用于显示模态对话框

    如果需要在对话框显示期间执行一些其他操作,建议使用 show 方法,如果需要等待用户关闭对话框后再执行其他操作,建议使用 exec 方法

27. Qt 多线程

27.1 Qt 多线程使用方法

  • 方法一:继承 QThread 类
    • 该方法需要定义一个新类,继承自 QThread 类,并重写 run() 函数,run() 函数中包含了需要在新线程中执行的代码,在主线程中创建该类的实例对象,调用 start() 函数启动新线程
    class MyThread : public QThread {
        Q_OBJECT
    public:
        void run() override {
            // 在新线程中执行的代码
        }
    };
    
    MyThread thread;
    thread.start();
    
  • 方法二:继承 QObject 类
    • 使用 QThread 对象继承 QObject 类,该方法需要定义一个新类,继承自 QObject 类,并在该类中定义需要在新线程中执行的槽函数。在主线程中创建 QThread 对象,将新类的实例对象移动到该 QThread 对象所在的线程中,然后启动该 QThread 对象
    class MyObject : public QObject {
        Q_OBJECT
    public slots:
        void doWork() {
            // 在新线程中执行的代码
        }
    };
    
    QThread thread;
    MyObject *obj = new MyObject();
    obj->moveToThread(&thread);
    QObject::connect(&thread, &QThread::started, obj, &MyObject::doWork);
    thread.start();
    
  • 方法三:继承 QRunnable 类
    • 派生于 QRunnable,重写 run() 方法,在 run() 方法里处理其它任务,调用时需要借助 Qt 线程池
    • 这种方法的缺点是:不能使用 Qt 的信号与槽机制,因为 QRunnable 不是继承自 QObject,但这种方法的好处是:可以让 QThreadPool 来管理线程,QThreadPool 会自动清理新建的 QRunnable 对象

27.2 Qt 线程同步方法

  • 1. 互斥量(QMutex)

    QMutex m_Mutex;
    m_Mutex.lock();
    m_Mutex.unlock();
    
  • 2. 互斥锁(QMutexLocker)

    • 从声明处开始(在构造函数中加锁),出了作用域自动解锁(在析构函数中解锁)
    QMutexLocker mutexLocker(&m_Mutex);
    
  • 3. 等待条件(QWaitCondition)

    QWaitCondtion m_WaitCondition; m_WaitConditon.wait(&m_muxtex, time); 
    m_WaitCondition.wakeAll();
    
  • 4. 读写锁(QReadWriteLock)

    • 一个线程试图对一个加了读锁的互斥量进行上读锁,允许
    • 一个线程试图对一个加了读锁的互斥量进行上写锁,阻塞
    • 一个线程试图对一个加了写锁的互斥量进行上读锁,阻塞
    • 一个线程试图对一个加了写锁的互斥量进行上写锁,阻塞
    • 适用情况:需要多次对共享的数据进行读操作的阅读线程

    QReadWriterLock 与 QMutex 相似,除了它对 “read”,“write” 访问进行区别对待。它使得多个读者可以共时访问数据,使用 QReadWriteLock 而不是QMutex,可以使得多线程程序更具有并发性

  • 5.信号量(QSemaphore)

    • 有些互斥量(资源)的数量并不止一个,比如一个电脑安装了 2 个打印机,我已经申请了一个,但是我不能霸占这两个,你来访问的时候如果发现还有空闲的仍然可以申请到的,于是这个互斥量可以分为两部分,已使用和未使用
  • 6.QReadLocker 便利类和 QWriteLocker 便利类对 QReadWriteLock 进行加解锁

27.3 Qthread 和 QtConcurrent 对比

  • QThread 可以使用信号和槽机制,而 QtConcurrent 不支持
  • QThread 可以设置线程优先级,而 QtConcurrent 不支持
  • QThread 可以实现跨平台多线程,而 QtConcurrent 只能在支持 C++11 的平台上实现
  • QThread 可以实现更复杂的多线程任务,而 QtConcurrent 只能实现简单的多线程任务

28. Qt 网络通信

28.1 Qt 中 TCP/UDP 网络通信流程

  • 1. 服务器端的创建和监听

    • 服务器端首先需要创建一个 QTcpServer 或 QUdpSocket 对象,用于监听客户端的连接或接收数据。创建时需要指定端口号和 IP 地址(如果有多个网卡,则需要指定监听的网卡地址)。然后调用 listen() 函数开始监听客户端的连接或数据包的到来
  • 2. 客户端的连接或数据发送

    • 客户端需要创建一个 QTcpSocket 或 QUdpSocket 对象,用于连接服务器或发送数据包
    • 对于 TCP 通信,客户端需要调用 connectToHost() 函数连接服务器
    • 对于 UDP 通信,客户端可以直接使用 writeDatagram() 函数发送数据包
  • 3. 服务器端的响应和数据处理

    • 当客户端连接到服务器或发送数据包时,服务器端会触发相应的信号(如 newConnection()、readyRead() 等),在相应的槽函数中进行响应和数据处理
    • 对于 TCP 通信,服务器端需要在 newConnection() 槽函数中调用 nextPendingConnection() 函数获取客户端的 QTcpSocket 对象,然后在客户端的 QTcpSocket 对象上调用 read() 函数读取数据
    • 对于 UDP 通信,服务器端可以直接在 readyRead() 槽函数中调用 readDatagram() 函数读取数据包
  • 4. 客户端的数据接收和响应

    • 当客户端连接到服务器或发送数据包时,客户端会触发相应的信号(如 connected()、readyRead() 等),在相应的槽函数中进行数据接收和响应
    • 对于 TCP 通信,客户端需要在 connected() 槽函数中调用 write() 函数发送数据,然后在 readyRead() 槽函数中调用 read() 函数读取服务器端的响应数据
    • 对于 UDP 通信,客户端可以直接在 readyRead() 槽函数中调用 readDatagram() 函数读取服务器端的响应数据包
  • 5. 断开连接和清理资源

    • 当通信完成或出现错误时,需要断开连接并清理资源
    • 对于 TCP 通信,可以在客户端或服务器端的 QTcpSocket 对象上调用 disconnectFromHost() 函数或 close() 函数断开连接,并在 socketDisconnected() 槽函数中清理资源
    • 对于 UDP 通信,不需要显式地断开连接,系统会自动管理资源

28.2 Qt 网络应用层编程

Qt4 以前的版本提供 QHttp 类用于构建 HTTP 客户端,提供 QFtp 类用于开发 FTP 客户端。从 Qt5 开始,已经不再分别提供 QHttp 类、QFtp 类,应用层的编程使用 QNetworkRequest、QNetworkReply 和 QNetworkAccessManager 这几个高层次的类,它们提供更加简单和强大的接口

  • 网络请求由 QNetworkRequest 类来表示,作为与请求有关的信息的统一容器,在创建请求对象时指定的 URL 决定了请求使用的协议,目前支待 HTTP FTP 和本地文件 URLs 上传和下载
  • QNetworkAceessManager 类用于协调网络操作,每当创建一个请求后,该类用来调度它,并发送信号以报告进度
  • 而对于网络请求的应答则使用 QNetworkReply 类表示,它会在请求被完成调度时由 QNetworkAccessManager 类创建

29. Qt 文件操作

29.1 Qt 如何读写文件

  • 读文件
    // 首先使用 QFile 类打开要读取的文件
    QFile file("test.txt");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;
    
    // 然后使用 QTextStream 类对文件进行读取
    QTextStream in(&file);
    // 通过while循环,每次读取一行数据,然后进行处理
    while (!in.atEnd()) {
        QString line = in.readLine();
        // 处理每一行数据
    }
    // 最后关闭文件
    file.close();
    
  • 写文件
    // 首先使用 QFile 类打开要写入的文件
    QFile file("test.txt");
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        return;
    // 然后使用 QTextStream 类对文件进行写入
    QTextStream out(&file);
    // 通过向 QTextStream 对象中写入数据,可以将数据写入文件中
    out << "Hello world" << endl;
    out << "Qt is awesome" << endl;
    // 最后关闭文件
    file.close();
    

在进行文件读写操作时,需要确保文件路径正确,并且文件权限足够。同时,需要根据具体情况使用不同的打开模式,例如只读模式、只写模式、追加模式等

29.2 Qt 常用文件格式处理方式

  • 1. 操作 INI 文件
    • INI 文件是一种常用的配置文件格式,在 Qt 中可以通过 QSettings 类来读写 INI 文件
    QSettings settings("myApp.ini", QSettings::IniFormat);
    // 写入配置项
    settings.setValue("General/Name", "Tom");
    settings.setValue("General/Age", 20);
    // 读取配置项
    QString name = settings.value("General/Name").toString();
    int age = settings.value("General/Age").toInt();
    
  • 2. 操作 JSON 文件
    • JSON 是一种轻量级数据交换格式,Qt 中可通过 QJsonDocument 类和 QJsonObject 类来读写 JSON 文件
    // 读取 JSON 文件
    QFile file("data.json");
    if (file.open(QIODevice::ReadOnly)) {
        QJsonParseError error;
        QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
        if (error.error == QJsonParseError::NoError && doc.isObject()) {
            QJsonObject obj = doc.object();
            QString name = obj.value("name").toString();
            int age = obj.value("age").toInt();
        }
        file.close();
    }
    // 写入 JSON 文件
    QJsonObject obj;
    obj.insert("name", "Tom");
    obj.insert("age", 20);
    QJsonDocument doc(obj);
    QFile file("data.json");
    if (file.open(QIODevice::WriteOnly)) {
        file.write(doc.toJson());
        file.close();
    }
    
  • 3. 操作 XML 文件
    • XML 是一种常用的文本格式,用于表示结构化的数据,Qt 中可通过 QXmlStreamReader 类和 QXmlStreamWriter 类来读写 XML 文件
    // 读取 XML 文件
    QFile file("data.xml");
    if (file.open(QIODevice::ReadOnly)) {
        QXmlStreamReader reader(&file);
        while (!reader.atEnd()) {
            reader.readNext();
            if (reader.isStartElement() && reader.name() == "person") {
                QString name = reader.attributes().value("name").toString();
                int age = reader.attributes().value("age").toInt();
                // 处理读取到的数据
            }
        }
        file.close();
    }
    // 写入 XML 文件
    QFile file("data.xml");
    if (file.open(QIODevice::WriteOnly)) {
        QXmlStreamWriter writer(&file);
        writer.setAutoFormatting(true);
        writer.writeStartDocument();
        writer.writeStartElement("persons");
        writer.writeStartElement("person");
        writer.writeAttribute("name", "Tom");
        writer.writeAttribute("age", "20");
        writer.writeEndElement();
        writer.writeEndElement();
        writer.writeEndDocument();
        file.close();
    }
    

30. QDataStream 和 QTextStream 区别

  • Qt 中的数据流(QDataStream)和文件流(QTextStream)都是用于读写数据的流类,但它们有以下区别
    • 数据类型
      • 数据流(QDataStream)支持 Qt 中的所有基本数据类型和自定义类型,如 QString、QByteArray 等
      • 文件流(QTextStream)只能读写文本数据,不支持二进制数据
    • 数据格式
      • 数据流(QDataStream)是二进制格式,可以直接读写二进制数据
      • 文件流(QTextStream)是文本格式,只能读写文本数据,对于二进制数据需要进行编码和解码
    • 数据编码
      • 文件流(QTextStream)默认使用 Unicode 编码,可以通过设置不同的编码格式来读写不同的文本数据
      • 数据流(QDataStream)不需要进行编码,它直接以二进制形式读写数据
    • 应用场景
      • 数据流(QDataStream)适用于读写二进制数据,例如读写文件、网络传输等场景
      • 文件流(QTextStream)适用于读写文本数据,例如读写配置文件、日志文件等场景
  • 15
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值