qt 元对象系统及属性系统
Qt元对象系统(QMetaObject)
Qt 的元对象系统叫 Meta-Object-System,提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。即使编译器不支持RTTI(RTTI的实现耗费了很大的时间和存储空间,这就会降低程序的性能),我们也能动态获取类型信息。
元对象实质上是对类的描述
但是,元对象是基于三个条件的:
1、该类必须继承自QObject类
2、必须在类的私有声明区声明Q_OBJECT宏(在类定义的时候,如果没有指定public,
则默认为private,用来启用元对象功能,比如动态属性、信号和槽)。
3、 元对象编译器Meta-Object Compiler(moc)为 QObject的子类实现元对象
特性提供必要的代码。
有了元对象系统后,我们就可以使用Qt的信号和槽了。
moc(Meta-Object Compiler)元对象预编译器。
moc读取一个c++头文件。如果它找到包含Q_OBJECT宏的一个或多个类声明,它会生成一个包含这些类的元对象代码的c++源文件,并且以moc_作为前缀。
信号和槽机制、运行时类型信息和动态属性系统需要元对象代码。
由moc生成的c++源文件必须编译并与类的实现联系起来。通常,moc不是手工调用的,而是由构建系统自动调用的。
获取类关联的元对象的函数是:metaObject
QMetaObject *mtobj = QObject::metaObject()
如:
QPushButton *btn=new QPushButton();
const QMetaObject *metaPtr=btn->metaObject(); //获取元对象指针
常用的函数:
(1)函数QMetaObject::className():该函数运行时返回类名称的字符串
(2)函数QObjetc::inhetits()。可以判断一个对象是不是继承自某个类的实例。顶层的父类是QObject ;
(3)函数QMetaObject::superClass()。用来返回该元对象所描述类的父类的元对象,通过父类的元对象可以获取父类的一些元数据;
(4)函数qobject_cast(): 对于Object及其子类对象,可以使用函数qobject_cast()进行动态类型转换,此处可以理解为c++中的强制类型转换
属性系统(Q_PROPERTY)
在QObject的子类中,使用宏Q_PROPERTY定义属性
Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
Q_PROPERTY()宏定义一个返回值类型为type,名称为name的属性。属性的类型可以是QVarient支持的任何类型( C++标准类型、类名、结构体、枚举等),也可以用户自定义类型。
READ:用于读取属性值。
WRITE:写访问器函数是可选的。用于设置属性值。它必须返回void,并且必须只接受一个参数,要么是属性的类型,要么是指向该类型的指针或引用。
MEMBER:如果未指定读取访问器函数,则需要成员变量关联。这使得给定的成员变量可读写,而无需创建读写访问器函数。使用MEMBER可以替代READ、WRITE。
RESET:复位功能是可选的。它用于将属性设置回其特定于上下文的默认值。
NOTIFY:通知信号是可选的。如果已定义,它应该指定该类中的一个现有信号,该信号在属性值更改时发出。
定义属性:
头文件:#ifndef COLORMAKER_H#define COLORMAKER_H#include <QObject>class CTest{public:CTest(){}int nAge;QString strName;};Q_DECLARE_METATYPE(CTest)class ColorMaker : public QObject{Q_OBJECTpublic:explicit ColorMaker(QObject *parent = nullptr);~ColorMaker();Q_PROPERTY(int value READ getvalue WRITE setvalue NOTIFY valueChanged);Q_PROPERTY(CTest test READ gettest WRITE settest NOTIFY testChanged);//使用自定义的类int getvalue() const;void setvalue(const int& value);CTest gettest() const;void settest(const CTest& test);signals:void valueChanged(int value);void testChanged(CTest test);private:int m_value;CTest m_test;};#endif // COLORMAKER_H源文件#include "ColorMaker.h"ColorMaker::ColorMaker(QObject *parent){}ColorMaker::~ColorMaker(){}int ColorMaker::getvalue() const{return m_value;}void ColorMaker::setvalue(const int &value){m_value = value;emit valueChanged(m_value);}CTest ColorMaker::gettest() const{return m_test;}void ColorMaker::settest(const CTest &test){m_test = test;emit testChanged(m_test);}
使用属性:
属性的读写既可以使用各个属性自己的读写函数,也可以使用属性通用的函数:setProperty() 写属性,property() 读属性,都是通过属性的名称来寻找特定属性实现读写。
bool setProperty(const char *name, const QVariant &value);
QVariant property(const char *name) const;
setProperty() 第一个参数是普通字符串,就是属性的名称,第二个参数是属性的数值。QVariant 是 Qt 定义的通用变量类型,标准 C++ 的类型和 Qt 自己的数值类型都可以自动转为 QVariant 类的对象。
int propertyCount() const; 通过元对象获取属性的个数
QMetaProperty property(int index) const; 获取属性
QMetaProperty 的const char *name() const; 获取属性名
例子:
#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include "ColorMaker.h"QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEclass Widget : public QWidget{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void recv(int nval);void recvtest(CTest test);private:Ui::Widget *ui;};#endif // WIDGET_H源文件#include "widget.h"#include "ui_widget.h"#include <QDebug>#include <QMetaProperty>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){ui->setupUi(this);ColorMaker *cm = new ColorMaker();connect(cm,&ColorMaker::valueChanged,this,&Widget::recv);connect(cm,&ColorMaker::testChanged,this,&Widget::recvtest);cm->setvalue(1);int value = cm->getvalue();cm->setProperty("value", 2);value = cm->property("value").toInt();CTest test;test.nAge = 2;test.strName = "qq";cm->setProperty("test",QVariant::fromValue(test));CTest test1 = qvariant_cast<CTest>(cm->property("test"));QObject *object = cm;const QMetaObject *metaobject = object->metaObject();int ncount = metaobject->propertyCount();for (int i = 0; i < ncount; ++i){QMetaProperty metaproperty = metaobject->property(i);const char *name = metaproperty.name();qDebug() << name;QVariant value = object->property(name);qDebug() << value;}CTest s;s.nAge = 1;s.strName = "hello";QVariant varTest;varTest.setValue(s);QVariant var = QVariant::fromValue(s);bool b = var.canConvert<CTest>();if(b){CTest test = var.value<CTest>();CTest test1 = qvariant_cast<CTest>(var);qDebug() << test.nAge;qDebug() << test.strName;}}Widget::~Widget(){delete ui;}void Widget::recv(int nval){int a = nval;qDebug() << a;}void Widget::recvtest(CTest test){qDebug() << test.nAge;qDebug() << test.strName;}
作用:
- 属性系统提供了可以像操作普通的数据成员一样操作这些自定义属性的方法,同时也可以利用Qt的信号槽系统来监听属性值的变化。
使用场景:
- Q_PROPERTY用于c++类注册到qml交互上。在c++的变化发送信号,而在qml上接收信号,实现处理槽函数。这个使用于qml导出到c++类,c++类获取和设置qml的属性。
- 自定义qt designer 插件 在ui上可以直接看到并设置属性值、信号槽。
延伸:
Q_DECLARE_METATYPE
Q_DECLARE_METATYPE(Type)向Qt元系统注册一些非基本类型。Type可以是自定义类、结构体、枚举。一旦注册后,在Qt元系统中就可以很方便的利用这些非基本类型。
如果Type在命名空间中,Q_DECLARE_METATYPE()必须在命名空间外部。
定义:
class CTest
{
public:
CTest(){}
int nAge;
QString strName;
};
//或者
//struct CTest
//{
// int nAge;
// QString strName;
//};
Q_DECLARE_METATYPE(CTest)
使用:
设置函数
QVariant::setValue或者 QVariant fromValue
获取函数
Value 或者 QVariant fromValue
CTest s;
s.nAge = 1;
s.strName = "hello";
QVariant varTest;
varTest.setValue(s);
QVariant var = QVariant::fromValue(s);
bool b = var.canConvert<CTest>();
if(b)
{
CTest test = var.value<CTest>();
CTest test1 = qvariant_cast<CTest>(var);
qDebug() << test.nAge;
qDebug() << test.strName;
}
枚举常用宏
Q_ENUM
作用:宏Q_ENUM会向元对象系统注册一个枚举类型。
使用注意事项:
1.使用Q_ENUM之前,必须在类中先声明Q_OBJECT或Q_GADGET宏。
2.Q_ENUM(枚举类型)必须放在枚举声明之后,放在前面编译器会报错。
如注册Orientation枚举
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
enum Orientation {
Up = 1,
Down = 2,
Left = 3,
Right = 4
};
Q_ENUM(Orientation) //向元对象系统注册枚举类型
public slots:
void recv(int nval);
void recvtest(CTest test);
private:
Ui::Widget *ui;
};
使用静态函数QMetaEnum::fromType()来获取QMetaEnum
QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>(); //MyEnum是当前类,Orientation是枚举的类型
QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>(); //通过静态函数fromType获取QMetaEnum对象
QString name = metaEnum.name(); //枚举名称
int count = metaEnum.keyCount(); //枚举数量
QString keyIndex = metaEnum.key(0); //下标为0的key
int valueIndex = metaEnum.value(0); //下标为0的value
QString Key = metaEnum.valueToKey(Widget::Left); //通过value得到key
int value = metaEnum.keyToValue("Left"); //通过key得到value
qDebug() << "枚举的名称:" << name;
qDebug() << "枚举的数量:" << QString::number(count);
qDebug() << "index下标的key值:" << keyIndex;
qDebug() << "index下标的Value值:" << QString::number(valueIndex); qDebug() << "value对应的key值:" << Key;
qDebug() << "key值对应的Vaule:" << QString::number(value);
Q_FLAG
为了解决枚举变量的组合使用,增加枚举变量间与或非计算。且运算结果还是一个QFlags包装的枚举量。一个普通的枚举类型包装成QFlags型,需要使用Q_DECLARE_FLAGS宏,在全局任意地方使用”|"操作符计算自定义的枚举量,需要使用Q_DECLARE_OPERATORS_FOR_FLAGS宏。
Q_DECLARE_FLAGS()宏
Q_DECLARE_FLAGS(Flags, Enum)宏展开为 typedef QFlags<Enum> Flags;
QFlags<Enum>是一个模板类,其中Enum是枚举类型,QFlags用于存储枚举值的组合
Q_DECLARE_OPERATORS_FOR_FLAGS()宏
1.Q_DECLARE_OPERATORS_FOR_FLAGS(Flags)赋予了Flags一个全局操作符“|”,没有这个宏语句,Flags量之间进行与操作后的结果将是一个int值,而不是Flags值。
2.Q_DECLARE_OPERATORS_FOR_FLAGS必须定义在类外。
3.Q_DECLARE_OPERATORS_FOR_FLAGS只提供了“或”操作,没有提供“与”“非”操作。
例子
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "ColorMaker.h"
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
enum Orientation {
Up = 1,
Down = 2,
Left = 4,
Right = 8
};
Q_ENUM(Orientation) //向元对象系统注册枚举类型
Q_DECLARE_FLAGS(OrientationFlag,Orientation)
Q_FLAG(OrientationFlag)
public slots:
void recv(int nval);
void recvtest(CTest test);
private:
Ui::Widget *ui;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Widget::OrientationFlag)
#endif // WIDGET_H
使用
QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>(); //通过静态函数fromType获取QMetaEnum对象
QString name = metaEnum.name(); //枚举名称
int count = metaEnum.keyCount(); //枚举数量
QString keyIndex = metaEnum.key(0); //下标为0的key
int valueIndex = metaEnum.value(0); //下标为0的value
QString Key = metaEnum.valueToKey(Widget::Left); //通过value得到key
int value = metaEnum.keyToValue("Left"); //通过key得到value
QString Key2 = metaEnum.valueToKeys(Widget::Left | Widget::Right); //通过value得到key
int value2 = metaEnum.keysToValue("Up | Down");
qDebug() << "枚举的名称:" << name;
qDebug() << "枚举的数量:" << QString::number(count);
qDebug() << "index下标的key值:" << keyIndex; //Up
qDebug() << "index下标的Value值:" << QString::number(valueIndex); //1
qDebug() << "value对应的key值:" << Key; //Left
qDebug() << "value对应的key值:" << Key2; //Left|Right
qDebug() <<"key值对应的Vaule:"<< QString::number(value);//4
qDebug() <<"key值对应的Vaule:"<< QString::number(value2);//3
QMetaObject::invokeMethod()
作用:使用QMetaObject::invokeMethod()调用QObject的某个注册到元对象系统中的方法。支持跨线程调用。
一般该方法是信号、或者槽函数。无论这个方法是公有的、保护的还是私有的。
如果是普通函数,则需要使用Q_INVOKABLE宏把函数注册到元对象系统。
格式:
bool QMetaObjcet:invokeMethod(
QObject* obj,
const char* member,
Qt::ConnectionType type,
QGenericReturnArgument ret,
QGenericReturnArgument vla0 = QGenericReturnArgument(0),
QGenericReturnArgument vla1 = QGenericReturnArgument(),
QGenericReturnArgument vla2 = QGenericReturnArgument(),
QGenericReturnArgument vla3 = QGenericReturnArgument(),
QGenericReturnArgument vla4 = QGenericReturnArgument(),
QGenericReturnArgument vla5 = QGenericReturnArgument(),
QGenericReturnArgument vla6 = QGenericReturnArgument(),
QGenericReturnArgument vla7 = QGenericReturnArgument(),
QGenericReturnArgument vla8 = QGenericReturnArgument(),
QGenericReturnArgument vla9 = QGenericReturnArgument());
返回值:返回true说明调用成功;返回false,要么是因为没有你说的那个方法,要么是参数类型不匹配;
obj:被调用对象的指针;
member:方法名字 必须是信号、槽,以及Qt元对象系统能识别的类型, 如果不是信号和槽,可以使用qRegisterMetaType()来注册数据类型。此外,使用Q_INVOKABLE来声明函数,也可以正确调用。
type:连接类型;invokeMethod为信号槽而生,你可以指定连接类型,如果被调用的对象和发起调用的线程是同一线程,那么可以使用Qt::DirectConnection、Qt::AutoConnection、Qt::QueuedConnection,如果被调用对象在另一个线程,那么建议使用Qt::QueuedConnection;
ret:接收返回值;
然后就是多达10个可以传递给被调用方法的参数;(看来信号槽的参数个数是有限制的,最好不要超过10个)
QGenericArgument和QGenericReturnArgument是内部帮助程序类,由于可以动态调用信号和槽,因此必须使用Q_ARG()和Q_RETURN_ARG()宏来封装参数
注意:此功能是线程安全的。
例子:
#ifndef COLORMAKER_H#define COLORMAKER_H#include <QObject>class CTest{public:CTest(){}int nAge;QString strName;};Q_DECLARE_METATYPE(CTest)class ColorMaker : public QObject{Q_OBJECTpublic:explicit ColorMaker(QObject *parent = nullptr);~ColorMaker();private slots:QString testslot(int n);};#endif // COLORMAKER_H#include "ColorMaker.h"ColorMaker::ColorMaker(QObject *parent){}ColorMaker::~ColorMaker(){}QString ColorMaker::testslot(int n){return "q";}调用#include "widget.h"//#include "qobjectdefs.h"#include "ui_widget.h"#include <QDebug>#include <QMetaProperty>#include <QMetaObject>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){ui->setupUi(this);ColorMaker *cm = new ColorMaker();QString retVal;QMetaObject::invokeMethod(this,"test", Qt::DirectConnection);QMetaObject::invokeMethod(cm,"testslot", Qt::DirectConnection,Q_RETURN_ARG(QString, retVal),Q_ARG(int,1));}void Widget::test(){int a = 1;}
Q_INVOKABLE
作用:定义一个类的成员函数时使用Q_INVOKABLE宏来修饰,就可以让该方法被元对象系统调用(即把该函数注册到元对象系统)。
注意事项:Q_INVOKABLE宏必须放在返回类型前面。
如
private :
Q_INVOKABLE QString testmd(int n);
QString ColorMaker::testmd(int n)
{
return "md";
}
使用场景:
- c++和qml混用.
普通类成员函数是不能直接在qml使用。除非是声明为槽函数或者用Q_INVOKABLE声明函数.
- 和QMetaObject::invokeMethod()结合使用,invokeMethod函数的参数member方法如果是自定义的普通函数,需使用Q_INVOKABLE宏注册到元对象系统。
例子
class ColorMaker : public QObject{Q_OBJECTpublic:explicit ColorMaker(QObject *parent = nullptr);~ColorMaker();private :Q_INVOKABLE QString testmd(int n);};ColorMaker *cm = new ColorMaker();QMetaObject::invokeMethod(cm,"testmd", Qt::DirectConnection,Q_RETURN_ARG(QString, retVal),Q_ARG(int,1));
完整代码:
#ifndef COLORMAKER_H#define COLORMAKER_H#include <QObject>class CTest{public:CTest(){}int nAge;QString strName;};Q_DECLARE_METATYPE(CTest)class ColorMaker : public QObject{Q_OBJECTpublic:explicit ColorMaker(QObject *parent = nullptr);~ColorMaker();Q_PROPERTY(int value READ getvalue WRITE setvalue NOTIFY valueChanged);Q_PROPERTY(CTest test READ gettest WRITE settest NOTIFY testChanged);//使用自定义的类int getvalue() const;void setvalue(const int& value);CTest gettest() const;void settest(const CTest& test);signals:void valueChanged(int value);void testChanged(CTest test);private slots:QString testslot(int n);private :Q_INVOKABLE QString testmd(int n);private:int m_value;CTest m_test;};#endif // COLORMAKER_H#include "ColorMaker.h"ColorMaker::ColorMaker(QObject *parent){}ColorMaker::~ColorMaker(){}int ColorMaker::getvalue() const{return m_value;}void ColorMaker::setvalue(const int &value){m_value = value;emit valueChanged(m_value);}CTest ColorMaker::gettest() const{return m_test;}void ColorMaker::settest(const CTest &test){m_test = test;emit testChanged(m_test);}QString ColorMaker::testslot(int n){return "q";}QString ColorMaker::testmd(int n){return "md";}#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include "ColorMaker.h"QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEclass Widget : public QWidget{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();enum Orientation {Up = 1,Down = 2,Left = 4,Right = 8};Q_ENUM(Orientation) //向元对象系统注册枚举类型Q_DECLARE_FLAGS(OrientationFlag,Orientation)Q_FLAG(OrientationFlag)public slots:void recv(int nval);void recvtest(CTest test);public slots:void test();private:Ui::Widget *ui;};Q_DECLARE_OPERATORS_FOR_FLAGS(Widget::OrientationFlag)#endif // WIDGET_H#include "widget.h"//#include "qobjectdefs.h"#include "ui_widget.h"#include <QDebug>#include <QMetaProperty>#include <QMetaObject>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget){ui->setupUi(this);QMetaEnum metaEnum = QMetaEnum::fromType<Widget::Orientation>(); //通过静态函数fromType获取QMetaEnum对象QString name = metaEnum.name(); //枚举名称int count = metaEnum.keyCount(); //枚举数量QString keyIndex = metaEnum.key(0); //下标为0的keyint valueIndex = metaEnum.value(0); //下标为0的valueQString Key = metaEnum.valueToKey(Widget::Left); //通过value得到keyint value = metaEnum.keyToValue("Left"); //通过key得到valueQString Key2 = metaEnum.valueToKeys(Widget::Left | Widget::Right); //通过value得到keyint value2 = metaEnum.keysToValue("Up | Down");qDebug() << "枚举的名称:" << name;qDebug() << "枚举的数量:" << QString::number(count);qDebug() << "index下标的key值:" << keyIndex; //UpqDebug() << "index下标的Value值:" << QString::number(valueIndex); //1qDebug() << "value对应的key值:" << Key; //LeftqDebug() << "value对应的key值:" << Key2; //Left|RightqDebug() <<"key值对应的Vaule:"<< QString::number(value);//4qDebug() <<"key值对应的Vaule:"<< QString::number(value2);//3ColorMaker *cm = new ColorMaker();QObject *object = cm;connect(cm,&ColorMaker::valueChanged,this,&Widget::recv);connect(cm,&ColorMaker::testChanged,this,&Widget::recvtest);QString retVal;QMetaObject::invokeMethod(this,"test", Qt::DirectConnection);QMetaObject::invokeMethod(cm,"testslot", Qt::DirectConnection,Q_RETURN_ARG(QString, retVal),Q_ARG(int,1));QMetaObject::invokeMethod(cm,"testmd", Qt::DirectConnection,Q_RETURN_ARG(QString, retVal),Q_ARG(int,1));cm->setvalue(1);int value1 = cm->getvalue();cm->setProperty("value", 2);value = cm->property("value").toInt();CTest test;test.nAge = 2;test.strName = "qq";cm->setProperty("test",QVariant::fromValue(test));CTest test1 = qvariant_cast<CTest>(cm->property("test"));const QMetaObject *metaobject = object->metaObject();int ncount = metaobject->propertyCount();for (int i = 0; i < ncount; ++i){QMetaProperty metaproperty = metaobject->property(i);const char *name = metaproperty.name();qDebug() << name;QVariant value = object->property(name);qDebug() << value;}CTest s;s.nAge = 1;s.strName = "hello";QVariant varTest;varTest.setValue(s);QVariant var = QVariant::fromValue(s);bool b = var.canConvert<CTest>();if(b){CTest test = var.value<CTest>();CTest test1 = qvariant_cast<CTest>(var);qDebug() << test.nAge;qDebug() << test.strName;}}Widget::~Widget(){delete ui;}void Widget::recv(int nval){int a = nval;qDebug() << a;}void Widget::recvtest(CTest test){qDebug() << test.nAge;qDebug() << test.strName;}void Widget::test(){int a = 1;}
相关文章:
qt 元对象系统及属性系统
Qt元对象系统(QMetaObject) Qt 的元对象系统叫 Meta-Object-System,提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。即使编译器不支持RTTI(RTTI的实现耗费了很大的时间和存储空间,这就会降低程序的性能)&…...

