qt 学习笔记(QSettings读写ini文件,new出来的控件的qss不继承到子控件,QVariant使用及存取各种类型,信号传递图片、自定义结构体、QVariant格式、传递类对象、传递控件)

44 篇文章 8 订阅
1、Qt中使用QSettings读写ini文件:
(1)ini文件基本格式:

使用ini文件来存储软件中的一些参数。

[cameraSettings]

ipAddress=192.168.1.5
ifExpose=1
exposeTime=200

ini文件格式基本由节、键、值组成。

可以通过记事本保存为ini格式创建。或者直接通过下面的方法创建ini,构建QSettings对象时,如果ini文件不存在,就会自动在该目录下创建这个ini文件。

(2)基本的方法和使用:

mainwindow.h中引入QSettings

#include <QSettings>

QSettings的一些方法,参考自:https://www.cnblogs.com/chengkeke/p/5417427.html

//创建QSettings对象
QSettings(const QString & organization, const QString & application = QString(), QObject * parent = 0)   

//读取数据,cameraSettings节的exposeTime的值,由于读出为QVariant,所以按照格式转化一下
int exposeTime= settings.value("cameraSettings/exposeTime").toInt();  
// 如果key不存在,则返回 null QVariant(可以被转化为整数0)
//读取数据的时候,可以传递第二个参数,给定新的value。
int exposeTime= settings.value("cameraSettings/exposeTime", 80).toInt();

//写入数据
settings.setValue("cameraSettings/exposeTime", 68);

创建QSettings对象时:

//其实可以设置ini文件的路径到当前目录的,用了几次 ./ 都没能定位到当前目录就放弃了。
//其实可以使用 QDir 定位当前目录的,只是我比较懒,不要学我。 
QSettings *config = new QSettings ("C:/Users/Administrator/Documents/vision_1/source/cameraSettings.ini",QSettings::IniFormat);

QSettings::IniFormat表示读取方式为存储在INI文件中的设置。

其他格式:
QSettings::InvalidFormat registerFormat()返回的值。
QSettings::NativeFormat 使用平台最合适的存储格式设置。

(3)读取数据:

使用时:(下面以读取上面给出的ini文件中的键值对为例)

QSettings *config = new QSettings ("C:/Users/Administrator/Documents/vision_1/source/cameraSettings.ini",QSettings::IniFormat);
qDebug()<<config;   //返回config内存地址
exposeTime = config->value("cameraSettings/exposeTime",300).toInt();  //读取失败则返回300
delete config;   //释放内存
qDebug()<<"exposeTime:"<<exposeTime;   //输出

输出:
在这里插入图片描述
除此之外,还可以通过beginGroupendGroup来指定节点:

QSettings *config = new QSettings ("C:/Users/Administrator/Documents/vision_1/source/cameraSettings.ini",QSettings::IniFormat);
config->beginGroup("cameraSettings");
exposeTime = config->value("exposeTime",300).toInt();
//config->endGroup();   //读取操作中可不加
delete config;
qDebug()<<"exposeTime:"<<exposeTime;

效果和上面是一样的。除此之外还可以用beginReadArray来读取。

(4)写入数据:

写入数据时,beginGroup()endGroup()是必要的:

QSettings *config = new QSettings ("C:/Users/Administrator/Documents/vision_1/source/cameraSettings.ini",QSettings::IniFormat);
config->beginGroup("cameraSettings");
config->setValue("ipAddress","192.168.3.5");                                  //ip地址
config->setValue("ifExpose",1);                                     //是否曝光
config->setValue("exposeTime",200);                                 //曝光时间
config->endGroup();
delete config;

注意了,这里读取的ini文件路径不要再使用:/打头的Qt资源文件了,:/Qt资源中的文件,表示引用。在程序中先向ini文件中写入,再读取,然后重启程序再读取会发现,第一次读取时显示是修改后的内容,第二次读取却还是变为原样,就是因为资源里的:/中的文件中是引用的而非真正的文件,所以要用完整的路径来读取。我一开始在这卡了很久,一直写入无效,直到在https://blog.csdn.net/LyRics1996/article/details/107923887 看到了我上面描述的答案才解决。

再提一句,Qt中引用的资源会在程序启动时读取一次这个文件,然后整个程序周期就都一直引用这个模板。如果写入引用文件,就会改变引用文件,但是在程序下一次启动时,引用文件又会被初始化为本地的文件。如果不想配置参数每次都复位,就用本地文件地址吧。同样的,读取也适用这个规则,如果写入的是本地文件,但是读取的是引用文件,刚刚说过,引用文件只是在程序运行的时候读取一下文件,然后在程序周期中就不会跟随本地文件改变了,就导致读取的和写入的不同步了。所以,最好还是读取和写入都使用本地的文件吧。

