当前位置: 首页 > news >正文

QT属性系统,简单属性功能快速实现 QT属性的简单理解 属性学习如此简单 一文就能读懂QT属性 QT属性最简单的学习

4.4 属性系统


Qt 元对象系统最主要的功能是实现信号和槽机制,当然也有其他功能,就是支持属性系统。有些高级语言通过编译器的 __property 或者 [property] 等关键字实现属性系统,用于提供对成员变量的访问权限,Qt 则通过自己的元对象系统支持属性访问,Qt 是基于标准 C++ 的,不需要底层编译器支持属性,Qt 本身提供了通用的跨平台的属性系统。关于属性系统可以在 Qt 助手索引里面输入“The Property System”,找到相应的主题文档。Qt 类库大量使用属性,通常开发基于 Qt 的类库时,也会用到属性系统。下面我们介绍简化版的属性系统,只列举了属性系统里面几个基本的条目。
 

4.4.1 属性系统简介


为了保持类的封装特性,通常成员变量需要保持私有状态,而为了与其他对象协作,就需要提供相应的 get/set 函数。如果成员变量的数值发生了变化,通常也需要提供通知(NOTIFY)信息告知相关对象,Qt 里的通知一般都是使用信号触发。set 函数可以作为槽函数,方便接收相关对象的信号以实现自动调整,比如上一节标签控件的 setText 槽函数。set 函数会导致成员变量数值变化,为了通知相关对象,set 函数里通常会 emit 该成员变量发生变化的信号。
属性系统也是通过元对象系统实现的,它也是需要直接或间接从 QObject 类继承,并在类的声明里需要 Q_OBJECT 宏。下面介绍简化版的属性声明,第一类是不指明与属性相关的私有成员变量,这时必须至少提供该属性的读函数:

Q_PROPERTY(type name
           READ getFunction
           [WRITE setFunction]
           [RESET resetFunction]
           [NOTIFY notifySignal] )

Q_PROPERTY()宏就是属性的声明:

  • type 是指属性的类型,可以是 C++ 标准类型、类名、结构体、枚举等,name 就是属性的名字。
  • READ 标出该属性的读函数 getFunction,Qt 属性的读函数通常省略 get 三个字母。
  • WRITE 标出该属性的写函数 setFunction,中括号表示可选,写函数不是必须的。
  • RESET 标出该属性的重置函数 resetFunction,重置函数将属性设为某个默认值,中括号表示可选,重置函数不是必须的。
  • NOTIFY 标出该属性变化时发出的通知信号 notifySignal,中括号表示可选,这个信号不是必须的。

这仅仅列举了属性声明里简单的几行,复杂需要查阅 Qt 帮助文档。对于属性,注意 name 仅仅是一个用于标识属性的名字,它不是实际存在的成员变量,属性系统不会自动生成成员变量,它就是虚无的名字代号(不同属性的名字不能相同)。对于属性用到的数值会存在一 个真正的私有成员变量里面, 私有成员变量、读函数、写函数、信号等需要另外编写这些声明,对于函数还需要编写实体代码。

上面是不明确指出私有成员变量的情形,也可以明确指出使用了哪个成员变量,这时候属性声明为:

Q_PROPERTY(type name
           MEMBER memberName
           [READ getFunction]
           [WRITE setFunction]
           [RESET resetFunction]
           [NOTIFY notifySignal] )

这里的 MEMBER 标出属性使用的成员变量 memberName,其他的行与上面的声明类似。

在明确标出属性使用的成员变量的情况下,属性的读写函数可以省略不写,Qt 的 moc 工具会自动为成员变量生成读写代码;而重置函数、信号等需要自己声明,并编写必须的代码;如果声明了属性值变化的通知信号,那么 moc 工具生成的写属性代码会自动触发该通知信号。

如果希望自己的编写的类库支持 QML,那么 NOTIFY 通知信号是必须的,一般建议把成员变量、读函数、写函数、通知信号都明确标出来,这样方便程序员阅读和使用。
 

4.4.2 普通属性示例