2024年MathorCup数学建模A题移动通信网络中PCI规划问题解题文档与程序
2024年第十四届MathorCup高校数学建模挑战赛 A题 移动通信网络中PCI规划问题 原题再现: 物理小区识别码(PCI)规划是移动通信网络中下行链路层上,对各覆盖小区编号进行合理配置,以避免 PCI 冲突、PCI 混淆以及 PCI 模3 千扰等现象。PCI 规划…...

Learn something about front end——颜色
好装的标题啊哈哈哈哈哈哈 最近get了一个学习前端的网站叫FreeCodeCamp 原色:rgb三个值的其中一个值拉满,比如说rgb(255,0,0)是红色这样,三个主色: 红色 rgb(255, 0, 0) #FF0000绿色 rgb(0, 255, 0) #00FF00蓝色 rgb(0, 0, …...

各大厂都推出鸿蒙APP了,你就一定要学习一下鸿蒙APP测试了!
2023年8月,华为推出鸿蒙4.0,由于其广泛的用户基础和品牌传播力,在短短几个月的时间,使用鸿蒙4.0系统的设备就达到千万级别,并且在9月份发售Mate 6之后,还在装机量的增长更加迅猛。 基于此,11月…...

ppt里的音乐哪里来的?
心血来潮,想照着大神的模板套一个类似于快闪的ppt。 ppt里是有一段音乐的,那段音乐就是从幻灯片第二页开始响起的。 但是我就找不到音乐在哪。 甚至我把ppt里的所有素材都删除了,再看动画窗格,仍然是空无一物,显然&…...
【算法】标签算法及其运作流程
标签算法 1. 标签算法及其运作流程2. 标签算法主要有哪些?3.用python语言举例实现聚类 1. 标签算法及其运作流程 标签算法是一种用于自动为数据或文本内容添加标签或分类的算法。这些标签可以帮助组织、检索和理解数据,是信息管理和数据挖掘中的重要工具…...