2、正则表达式检查IP输入QLineEdit:
(1)只能输入0-100的数字:
ui->sendNm->setValidator(new QIntValidator(0, 100, this));
(2)IP:

代码来自:https://blog.csdn.net/qq_32605451/article/details/107184419,记录一下

#include <QRegExpValidator>

QRegExp rx("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$");
QRegExpValidator *m_IP = new QRegExpValidator(rx, this);
ui->ipAddress->setValidator(m_IP);

只接收每输入三个数字后面跟一个点的IP样式。

3、使new出来的控件的qss不继承到子控件:

对于在ui中放置的控件设置qss,为了不将样式继承到子控件,一般都是像这样:

ui->widget1->setStyleSheet("QWidget#widget1{border:1px solid red;background-color:blue;}");

但是对于new出来的widget1却达不到这样的效果,如:

QWidget *widget1 = new QWidget(this);
widget1->resize(200,200);
widget1->setStyleSheet("QWidget#widget1{border:1px solid red;background-color:blue;}");

发现反而不显示了,今天灵机一动,加上最近写的css,想了两个方法。

(1)类选择器:

在基类前加上一个点,就会对这一class分类的控件才生效:

widget1->setStyleSheet(".QWidget{border:1px solid red;background-color:blue;}");

不过有一个坏处,就是如果子控件也有QWidget,那父控件设的这个类选择器也会作用于子控件的QWidget。如:
在这里插入图片描述

(2)设置objectname:

这就是为什么上面的选择器不起作用的原因了,今天突然一拍脑门想到了。因为你创建的QWidget对象的名字并不是在GUI中的控件名,想要在qss的选择器中生效,需要使用它的ObjectName,所以要先设置它的ObjectName。如:

    QWidget *widget1 = new QWidget(this);
    QWidget *widget2 = new QWidget(widget1);
    widget1->resize(200,200);
    widget1->setObjectName("widget1p");
    widget2->setObjectName("widget2p");
    widget1->setStyleSheet("QWidget#widget1p{border:1px solid red;background-color:blue;}");
    widget2->setStyleSheet("QWidget#widget2p{border:1px solid green;background-color:red;}");

就可以对每个控件精准打击了,也不会影响同类型的子控件。
在这里插入图片描述

https://blog.csdn.net/u012870892/article/details/81612407 还有一些其他方法,可以参考一下。对于我来说,我琢磨的第二个方法够用了。

4、Q_DECLARE_METATYPE:

Qt中自定义结构体需要使用Q_DECLARE_METATYPEQ_DECLARE_METATYPE是为了让QMetaType知道Type这个数据类型,并提供一个默认的拷贝构造函数和析构函数。QVariant需要使用Q_DECLARE_METATYPE这个宏来定制类型,一般放置于最后。有些类型在QMETA中有的,有的是没有的,没有的时候,就需要用这个函数来注册。

typedef struct {
    int son;
    QString moom;
    bool father;
}family;

Q_DECLARE_METATYPE(family);

其余可以参考:https://blog.csdn.net/qq78442761/article/details/82084295

5、QVariant使用:

QVariant可以存储各种数据类型。

部分参考自:https://blog.csdn.net/liushiyi3083862599/article/details/92825446

(1)定义:
QVariant v1;
(2)基本类型存取:
v1.setValue(1);
int nvar = v1.value<int>();

v1.setValue(QString("world"));
QString strValue = v1.value<QString>();

QImage image1;
image1.load("1.jpg");
v1.setValue(image1);
QImage image2 = v1.value<QImage>();
(3)存取储结构体:

以上面我举例的结构体为例:
记住在下面添加:Q_DECLARE_METATYPE(family);

family family1;
v1.setValue(family1);//存
family strValue = v1.value<family>();//取
(4)存取类:

mainwindow.h中:

class a;  //前置声明

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
public slots:
    void on_pushButton_clicked();
};

class a{
public:
    int a1;
    double a2;
    void out1();
};
#endif
Q_DECLARE_METATYPE(*a); 

mainwindow.cpp中:

void MainWindow::on_pushButton_clicked(){
    a *aaa=new a();
    aaa->a1 = 1;
    aaa->a2 = 2.2;

    QVariant v1;
    v1.setValue(aaa);
    a *abb = v1.value<a*>();

    ui->label->setText(QString::number(abb->a1));
    qDebug()<<abb->a2;
    abb->out1();
    }

void a::out1(){
    qDebug()<<u8"我在这";
}

点击前:
在这里插入图片描述
点击后:
在这里插入图片描述

(5)存取控件:
void MainWindow::on_pushButton_clicked(){
    QPushButton *aaa=new QPushButton(this);
    aaa->setGeometry(500,200,200,200);
    aaa->show();

    QVariant v1;
    v1.setValue(aaa);
    QPushButton *abb = v1.value<QPushButton*>();
    abb->setText(u8"少损失");
    }

