嵌入式学习-QT-Day07

server/2024/12/26 20:54:24/

嵌入式学习-QT-Day07

七、文件IO

1、QFileDialog文件对话框

2、QFileInfo文件信息类

3、QFile文件读写类(重点)

4、UI与耗时操作

5、QThread线程类

5.1 复现程序未响应

5.2 创建并启动一个子线程

5.3 异步刷新

5.4 线程停止

6、数据持久化

七、文件IO

1、QFileDialog文件对话框

与QMessageBox一样,QFileDialog也继承QDialog类,直接使用静态成员函数弹窗,弹窗的结果(选择的文件路径)通过函数返回值获取。

// 获取一个打开或保存的文件路径
// 参数1:父对象
// 参数2:即windowTitle属性(标题)
// 参数3:在那个目录中打开,默认值表示项目的工作目录
// 参数4:文件格式过滤器
// 返回值:选择的文件路径,如果选择失败,返回空字符
QString QFileDialog::getOpenFileName(
    QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString())[static]QString QFileDialog::getSaveFileName(
    QWidget * parent = 0, const QString & caption = QString(), const QString & dir = QString(), const QString & filter = QString(), 
)[static]

需要注意的是,QFileDialog只是一个窗口类,本身不具备任何IO的能力。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QFileDialog>
#include <QMessageBox>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;
    QString readPath;
    QString writePath;private slots:
    void btnClickedSlot();
};#endif // DIALOG_H

dilaog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    connect(ui->pushButtonOpen,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));    connect(ui->pushButtonSave,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));}Dialog::~Dialog()
{
    delete ui;
}void Dialog::btnClickedSlot()
{
    if(ui->pushButtonOpen == sender())
    {
        QString filter = "所有文件(*.*);;Qt(*.cpp *.h *.ui *.pro)";
        QString path = QFileDialog::getOpenFileName(this,"打开","D:/",filter);
        if(path != "")
        {
            ui->textBrowserOpen->append(path);
            readPath = path;
        }
        else if(readPath == "")
        {
            // 弹窗
            QMessageBox::warning(this,"警告","请选择要打开的文件");
        }    }
    else if(ui->pushButtonSave == sender())
    {
        QString filter = "所有文件(*.*);;Qt(*.cpp *.h *.ui *.pro)";
        QString path = QFileDialog::getSaveFileName(this,"保存","D:/",filter);
        if(path != "")
        {
            ui->textBrowserSave->append(path);
            writePath = path;
        }
        else if(writePath == "")
        {
            // 弹窗
            QMessageBox::warning(this,"警告","请选择要保存的文件");
        }
    }
    else
    {    }
}

2、QFileInfo文件信息类

只需要创建出对象后,通过各种成员函数直接获取文件信息。

// 构造函数
// 参数为文件路径,如果文件非法,仍然可以创建出QFileInfo对象
QFileInfo::​QFileInfo(const QString & file)
// 判断文件是否存在
// 如果存在返回ture,不存在返回false
bool QFileInfo::​exists() const
// 返回基础文件名,不包含后缀
QString QFileInfo::​baseName() const
// 返回文件可读性,true可读,false不可读
bool QFileInfo::​isReadable() const

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QFileDialog>
#include <QMessageBox>
#include <QFileInfo>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
    void printFileInfo();private:
    Ui::Dialog *ui;
    QString readPath;
    QString writePath;private slots:
    void btnClickedSlot();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    connect(ui->pushButtonOpen,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));    connect(ui->pushButtonSave,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
}Dialog::~Dialog()
{
    delete ui;
}void Dialog::printFileInfo()
{
    // 创建文件信息对象
    QFileInfo fileInfo(readPath);
    if(!fileInfo.exists())
    {
        return;
    }    // 获取文件大小
    qint64 fileSize = fileInfo.size();
    QString text = QString::number(fileSize);
    text.prepend("文件大小:").append("字节");
    ui->textBrowserOpen->append(text);    // 获取文件名称
    text = fileInfo.baseName();
    text.prepend("文件名称:");
    ui->textBrowserOpen->append(text);    // 获取文件可读性
    bool result = fileInfo.isReadable();
    if(result)
    {
        ui->textBrowserOpen->append("文件可读!!");
    }
    else
    {
        ui->textBrowserOpen->append("文件不可读!!");
    }
}void Dialog::btnClickedSlot()
{
    if(ui->pushButtonOpen == sender())
    {
        QString filter = "所有文件(*.*);;Qt(*.cpp *.h *.ui *.pro)";
        QString path = QFileDialog::getOpenFileName(this,"打开","D:/",filter);
        if(path != "")
        {
            ui->textBrowserOpen->append(path);
            readPath = path;
            printFileInfo();
        }
        else if(readPath == "")
        {
            // 弹窗
            QMessageBox::warning(this,"警告","请选择要打开的文件");
        }    }
    else if(ui->pushButtonSave == sender())
    {
        QString filter = "所有文件(*.*);;Qt(*.cpp *.h *.ui *.pro)";
        QString path = QFileDialog::getSaveFileName(this,"保存","D:/",filter);
        if(path != "")
        {
            ui->textBrowserSave->append(path);
            writePath = path;
        }
        else if(writePath == "")
        {
            // 弹窗
            QMessageBox::warning(this,"警告","请选择要保存的文件");
        }
    }
    else
    {    }
}