使用 Q_PROPERTY()宏声明的其实都是声明好的普通属性,在程序编译时就已经规定好了,本小节示范普通属性的例子,下一小节示范在运行时动态添加属性。本 小节示范为窗口类添加自定义的属性,然后从 main 函数里面设置和打印属性的值。
打开 QtCreator ,新建一个 Qt Widgets Application 项目,在新建项目的向导里填写:
①项目名称 normalpros,创建路径 D:\QtProjects\ch04,点击下一步;
②套件选择里面选择全部套件,点击下一步;
③基类选择 QWidget,点击下一步;
④项目管理不修改,点击完成。
建好项目之后,打开头文件 widget.h,添加属性的声明代码、读写函数声明、信号声明和成员变量:

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();//声明属性//不直接标出成员变量的形式Q_PROPERTY(QString nickName READ nickName WRITE setNickName NOTIFY nickNameChanged)//直接标出成员变量的形式Q_PROPERTY(int count MEMBER m_count READ count WRITE setCount NOTIFY countChanged)//标出成员变量,可以省略读写函数Q_PROPERTY(double value MEMBER m_value NOTIFY valueChanged)//nickName读函数声明const QString& nickName();//count读函数int count();//value属性声明时,指出了成员变量并省略了读写函数,它的读写代码由moc工具自动生成//value数值被修改时,valueChanged信号会自动触发//自动生成的读写代码只有简单的读写功能,不能做数值有效性检查signals://三个属性数值变化时发信号void nickNameChanged(const QString& strNewName);void countChanged(int nNewCount);void valueChanged(double dblNewValue);public slots://写函数通常可以作为槽函数,方便与其他信号关联,自动调整数值//nickName写函数声明void setNickName(const QString& strNewName);//count写函数声明void setCount(int nNewCount);//value写代码由 moc 自动生成,没有写函数private:Ui::Widget *ui;//三个私有变量,对应是三个属性QString m_nickName;int m_count;double m_value;
};#endif // WIDGET_H

上面代码声明了三个属性,首先是 nickName:

  • 没有直接指出其成员变量,但其实是有的;
  • 读函数为 nickName(),返回值为属性里声明的 QString 类型(引用也算的);
  • 写函数为 setNickName(),写函数接收 QString 类型参数,并返回 void;
  • 当属性值变化时,发送 nickNameChanged 信号,信号参数里会带有新的数值。

属性声明里的读写函数都需要程序员自己编写,信号自己声明,并在写函数里触发。写函数 setNickName() 的声明放到槽函数声明部分了,这样方便关联其他信号,实现自动调整属性值。虽然属性声明里没说有成员变量,但是需要自己定义一个私有变量 m_nickName 保存属性的数值。

第二个属性是 count:

  • 直接指出它对应的成员变量是 m_count;
  • 读函数是 count(),返回 int 类型;
  • 写函数是 setCount(),接收一个 int 参数,并返回 void;
  • 当属性值变化时,发送 countChanged 信号,信号参数里会带有新的数值;

count 属性的工作原理 nickName 属性差不多,仅仅是在声明里明确说了对应的成员变量为 m_count。

第三个属性是 value ,这是属性声明的极简形式,读写函数都省略了,属性读写的代码由 moc 工具自动生成。因此这种极简形式的属性,它只需要在头文件里放三行声明代码,其他所有代码都不需要:

 

   Q_PROPERTY(double value MEMBER m_value NOTIFY valueChanged)signals:void valueChanged(double dblNewValue);private:double m_value;

除了属性声明本身的一句,就只需要声明属性值变化是的信号和私有成员变量。

moc 工具自动生成的读写代码仅仅是代码片段(4.5 节专门讲这些代码),没有函数的,自然没有相关的槽函数,所以如果希望把写函数作为槽函数来用,就得用类 似 count 属性的声明,并自己编读写函数的实体代码。

头文件代码就如上编辑,下面来添加 widget.cpp 中必须的函数实体代码:

#include "widget.h"#include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}//读函数定义
//读nickName数值
const QString& Widget::nickName()
{return m_nickName;
}
//读count数值
int Widget::count()
{return m_count;
}//写函数,在数值发生变化是才发信号
void Widget::setNickName(const QString &strNewName)
{if(strNewName == m_nickName){//数值没变化,直接返回return;}//修改数值并触发信号m_nickName = strNewName;emit nickNameChanged(strNewName);
}void Widget::setCount(int nNewCount)
{if(nNewCount == m_count){//数值没变化,直接返回return;}//修改数值并触发信号m_count = nNewCount;emit countChanged(nNewCount);
}

在 widget.cpp 只需要为 nickName 和 count 两个属性添加读写函数的代码。读函数 nickName() 和 count() 非常简 单,就是返回相应的私有成员变量数值。
对于写函数 setNickName()里面代码,首先判断传入的参数值是否与旧的值相同,如果是一样的就不用修改,直接返回。如果新旧数值不同,那就设置成员变量为新的值,并发送数 值发生变化的信号 nickNameChanged,并把新值作为参数放到信号里面。set 函数里其实可以顺便做一下数值的有效性检查,上面代码里省略了有效性 检查。
对于写函数 setCount 是类似的过程,新旧数值一样就不变,不一样就修改成员变量并发信号。

窗口类 Widget 的代码就是上面那么多。如何使用这些属性呢?我们可以编辑 main.cpp ,尝试修改和读取这些属性:

#include "widget.h"#include <QApplication>
#include <QDebug>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;//属性读写//通过写函数、读函数w.setNickName( "Wid" );qDebug()<<w.nickName();w.setCount(100);qDebug()<<w.count();//通过 setProperty() 函数 和 property() 函数w.setProperty("value", 2.3456);qDebug()<<fixed<<w.property("value").toDouble();//显示窗体w.show();return a.exec();
}

属性的读写既可以使用各个属性自己的读写函数,如 setNickName()、nickName()、setCount()、count(),也可以使用属性通用的函数:setProperty() 写属性,property() 读属性,都是通过属性的名称来寻找特定属性实现读写。
注意由于上面的 value 属性没有声明读写函数,所以对它的读写只能靠 setProperty() 和 property() 函数,这对通用的属性读写函数的声明如下:

bool QObject::​setProperty(const char * name, const QVariant & value)QVariant QObject::​property(const char * name) const

​setProperty() 第一个参数是普通字符串,就是属性的名称,第二个参数是属性的数值,QVariant 是 Qt 定义的通用变量类型,标准 C++ 的类型和 Qt 自己的数值类型都可以自动转为 QVariant 类的对象。
​property() 函数以变量名的字符串作为输入参数,返回一个通用的 QVariant 对象,将 QVariant 对象转为标准类型或者 Qt 数值类型,可以用对应的 to**** 函数,toDouble 是转为双精度浮点数,toInt 是转为整型数, toString 是转为 QString 字符串,还有其他转换函数,详细的请查阅 QVariant 帮助文档。

代码先添加这些,我们运行这个示例,它执行的结果会打印到输出面板,如下图所示:

run1


这个例子展示属性的声明和访问,但是还有一个问题,我们在 set*** 函数里修改了属性值,应该发了值改变的信号,我们没有接收这些信号,还不知道它们真发信号还是假发信号,得验验货。
我们为这个例子添加一个 C++ 类,名字为 ShowChanges,基类为 QObject:

class

编辑 showchanges.h,为 valueChanged 信号添加对应的槽函数 RecvValue 声明:

#ifndef SHOWCHANGES_H#define SHOWCHANGES_H#include <QObject>class ShowChanges : public QObject
{Q_OBJECT
public:explicit ShowChanges(QObject *parent = 0);~ShowChanges();signals:public slots://槽函数,接收 value 变化信号void RecvValue(double v);
};#endif // SHOWCHANGES_H

然后编辑 showchanges.cpp,为槽函数添加实体代码:

#include "showchanges.h"#include <QDebug>ShowChanges::ShowChanges(QObject *parent) : QObject(parent)
{}ShowChanges::~ShowChanges()
{}
//接收并打印 value 变化后的新值
void ShowChanges::RecvValue(double v)
{qDebug()<<"RecvValue: "<<fixed<<v;
}

这个仅仅是类的代码,接收信号必须要定义一个对象,然后才能关联源头信号和接收端槽函数,下面修改 main.cpp 代码,添加接收端对象和关联函数代码:

#include "widget.h"#include <QApplication>
#include <QDebug>
#include "showchanges.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;   //源头对象//接收端对象ShowChanges s;//关联QObject::connect(&w, SIGNAL(valueChanged(double)), &s, SLOT(RecvValue(double)));//属性读写//通过写函数、读函数w.setNickName( "Wid" );qDebug()<<w.nickName();w.setCount(100);qDebug()<<w.count();//通过 setProperty() 函数 和 property() 函数w.setProperty("value", 2.3456);qDebug()<<fixed<<w.property("value").toDouble();//显示窗体w.show();return a.exec();
}

value 属性值被修改成了 2.3456,这个值一被修改,就会触发 valueChanged 信号,槽函数 RecvValue 被自动调用,并且会接收到新数值并打印出来。运行这个修改后的示例,得到的结果如下:

run2

可以看到,槽函数打印的信息会在 qDebug()<<fixed<<w.property("value").toDouble(); 这行调用之前打印出来。无论使用通用的
setProperty() 函数,还是属性自己独有的 set 函数,变化信号都会正确地发出来。
上面只接收了 valueChanged 信号,还有 nickNameChanged 信号和 countChanged 信号没接收,这个两个信号对应的槽函数和关联函数代码作为练习,请读者自己动手完成。下面小节示范动态属性的使用。
 

4.4.3 动态属性示例


不仅在源代码里面添加属性声明,程序运行时也可以通过 setProperty() 函数为当前类对象添加动态属性,获取动态属性的值也是用 property() 函数。获取全部的动态属性名称列表可以通过 ​dynamicPropertyNames 函数:

QList<QByteArray> QObject::​dynamicPropertyNames() const

​dynamicPropertyNames 返回当前所有动态属性名称字符串的列表。
如果尝试用 property() 函数获取不存在的属性名的数值,那么会得到一个特殊的 QVariant 对象,这个对象处于不可用状态,这时 QVariant 对象的 isValid() 函数返回 false。下面示范动态属性的例子。
重新打开 QtCreator ,新建一个 Qt Widgets Application 项目,在新建项目的向导里填写:
①项目名称 dynamicpros,创建路径 D:\QtProjects\ch04,点击下一步;
②套件选择里面选择全部套件,点击下一步;
③基类选择 QWidget,点击下一步;
④项目管理不修改,点击完成。
建好项目之后,Widget 类的代码不需要修改,动态属性不需要额外声明,直接在 main 函数里面使用就行了,我们编辑 main.cpp:

#include "widget.h"#include <QApplication>
#include <QDebug>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;//如果动态属性不存在,QVariant 对象的 isValid() 函数返回 false,变量不可用qDebug()<<w.property("myValue").isValid();//添加属性 myValuew.setProperty("myValue", 2.3456);//获取并打印qDebug()<<w.property("myValue").toDouble();//添加属性 myNamew.setProperty("myName", "Wid");//获取并打印qDebug()<<w.property("myName").toString();//获取所有动态属性名称,打印名称列表qDebug()<<w.dynamicPropertyNames();w.show();return a.exec();
}

在 main 函数里,我们先尝试获取一个不存在的属性 myValue,property() 函数返回 QVariant 对象,由于属性不存在,所以 QVariant 对象 isValid() 函数会返回 false,表明不可用状态,也就意味着该属性是不存在的。

然后我们向窗体对象 w 添加了动态属性 myValue,并用 property() 函数获取了该属性的 QVariant 对象,然后转成双精度浮点数打印。接着我们向窗体对象 w 添加了动态属性 myName,类似地用 property() 函数获取属性的 QVariant 对象,然后转为字符串打印。
最后我们用窗体对象 w 的 dynamicPropertyNames() 函数获取了所有的动态属性名称列表,并打印了动态属性名称列表。

例子修改的代码只有上面那些,例子运行的效果如下图所示:

run

通过在头文件声明普通的属性,可以为属性标明相关的成员变量、读函数、写函数、变化通知信号等等,而动态属性就没有这些特性,它其实就是以成对的属性名、属性值的 形式存在,可以通过 setProperty() 和 property() 读写,仅此而已,所以动态属性应用得比较少。

属性系统不仅可以声明普通属性和在运行时添加动态属性,还有一个衍生功能,就是为类添加一些附加信息,运行时可以查询这些附加信息,方便程序员或用户查询相关信 息,下面学习为类添加附加信息的例子。
 

4.4.4 类的附加信息


Qt 程序运行时可以查询当前对象的名称,我们之前 4.2.3 节用 QObject::objectName() 函数获取过对象名称。运行时还可以查询类的信息,主要包括两种类信息,一种是基本的类信息,Qt 类会自动生成这些信息,包括当前类名、继承树上的基类名称等;另一类是程序员手动添加的类附加信息,通过 Q_CLASSINFO() 宏,在类的声明里添加类附加信息,比如:

Q_CLASSINFO("Version", "1.0.0")

附加信息也是成对的“名称-值”,不过注意 名称和值 都是普通字符串。如果希望在运行时查询类的附加信息,可以先用 QObject::metaObject() 获取当前对象包含的元对象数据,然后使用 QMetaObject::​classInfo 函数查询某个序号的附加信息:

const QMetaObject * QObject::​metaObject() const               [virtual]

QMetaClassInfo QMetaObject::​classInfo(int index) const


对于基本信息,可以用 QMetaObject::className() 函数获取类名。如果要判断继承树上是否有某个基类,使用 QObject::​inherits() 函数判断。这两个函数声明如下:

const char * QMetaObject::​className() const

bool QObject::​inherits(const char * className) const

下面示范类的附加信息例子,并顺路打印类的基本信息,判断基类名。
重新打开 QtCreator ,新建一个 Qt Widgets Application 项目,在新建项目的向导里填写:
①项目名称 classinfo,创建路径 D:\QtProjects\ch04,点击下一步;
②套件选择里面选择全部套件,点击下一步;
③基类选择 QWidget,点击下一步;
④项目管理不修改,点击完成。
建好项目之后,编辑 widget.h 头文件,添加附加信息:

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();//类的附加信息Q_CLASSINFO("Version", "1.0.0")Q_CLASSINFO("Author", "Winland")Q_CLASSINFO("Site", "https://lug.ustc.edu.cn/sites/qtguide/")private:Ui::Widget *ui;
};#endif // WIDGET_H

头文件里添加了三行,也就是三对“名称-值”,都是普通字符串。附加信息只需要添加到声明里,不需要其他代码,所以 widget.cpp 文件保持原样,不修改。
下面我们在 main.cpp 里面访问窗体的附加信息和基本信息:

#include "widget.h"#include <QApplication>
#include <QDebug>
#include <QMetaClassInfo>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;//获取类的附加信息const QMetaObject *pMO = w.metaObject();//附加信息个数int nInfoCount = pMO->classInfoCount();//打印所有的附加信息for(int i=0; i<nInfoCount; i++){QMetaClassInfo info = pMO->classInfo(i);qDebug()<<info.name()<<"\t"<<info.value();}//基本信息qDebug()<<"Class Name: "<<pMO->className();qDebug()<<"Object Name: "<<w.objectName();//判断是否为基类qDebug()<<w.inherits("QWidget");qDebug()<<w.inherits("nothing");//显示窗口w.show();return a.exec();
}

文件开头添加了 <QDebug> 和 <QMetaClassInfo> 两个头文件,QMetaClassInfo 就是存储附加信息项的类,它有两个公开函数:name() 获取附加信息项的名称,value() 获取附加信息项的值。
在 main 函数里,定义好窗体对象 w,之后,先通过 metaObject() 函数得到一个 QMetaObject 常量指针 pMO;
通过 pMO->classInfoCount() 获知附加信息项的个数;
然后在 for 循环里枚举 pMO->classInfo(i) 信息项,打印信息项的名称和值。

接下来是一些基本信息的获取,类的名字也是通过元对象指针获取 pMO->className();
窗体对象名可以直接用 w.objectName() 获取;
判断窗体是否从某个基类派生,使用 inherits 函数,这个函数接收一个字符串,如果是对象的直接或间接基类名称就返回 true,否则返回 false。

这个示例运行结果如下图所示(这里窗体的类名和对象名正好是一样的,其他情况可能不一样):

run

相关文章:

QT属性系统,简单属性功能快速实现 QT属性的简单理解 属性学习如此简单 一文就能读懂QT属性 QT属性最简单的学习

4.4 属性系统 Qt 元对象系统最主要的功能是实现信号和槽机制&#xff0c;当然也有其他功能&#xff0c;就是支持属性系统。有些高级语言通过编译器的 __property 或者 [property] 等关键字实现属性系统&#xff0c;用于提供对成员变量的访问权限&#xff0c;Qt 则通过自己的元对…...

【IEEE出版丨EI检索】2024新型电力系统与电力电子国际会议(NPSPE 2024)

2024新型电力系统与电力电子国际会议&#xff08;NPSPE 2024&#xff09;将于8月16日至18日在中国大连举行&#xff0c;本届大会致力于为相关领域的专家和学者提供一个探讨行业热点问题&#xff0c;促进科技进步&#xff0c;增加科研合作的平台。本届大会涵盖新型电力系统和电力…...

【Netty】nio阻塞非阻塞Selector