点击按钮前:
在这里插入图片描述
点击后:
在这里插入图片描述

6、使用信号传递各种类型:
(1)QImage:

mainwindow.h中:

signals:
    void sendImg(QImage);
public slots:
    void on_pushButton_clicked();
    void setLab(QImage);

mainwindow.cpp中:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(this,SIGNAL(sendImg(QImage)),this,SLOT(setLab(QImage)));
}

void MainWindow::on_pushButton_clicked(){
    QImage image;
    image.load("C:/Users/Administrator/Pictures/qtback/2.jpg");
    emit sendImg(image);
}

void MainWindow::setLab(QImage image2){
    ui->label->setPixmap(QPixmap::fromImage(image2));
}

运行结果:
在这里插入图片描述

(2)自定义结构体:

mainwindow.h

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    typedef struct{
        bool son;
        int moom;
        QString dad;
    }family;

private:
    Ui::MainWindow *ui;

signals:
    void sendImg(family);
public slots:
    void on_pushButton_clicked();
    void setLab(family);

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(this,SIGNAL(sendImg(family)),this,SLOT(setLab(family)));
}

void MainWindow::on_pushButton_clicked(){
    family family1;
    //image.load("C:/Users/Administrator/Pictures/qtback/2.jpg");
    family1.dad="aa";
    family1.moom=2;
    family1.son=false;
    emit sendImg(family1);
}

void MainWindow::setLab(family fam){
    ui->label->setText(fam.dad);
    qDebug()<<fam.moom;
}

运行结果:
在这里插入图片描述

(3)QVariant:

下面还是以QVariant存储QImage,然后发送QVariant为例。当然并不局限于图片,其他很多格式,只要QVariant能存进去,一般都能传吧。但要注意除了int这些基础类型,其他的类型需要使用Q_DECLARE_METATYPE来告诉QVariant,比如自定义结构体。

mainwindow.h中声明信号:

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
    Ui::MainWindow *ui;

signals:
    void sendImg(QVariant);
public slots:
    void on_pushButton_clicked();
    void setLab(QVariant);
};
#endif // MAINWINDOW_H
Q_DECLARE_METATYPE(QImage);

最后一句是必要的,不用Q_DECLARE_METATYPE来声明QImage,否则QVariant无法识别QImage

mainwindow.cpp中操作槽函数和发送信号:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(this,SIGNAL(sendImg(QVariant)),this,SLOT(setLab(QVariant)));
}

void MainWindow::on_pushButton_clicked(){
    QImage image;
    image.load("C:/Users/Administrator/Pictures/qtback/2.jpg");
    
    QVariant v1;
    v1.setValue(image);
    emit sendImg(v1);
}

void MainWindow::setLab(QVariant v1){
    QImage image2;
    image2 = v1.value<QImage>();
    ui->label->setPixmap(QPixmap::fromImage(image2));
}

其实就是点击按钮,将图片用信号发给槽函数,槽函数来让label显示接收到的图片。

运行结果:
在这里插入图片描述

(4)使用信号传递类对象:

mainwindow.h中:

class a;  //前置声明
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

signals:
    void sendImg(a*);
public slots:
    void on_pushButton_clicked();
    void setLab(a*);
};

class a{
public:
    int a1;
    double a2;
    void out1();
};

mainwindow.cpp中:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(this,SIGNAL(sendImg(a*)),this,SLOT(setLab(a*)));
}

void MainWindow::on_pushButton_clicked(){
    a *aaa=new a();
    aaa->a1=1;
    aaa->a2=1.1;
    emit sendImg(aaa);
}

void MainWindow::setLab(a *aa){
    ui->label->setText(QString(aa->a1));
    qDebug()<<aa->a2;
    aa->out1();
}

void a::out1()
{
    qDebug()<<u8"输出啦!";
}

运行结果:
在这里插入图片描述

(5)传递控件:

mainwindow.h中:

signals:
    void sendImg(QPushButton*);
public slots:
    void on_pushButton_clicked();
    void setLab(QPushButton*);

mainwindow.cpp中:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(this,SIGNAL(sendImg(QPushButton*)),this,SLOT(setLab(QPushButton*)));
}

void MainWindow::on_pushButton_clicked(){
    QPushButton *aaa=new QPushButton(this);
    aaa->setGeometry(500,200,200,200);
    aaa->show();

    emit sendImg(aaa);
}

void MainWindow::setLab(QPushButton *aa){
     aa->setText(u8"沙克斯");
     ui->label->setText(aa->text());
}

点击按钮前:
在这里插入图片描述
点击按钮后:
在这里插入图片描述
可以发现我写的槽函数,使pushbutton显示的文字成功显示。那我不禁陷入思考,是不是线程也可以如此通过信号来直接操控ui界面呢,有机会试一试。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值