3、QFile文件读写类(重点)

在Qt中所有IO都继承自QIODevice类,QIODevice类中规定了最基础的IO相关的接口。这些接口虽然在不同的派生类中可能实现有所区别,但是调用方式一致。

// 构造函数
// 参数为文件路径,如果是非法路径,也能创建出QFile对象,但是不能正常IO输出输入操作。
QFile::​QFile(const QString & name)
// 判断QFile对应的文件是否存在
bool QFile::​exists() const
// 打开数据流
// 参数为打开的模式、只读模式、只写模式、读写模式等等。
// 返回值为打开的结果
bool QIODevice::​open(OpenMode mode)[virtual]
// 是否读到文件尾部
bool QIODevice::​atEnd() const
// 读取最大长度为maxSize个的字节到返回值中
QByteArray QIODevice::​read(qint64 maxSize)
// 构造函数,QByteArray是Qt中常用的数组
// 构造一个空字节数组
QByteArray::​QByteArray()
// 写出数据
// 参数为写出的内容
// 返回值为实际的数据写出的字节数,出错返回-1
qint64 QIODevice::​write(const QByteArray & byteArray)

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QFileDialog>
#include <QMessageBox>
#include <QFileInfo>
#include <QFile>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
    void printFileInfo();
    void copy();private:
    Ui::Dialog *ui;
    QString readPath;
    QString writePath;private slots:
    void btnClickedSlot();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    connect(ui->pushButtonOpen,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));    connect(ui->pushButtonSave,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));    connect(ui->pushButtonCopy,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
}Dialog::~Dialog()
{
    delete ui;
}void Dialog::printFileInfo()
{
    // 创建文件信息对象
    QFileInfo fileInfo(readPath);
    if(!fileInfo.exists())
    {
        return;
    }    // 获取文件大小
    qint64 fileSize = fileInfo.size();
    QString text = QString::number(fileSize);
    text.prepend("文件大小:").append("字节");
    ui->textBrowserOpen->append(text);    // 获取文件名称
    text = fileInfo.baseName();
    text.prepend("文件名称:");
    ui->textBrowserOpen->append(text);    // 获取文件可读性
    bool result = fileInfo.isReadable();
    if(result)
    {
        ui->textBrowserOpen->append("文件可读!!");
    }
    else
    {
        ui->textBrowserOpen->append("文件不可读!!");
    }
}void Dialog::copy()
{
    if(readPath == "")
    {
        QMessageBox::warning(this,"警告","请选择要读取的文件");
        return;
    }    if(writePath == "")
    {
        QMessageBox::warning(this,"警告","请选择要写入的文件路径");
        return;
    }
    // 正式拷贝时屏蔽拷贝按钮
    ui->pushButtonCopy->setEnabled(false);    // 创建QFile对象
    QFile readFile(readPath);
    QFile writeFile(writePath);    // 打开文件流
    readFile.open(QIODevice::ReadOnly); // 只读模式
    writeFile.open(QIODevice::WriteOnly);   // 只写模式    // 添加进度条效果
    qint64 totalSize = readFile.size(); // 获取文件总大小
    qint64 hasRead = 0; // 已经读写的大小    QByteArray array;   // 字节数组类对象
    while(!readFile.atEnd())    // 判断是否读到文件尾部
    {
        array = readFile.read(2048);    // 每次读取2kb
        qint64 writeRet = writeFile.write(array); // 写出数据,返回值为本次写出的大小
        if(writeRet == -1)  // 如果写出函数的返回值为-1,表示写出失败
        {
            QMessageBox::critical(this,"错误","文件拷贝失败");            // 清空缓冲区
            writeFile.flush();            // 关闭数据流
            readFile.close();
            writeFile.close();
            // 拷贝失败时,解除按钮的屏蔽效果
            ui->pushButtonCopy->setEnabled(true);
            return;
        }
        // 将写出的数据设置给进度条
        hasRead += writeRet;
        int per = hasRead*100 / totalSize;    // 计算百分比
        ui->progressBar->setValue(per); // 设置给进度条
    }
    // 清空缓冲区
    writeFile.flush();    // 关闭数据流
    readFile.close();
    writeFile.close();
    // 拷贝完成时,解除按钮屏蔽效果
    ui->pushButtonCopy->setEnabled(true);
    // 拷贝完成提示框
    QMessageBox::information(this,"提示","拷贝完成");
}void Dialog::btnClickedSlot()
{
    if(ui->pushButtonOpen == sender())
    {
        QString filter = "所有文件(*.*);;Qt(*.cpp *.h *.ui *.pro)";
        QString path = QFileDialog::getOpenFileName(this,"打开","D:/",filter);
        if(path != "")
        {
            ui->textBrowserOpen->append(path);
            readPath = path;
            printFileInfo();
        }
        else if(readPath == "")
        {
            // 弹窗
            QMessageBox::warning(this,"警告","请选择要打开的文件");
        }    }
    else if(ui->pushButtonSave == sender())
    {
        QString filter = "所有文件(*.*);;Qt(*.cpp *.h *.ui *.pro)";
        QString path = QFileDialog::getSaveFileName(this,"保存","D:/",filter);
        if(path != "")
        {
            ui->textBrowserSave->append(path);
            writePath = path;
        }
        else if(writePath == "")
        {
            // 弹窗
            QMessageBox::warning(this,"警告","请选择要保存的文件");
        }
    }
    else if(ui->pushButtonCopy == sender())
    {
        copy();
    }
    else
    {    }
}