阻塞VS非阻塞 阻塞 阻塞模式下&#xff0c;相关方法都会导致线程暂停。 ServerSocketChannel.accept() 会在没有建立连接的时候让线程暂停 SocketChannel.read()会在没有数据的时候让线程暂停。 阻塞的表现就是线程暂停了&#xff0c;暂停期间不会占用CPU&#xff0c;但线程…...

ES 操作

1、删除索引的所有记录 curl -X POST "localhost:9200/<index-name>/_delete_by_query" -H Content-Type: application/json -d {"query": {"match_all": {}} }POST /content_erp_nlp_help/_delete_by_query { "query": { &quo…...

uniapp如何实现跳转

在 UniApp 中&#xff0c;页面跳转主要可以通过两种方式实现&#xff1a;使用 <navigator> 组件和调用 UniApp 提供的导航 API。以下是这两种方式的详细说明&#xff1a; 1. 使用 <navigator> 组件 <navigator> 组件允许你在页面上创建一个可点击的元素&am…...

Stable-Diffusion-WebUI 常用提示词插件

SixGod提示词插件 SixGod提示词插件可以帮助用户快速生成逼真、有创意的图像。其中包含&#xff0c;清空正向提示词”和“清空负向提示词、提示词起手式包含人物、服饰、人物发型等各个维度的提示词、一键清除正面提示词与负面提示词、随机灵感关键词、提示词分类组合随机、动…...

单片机 PWM输入捕获【学习记录】

前言 学习是永无止境的&#xff0c;就算之前学过的东西再次学习一遍也能狗学习到很多东西&#xff0c;输入捕获很早之前就用过了&#xff0c;但是仅仅是照搬例程没有去进行理解。温故而知新&#xff01; 定时器 定时器简介 定时器的分类 高级定时器 通用定时器 基本定时器…...

3.1、前端异步编程(超详细手写实现Promise;实现all、race、allSettled、any;async/await的使用)

前端异步编程规范 Promise介绍手写Promise&#xff08;resolve&#xff0c;reject&#xff09;手写Promise&#xff08;then&#xff09;Promise相关 API实现allraceallSettledany async/await和Promise的关系async/await的使用 Promise介绍 Promise是一个类&#xff0c;可以翻…...

3.1. 马氏链-马氏链的定义和示例

马氏链的定义和示例 马氏链的定义和示例1. 马氏链的定义2. 马氏链的示例2.1. 随机游走2.2. 分支过程2.3. Ehrenfest chain2.4. 遗传模型2.5. M/G/1 队列 马氏链的定义和示例 1. 马氏链的定义 对于可数状态空间的马氏链, 马氏性指的是给定当前状态, 其他过去的状态与未来的预测…...

红利之外的A股底仓选择:A50

内容提要 华泰证券指出&#xff0c;当前指数层面下行风险不大&#xff0c;市场再入震荡期下&#xff0c;可关注三条配置线索&#xff1a;1&#xff09;A50为代表的产业巨头&#xff1b;2&#xff09;以家电/食饮/物流/出版为代表的稳健消费龙头&#xff0c;3&#xff09;消费电…...

wondershaper 一款限制 linux 服务器网卡级别的带宽工具

文章目录 一、关于wondershaper二、文档链接三、源码下载四、限流测试五、常见报错1. /usr/local/sbin/wondershaper: line 145: tc: command not found2. Failed to download metadata for repo ‘appstream‘: Cannot prepare internal mirrorlist: No URLs.. 一、关于wonder…...

独孤思维:盲目进群,根本赚不到钱

01 我看有些伙伴&#xff0c;对标同行找写作素材和灵感的时候。 喜欢把对标文章发给ai提炼总结。 这个方法好是好&#xff0c;但是&#xff0c;有一个问题。 即&#xff0c;无法感受全文的细节。 更无法感受作者的情感和温度。 就好像电影《记忆大师》一样。 我提取了记…...

针对indexedDB的简易封装

连接数据库 我们首先创建一个DBManager类&#xff0c;通过这个类new出来的对象管理一个数据库 具体关于indexedDB的相关内容可以看我的这篇博客 indexedDB class DBManager{}我们首先需要打开数据库&#xff0c;打开数据库需要数据库名和该数据库的版本 constructor(dbName,…...

网络编程--网络理论基础(二)

这里写目录标题 网络通信流程mac地址、ip地址arp协议交换机路由器简介子网划分网关 路由总结 为什么ip相同的主机在与同一个互联网服务通信时不冲突公网ip对于同一个路由器下的不同设备&#xff0c;虽然ip不冲突&#xff0c;但是因为都是由路由器的公网ip转发通信&#xff0c;接…...

Python MongoDB 基本操作

本文内容主要为使用Python 对Mongodb数据库的一些基本操作整理。 目录 安装类库 操作实例 引用类库 连接服务器 连接数据库 添加文档 添加单条 批量添加 查询文档 查询所有文档 查询部分文档 使用id查询 统计查询 排序 分页查询 更新文档 update_one方法 upd…...

Node.js 入门:

Node.js 是一个开源、跨平台的 JavaScript 运行时环境&#xff0c;它允许开发者在浏览器之外编写命令行工具和服务器端脚本。以下是一些关于 Node.js 的基础教程&#xff1a; 1. **Node.js 入门**&#xff1a; - 了解 Node.js 的基本概念&#xff0c;包括它是一个基于 Chro…...

java8 List的Stream流操作 (实用篇 三)

目录 java8 List的Stream流操作 (实用篇 三) 初始数据 1、Stream过滤&#xff1a; 过滤-常用方法 1.1 筛选单元素--年龄等于18 1.2 筛选单元素--年龄大于18 1.3 筛选范围--年龄大于18 and 年龄小于40 1.4 多条件筛选--年龄大于18 or 年龄小于40 and sex男 1.5 多条件筛…...

机器学习python实践——数据“相关性“的一些补充性个人思考

在上一篇“数据白化”的文章中&#xff0c;说到了数据“相关性”的概念&#xff0c;但是在统计学中&#xff0c;不仅存在“相关性”还存在“独立性”等等&#xff0c;所以&#xff0c;本文主要对数据“相关性”进行一些补充。当然&#xff0c;如果这篇文章还能入得了各位“看官…...

MySQL——触发器(trigger)基本结构

1、修改分隔符符号 delimiter $$ $$可以修改 2、创建触发器函数名称 create trigger 函数名 3、什么样在操作触发&#xff0c;操作哪个表 after &#xff1a;……之后触发 before &#xff1a;……之后触发 insert &#xff1a;……之后触发 update &#xff1a;……之后触…...

数字孪生定义及应用介绍

数字孪生定义及应用介绍 1 数字孪生&#xff08;Digital Twin, DT&#xff09;概述1.1 定义1.2 功能1.3 使用场景1.4 数字孪生三步走1.4.1 数字模型1.4.2 数字影子1.4.3 数字孪生 数字孪生地球平台Earth-2 参考 1 数字孪生&#xff08;Digital Twin, DT&#xff09;概述 数字孪…...

数据赋能(122)——体系:数据清洗——技术方法、主要工具

技术方法 数据清洗标准模型是将数据输入到数据清洗处理器&#xff0c;通过一系列步骤“清理”数据&#xff0c;然后以期望的格式输出清理过的数据。数据清洗从数据的准确性、完整性、一致性、惟一性、适时性、有效性几个方面来处理数据的丢失值、越界值、不一致代码、重复数据…...

【SCAU数据挖掘】数据挖掘期末总复习题库简答题及解析——中

1. 某学校对入学的新生进行性格问卷调查(没有心理学家的参与)&#xff0c;根据学生对问题的回答&#xff0c;把学生的性格分成了8个类别。请说明该数据挖掘任务是属于分类任务还是聚类任务?为什么?并利用该例说明聚类分析和分类分析的异同点。 解答&#xff1a; (a)该数据…...

2024年注册安全工程师报名常见问题汇总!

​ 注册安全工程师报名 24年注册安全工程师报名已正式拉开序幕&#xff0c;报名时间为6月18日—7月10日&#xff0c;考试时间为10月26日—10月27日。 目前经有12个地区公布了2024年注册安全工程师报名时间&#xff1a; 注册安全工程师报名信息完善 根据注安报名系统提示&am…...

JRebel-JVMTI [FATAL] Couldn‘t write to C:\Users\中文用户名-完美解决

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 热部署下载参考博客解决第一步第二步第三步&#xff1a;第四步&#xff1a; 热部署下载 下载后启动报错&#xff1a;JRebel-JVMTI [FATAL] Couldn’t write to C:\…...

STM32基于DMA数据转运和AD多通道

文章目录 1. DMA数据转运 1.1 初始化DMA步骤 1.2 DMA的库函数 1.3 设置当前数据寄存器 1.4 DMA获取当前数据寄存器 2. DMA数据转运 2.1 DMA.C 2.2 DMA.H 2.3 MAIN.C 3. DMAAD多通道 3.1 AD.C 3.2 AD.H 3.3 MAIN.C 1. DMA数据转运 对于DMA的详细解析可以看下面这篇…...

安卓应用开发——Android Studio中通过id进行约束布局

在Android开发中&#xff0c;布局通常使用XML文件来描述&#xff0c;而约束&#xff08;如相对位置、大小等&#xff09;可以通过多种方式实现&#xff0c;但直接使用ID进行约束并不直接对应于Android的传统布局系统&#xff08;如LinearLayout、RelativeLayout等&#xff09;。…...

Elasticsearch过滤器(filter):原理及使用

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…...

Docker配置与使用详解

一、引言 随着云计算和微服务的兴起&#xff0c;Docker作为一种轻量级的容器化技术&#xff0c;越来越受到开发者和运维人员的青睐。Docker通过容器化的方式&#xff0c;将应用程序及其依赖项打包成一个可移植的镜像&#xff0c;从而实现了应用程序的快速部署和扩展。本文将详…...

触控MCU芯片(1):英飞凌PSoC第6代第7代

前言: 说到触摸MCU芯片,这个历史也是很久了,比如日常经常接触到的洗衣机、电冰箱、小家电,隔着一层玻璃,轻轻一按就能识别按键,感觉比过去纯机械式的按键更高级更美观,不仅白电,现在很多汽车也都在进行触摸按键的改版,不再使用笨重的机械按键,比如空调调温按键、档位…...

git pull报错:unable to pull from remote repository due to conflicting tag(s)

背景 我在vscode里正常拉取代码&#xff0c;突然就报了如题所示的错误。 原因 因为vscode的拉取按钮执行的实际命令是&#xff1a;git pull --tags origin branch-name&#xff0c;该命令的实际含义是从远程仓库拉取指定的分支和该远程仓库上的所有标签。 在拉取标签时本地的…...

wordpress恢复主题/展示型网站设计公司

昨晚做了某公司的笔试&#xff0c;遇到一道名为“三子棋”的编程题&#xff0c;花了近一个小时的时间去完成了这道题。最后提交时&#xff0c;有部分测试实例没有通过。可是已经没有时间修改了&#xff0c;真是悔啊&#xff01;现在将原题复述如下&#xff1a; 题目描述&#x…...

外贸电子商务网站建设/推广是什么意思

1.与或有事项相关的“可能”是指&#xff08;&#xff09;。 A.发生的可能性大于95&#xff05;但小于100&#xff05; B.发生的可能性大于30&#xff05;但小于或等于50&#xff05; C.发生的可能性大于50&#xff05;但小于或等于95&#xff05; D.发生的可能性大于5&#x…...

wordpress中页面伪静态/安卓排名优化

下载地址&#xff1a;网盘下载 Spring Boot是目前Spring技术体系中炙手可热的框架之一&#xff0c;既可用于构建业务复杂的企业应用系统&#xff0c;也可以开发高性能和高吞吐量的互联网应用。Spring Boot框架降低了Spring技术体系的使用门槛&#xff0c;简化了Spring应用的搭建…...

做城市分类信息网站好做吗/优化网站搜索排名

对于一个给定的数列d1,d2,d3......dn,求相邻两个数的差&#xff0c;即d2-d1,d3-d2...得出一个新数列c1,c2,c3...cn, c(i)d(i)-d(i-1).这个新的数列c就是一个差分数组。 差分数组也有这么两个 性质&#xff1a; (1)通过计算可以得出&#xff0c;d1c1,d2f1f2d1(d2-d1),d3f1f2f…...

wordpress中的类/seo教程自学入门教材

上一节配置了Simple check&#xff0c;现在来通过Simple check 用ICMP ping来监控充节点运行情况。Zabbix使用fping处理ICMP ping的请求&#xff0c;需要安装fping程序&#xff0c;安装完毕之后需要在zabinx_server.conf中的参数FpingLocation配置fping安装的路径。由于fping默…...

网站的网站建设公司/宁波seo企业网络推广

Spring 框架作为 Java 开发中最流行的框架之一&#xff0c;其核心特性之一就是依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;。在Spring中&#xff0c;依赖注入是通过 IOC 容器&#xff08;Inversion of Control&#xff0c;控制反转&#xff09;来实现…...