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; //输出
输出:
除此之外,还可以通过beginGroup
和endGroup
来指定节点:
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_METATYPE
,Q_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界面呢,有机会试一试。