【思考】上面的代码有没有问题?

当拷贝大文件时,会出现程序卡顿,如果尝试关闭,则触发:

4、UI与耗时操作

在默认情况下,Qt的项目是单线程的,这个自带的线程用于处理程序的主要任务和UI交互,也被称为主线程或者UI线程。

如果在主线程中执行耗时操作(IO或者复杂算法)会导致主线程原本执行的操作被阻塞,设置无法关闭,形成“假死”现象。

当操作系统发现某个进程无法正常关闭时,会弹出程序未响应窗口引导用于是否选择强制关闭当前进程。

解决方式是使用多线程。

5、QThread线程类

5.1 复现程序未响应

QThread类是Qt的线程类,可以使用下面的函数模拟耗时操作。

// 强制线程休眠msecs个毫秒
void QThread::​msleep(unsigned long msecs)[static]

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QThread>
#include <QDebug>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;private slots:
    void btnSleepClickedSlot();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    connect(ui->pushButtonSleep,SIGNAL(clicked()),
            this,SLOT(btnSleepClickedSlot()));    connect(ui->pushButtonClose,SIGNAL(clicked()),
            this,SLOT(close()));
}Dialog::~Dialog()
{
    delete ui;
}void Dialog::btnSleepClickedSlot()
{
    qDebug() << "睡眠开始";
    QThread::msleep(10000);
    qDebug() << "睡眠结束";
}

5.2 创建并启动一个子线程