【数据结构】习题之链表的回文结构和相交链表
👑个人主页:啊Q闻 🎇收录专栏:《数据结构》 🎉前路漫漫亦灿灿 前言 今日的习题是关于链表的,分别是链表的回文结构和相交链表的判断。 链表的回文结构 题目为:链表的回文结…...

5个常见的前端手写功能:New、call apply bind、防抖和节流、instanceof、ajax
实现New 首先创建一个新的空对象设置原型,将对象的原型设置为函数的prototype对象让函数的this指向这个对象,执行构造函数的代码判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类…...
WPF 跨线程-Dispatcher:详解与示例
在 WPF 应用程序中,UI 线程负责处理用户界面元素的所有操作,例如绘制、布局和事件处理。由于 WPF 控件是线程敏感的,只能在 UI 线程上访问它们。如果我们想在后台线程中执行 UI 操作,我们就需要使用 Dispatcher 来确保这些操作在正…...
[c++][netcdf]通过c\c++读取字段的scale_factor与add_offset
函数:c void readScaleAndOffset(const char* FileName,const char* VarName) {NcFile dataFile(FileName, NcFile::read);NcVar Varf dataFile.getVar(VarName);//查看维度cout << "XSizef" << Varf.getDim(0).getSize() << endl;co…...

技术速递|.NET 智能组件简介 – AI 驱动的 UI 控件
作者:Daniel Roth 排版:Alan Wang AI 的最新进展有望彻底改变我们与软件交互和使用软件的方式。然而,将 AI 功能集成到现有软件中可能面临一些挑战。因此,我们开发了新的 .NET 智能组件,这是一组真正有用的 AI 支持的 …...

保护C#代码的艺术:深入浅出代码混淆技术
摘要 在C#开发中,代码的保护是一个不可忽视的问题。本文深入探讨了几种常用的C#代码混淆工具,帮助开发者理解如何有效地保护代码不被反编译。同时,本文也对混淆技术的优缺点进行了分析,并提供了一些实际使用的建议。 引言 C#是…...
多线程CountDownLatch使用
1、简介 CountDownLatch是一个同步工具类,用来携调多个线程之间的同步,它是是使用一个计数器进行实现的,计数器初始值为线程数量。当每一个线程完成自己任务后,计数器的值就会减1。当计数器的值为0时,表示所有的线程都…...

高校心理教育辅导系统|基于Springboot的高校心理教育辅导系统设计与实现(源码+数据库+文档)
高校心理教育辅导系统目录 目录 基于Springboot的高校心理教育辅导系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、学生功能模块的实现 (1)学生登录界面 (2)留言反馈界面 (3)试卷列表界…...
Rockchip Android13 Vold(三):App层
目录 前言 一:处理Volumes 1、接收StorageVolume 2、创建MediaVolume 3、附加MediaVolume...

数据结构——单链表(C语言版)
文章目录 一、链表的概念及结构二、单链表的实现SList.h链表的打印申请新的结点链表的尾插链表的头插链表的尾删链表的头删链表的查找在指定位置之前插入数据在指定位置之后插入数据删除pos结点删除pos之后的结点销毁链表 三、完整源代码SList.hSList.ctest.c 一、链表的概念及…...

:app debug:armeabi-v7a failed to configure C/C++
报错信息 由于刚换电脑不久,新建native c工程时,出现报错如下: :app debug:armeabi-v7a failed to configure C/C null java.lang.NullPointerExceptionat com.android.build.gradle.tasks.CmakeQueryMetadataGenerator.getProcessBuilder(…...
计算机网络——应用层(4)DHCP和套接字编程
一、动态主机配置协议DHCP 1、关于协议配置: 在协议软件中,给协议参数赋值的动作就叫协议配置一个协议软件在使用前必须已被正确配置,具体的配置信息取决于协议栈连接到互联网的计算机的协议软件需要正确配置的参数包括①IP地址;…...

TF-IDF演算法(Term Frequency - Inverse Document Frequency)最好懂筆記
前情提要 BoW (Bag of Words) 演算法 假设现在有M篇文章,一共使用了N个词汇(term),我们就可以将文章转换成以下类型的矩阵,其中column1和row1的“10”表示“文章1”中出现了10次“词汇1”,“文章1”也可以…...

2024年4月最新版GPT
2024年4月最新版ChatGPT/GPT4, 附上最新的使用教程。 随着人工智能技术的不断发展,ChatGPT和GPT4已经成为了人们日常生活中不可或缺的助手。2024年4月,OpenAI公司推出了最新版本的GPT4,带来了更加强大的功能和更加友好的用户体验。本文将为大家带来最新版GPT4的实用…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...

jdbc查询mysql数据库时,出现id顺序错误的情况
我在repository中的查询语句如下所示,即传入一个List<intager>的数据,返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致,会导致返回的id是从小到大排列的,但我不希望这样。 Query("SELECT NEW com…...