主线程以外的线程都是子线程,子线程不能执行主线程的ui操作,只能执行耗时操作。

下面是创建并启动一个自定义线程的步骤:

在Qt Creator中选中项目名称,鼠标右键,点击“添加新文件”。

在弹出的窗口中,先设置类名,然后在选择基类名称QObject,最后点击“下一步”。

在项目管理界面, 直接点击完成过,可以看到线程类的文件已经创建。

选择新建的头文件,把继承的QObject更改为QThread

选择新建的.CPP文件,把透传构造的QObject更改为QThread

在自定义线程类中,覆盖基类QThread的run函数。

// 此函数是子线程的执行的起始点,也是子线程的结束点。
void QThread::​run()[virtual]
  1. 在run函数的函数体中编写子线程要执行的耗时操作
  2. 创建自定义子线程对象,并调用start函数启动子线程。
// 启动子线程,启动后会执行run
// 参数:线程调度优先级,默认是与父线程相同优先级
void QThread::​start(Priority priority = InheritPriority)

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QThread>
#include <QDebug>
#include "mythread.h"namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;private slots:
    void btnSleepClickedSlot();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    connect(ui->pushButtonSleep,SIGNAL(clicked()),
            this,SLOT(btnSleepClickedSlot()));    connect(ui->pushButtonClose,SIGNAL(clicked()),
            this,SLOT(close()));
}Dialog::~Dialog()
{
    delete ui;
}void Dialog::btnSleepClickedSlot()
{
    // 创建子线程并启动
    MyThread *mt = new MyThread(this);
    mt->start();
}

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>
#include <QDebug>class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = 0);
    ~MyThread();    void run();
signals:public slots:
};#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"MyThread::MyThread(QObject *parent) : QThread(parent)
{}MyThread::~MyThread()
{}void MyThread::run()
{
    qDebug() << "睡眠开始";
    QThread::msleep(10000);
    qDebug() << "睡眠结束";
}

5.3 异步刷新

在实际开发中,两个线程不可能毫无关系的前提下各干各的 ,最常见的情况是主线程分配一个耗时的任务给子线程,子线程需要把耗时任务的执行情况反馈给主线程。主线程刷新子线程的耗时操作,并展示对应的UI效果。

【例如】:子线程执行文件拷贝,主线程显示拷贝的进度。

通常子线程是主线程对象的子对象,因此异步刷新就是对象通信的问题,使用信号槽解决。

咱们写一个简单的例子,一个伪拷贝的案例,使用for循环加睡眠,模拟文件拷贝的功能。

今天晚上的作业:实现真正的拷贝功能。

Dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QMessageBox>
#include "mythread.h"namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;private slots:
    void btnClickedSlot();
    void valueSlot(int);
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);    connect(ui->pushButton,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
}Dialog::~Dialog()
{
    delete ui;
}void Dialog::btnClickedSlot()
{
    ui->pushButton->setEnabled(false);
    MyThread *mt = new MyThread(this);    connect(mt,SIGNAL(valueSignal(int)),
            this,SLOT(valueSlot(int)));
    // 启动子线程
    mt->start();
}void Dialog::valueSlot(int value)
{
    ui->progressBar->setValue(value);
    if(value == 100)
    {
        ui->pushButton->setEnabled(true);
        QMessageBox::information(this,"提示","拷贝完成!!");
    }
}

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = 0);
    ~MyThread();    void run();signals:
    void valueSignal(int);public slots:
};#endif // MYTHREAD_H

myThread.cpp

#include "mythread.h"MyThread::MyThread(QObject *parent) : QThread(parent)
{}MyThread::~MyThread()
{}void MyThread::run()
{
    for(int i = 0; i <= 100; i++)
    {
        QThread::msleep(100);
        emit valueSignal(i);
    }
}

进度条到100时,输出提示框。(问题:频繁抖动窗口,会出现焦点抢夺的问题,导致卡死,解决使用hide函数,来隐藏主窗口)

5.4 线程停止

子线程往往执行耗时操作,耗时任务往往又伴随着循环,因此并不建议使用粗暴的方式直接停止线程,因为强行停止线程会导致耗时资源无法回收等问题。

可以通过给循环设置标志位的方式使线程停止。

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QMessageBox>
#include "mythread.h"namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;
    MyThread *mt;private slots:
    void btnClickedSlot();
    void valueSlot(int);
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);    connect(ui->pushButton,SIGNAL(clicked()),
            this,SLOT(btnClickedSlot()));
}Dialog::~Dialog()
{
    delete ui;
}void Dialog::btnClickedSlot()
{
    if(ui->pushButton->text() == "开始拷贝")
    {
        mt = new MyThread(this);        connect(mt,SIGNAL(valueSignal(int)),
                this,SLOT(valueSlot(int)));
        // 启动子线程
        mt->start();        ui->pushButton->setText("停止拷贝");
    }
    else if(ui->pushButton->text() == "停止拷贝")
    {
        ui->pushButton->setText("开始拷贝");
        mt->setRunningState(false);
    }}void Dialog::valueSlot(int value)
{
    ui->progressBar->setValue(value);
    if(value == 100)
    {
        this->hide();   // 隐藏主窗口,只是看不到
        this->show();   // 显示主窗口
        QMessageBox::information(this,"提示","拷贝完成!!");
    }
}

myThread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>
#include <QDebug>class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = 0);
    ~MyThread();    void run();    bool getRunningState() const;
    void setRunningState(bool value);private:
    bool runningState;  // 状态标志signals:
    void valueSignal(int);public slots:
};#endif // MYTHREAD_H

myThread.cpp

#include "mythread.h"MyThread::MyThread(QObject *parent) : QThread(parent)
{
    runningState = true;
}MyThread::~MyThread()
{}void MyThread::run()
{
    for(int i = 0; i <= 100 && runningState; i++)
    {
        QThread::msleep(100);
        emit valueSignal(i);
    }    qDebug() << "资源释放成功";
}bool MyThread::getRunningState() const
{
    return runningState;
}void MyThread::setRunningState(bool value)
{
    runningState = value;
}

6、数据持久化

数据持久化:是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。

之前说过的数据库就是一种数据持久化的方式,虽然嵌入式使用的SQLite数据库已经是轻量级数据库了,但是相对于其他技术,还是略显冗余。

Qt中提供比数据库更轻巧的数据持久化的方式——QSettings

// 构造函数
// 参数1:存储文件的名称,默认为构建目录
// 参数2:存储格式(.ini)
// 参数3:父对象
QSettings::​QSettings(const QString & fileName, Format format, QObject * parent = 0)
// 设置INI文件的编码,建议使用UTF-8
// 编码字符串
void QSettings::​setIniCodec(const char * codecName)
// 开始存储,同类型建议使用此函数,以数组的方式进行存储
// 参数为数组的名称
void QSettings::​beginWriteArray(const QString & prefix, int size = -1)
// 以 “组”的方式进行存储,不同类型建议使用此函数(相同类型也可以,但是性能不如上面好)
// 参数:“组”的名称
void QSettings::​beginGroup(const QString & prefix)
// 在“组”中添加键值对(组和数组都用这个函数)
// 参数1:键
// 参数2:值
void QSettings::​setValue(const QString & key, const QVariant & value)
// 结束数组的存储
void QSettings::​endArray()
// 结束组的存储
void QSettings::​endGroup()
// 根据键获取值
// 参数1:键
// 参数2:如果取出失败的默认值
// 返回值:取出的值
QVariant QSettings::​value(const QString & key, const QVariant & defaultValue = QVariant()) const

dialog.h

#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QSettings>namespace Ui {
class Dialog;
}class Dialog : public QDialog
{
    Q_OBJECTpublic:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();private:
    Ui::Dialog *ui;    void load();private slots:
    void save();
};#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include "ui_dialog.h"Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);    load();
    connect(ui->pushButton,SIGNAL(clicked()),
            this,SLOT(save()));
}Dialog::~Dialog()
{
    delete ui;
}// 读取
void Dialog::load()
{
    // 创建一个临时使用的QSettings对象
    QSettings setting("config.ini",QSettings::IniFormat);    // 设置文件编码UTF-8
    setting.setIniCodec("UTF-8");    // 开始以组的方式读取数据
    setting.beginGroup("24081");    // 开始读数据
    QString name = setting.value("name").toString();
    ui->lineEdit->setText(name);
    QString text = setting.value("gender").toString();
    ui->comboBox->setCurrentText(text);
    int age = setting.value("age").toInt();
    ui->spinBox->setValue(age);    // 结束组
    setting.endGroup();
}// 存储
void Dialog::save()
{
    // 创建一个临时使用的QSettings对象
    QSettings setting("config.ini",QSettings::IniFormat);    // 设置文件编码 UTF-8
    setting.setIniCodec("UTF-8");    // 开始以组的方式存储数据
    setting.beginGroup("24081");    // 开始写数据
    setting.setValue("name",ui->lineEdit->text());
    setting.setValue("gender",ui->comboBox->currentText());
    setting.setValue("age",ui->spinBox->value());    // 结束组
    setting.endGroup();
}

http://www.ppmy.cn/server/153428.html

相关文章

GitLab的安装和使用

1.GitLab 环境说明 系统版本 CentOS 7.2 x86_64 软件版本 gitlab-ce-10.8.4 GitLab 是一个用于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xff0c;并在此基础上搭建起来的web服务。可通过Web界面进行访问公开的或者私人项目。它拥有与Github类似的功能…

Jmeter录制https请求

jmeter 5.5版本&#xff0c;chrome浏览器 1、首先添加Test Plan-Thread Group-HTTP(S) Test Script Recorder 2、设置HTTP(S) Test Script Recorder界面的Port&#xff08;监听端口&#xff0c;设置浏览器代理时需要与这里保持一致&#xff09;、HTPS Domains&#xff08;录制…

【华为OD-E卷-取出尽量少的球 100分(python、java、c++、js、c)】

【华为OD-E卷-取出尽量少的球 200分&#xff08;python、java、c、js、c&#xff09;】 题目 某部门开展 Family Day 开放日活动&#xff0c;其中有个从桶里取球的游戏&#xff0c;游戏规则如下&#xff1a; 有 N 个容量一样的小桶等距排开&#xff0c;且每个小桶都默认装了数…

小程序租赁系统开发指南与实现策略

内容概要 在如今这个快节奏的时代&#xff0c;小程序租赁系统的开发正逐渐成为许多商家提升服务质量与效率的重要选择。在设计这样一个系统时&#xff0c;首先要明白它的核心目标&#xff1a;便捷、安全。用户希望在最短的时间内找到需要的物品&#xff0c;而商家则希望通过这…

使用Excel制作通达信自定义外部数据,安排!!!

Excel相信大家电脑上都有这个工具&#xff0c;相比敲编程代码&#xff0c;用这个去做自定义数据对大多数人&#xff0c;应该是比较友好的。自定义数据分为外部序列数据&#xff0c;看了一下内容理解起来比较多&#xff0c;分两期给大家介绍。为了照顾电脑基础薄弱的朋友&#x…

一起学Git【第二节:创建版本库】

创建库 这个库相当于一个目录&#xff0c;目录中的文件都被Git管理&#xff0c;会记录每个文件的修改删除和添加工作&#xff0c;便于之后随时跟踪历史记录还原到之前的某一版本。如何创建库呢&#xff1f;有两种方式&#xff0c;本地创建库和云端克隆一个库。 1.本地创建库 …

37.2 prometheus分析接口源码讲解

本节重点介绍 : 获取配置文件 config获取运行信息 runtimeinfo编译的信息 buildinfotsdb统计信息 tsdbwalreplay的信息target统计信息获取metrics的元信息 状态信息相关 获取配置文件 path /api/v1/status/config代码位置 D:\go_path\src\github.com\prometheus\prometheus…

1. 深度学习介绍

深度学习关系 如下图&#xff0c;深度学习是机器学习的一部分 深度学习怎么个“深度”法 传统机器学习不能主动进行特征学习&#xff0c;需要人为进行特征工程提取特征&#xff0c;所以只是浅层学习。 而深度学习可以自动学习特征。 也就是说&#xff1a;深度学习传动机器学…