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

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可以替代READWRITE

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;}

作用:

  1. 属性系统提供了可以像操作普通的数据成员一样操作这些自定义属性的方法,同时也可以利用Qt的信号槽系统来监听属性值的变化。

使用场景:

  1. Q_PROPERTY用于c++类注册到qml交互上。在c++的变化发送信号,而在qml上接收信号,实现处理槽函数。这个使用于qml导出到c++类,c++类获取和设置qml的属性。
  2. 自定义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";

}

使用场景:

  1. c++和qml混用.

普通类成员函数是不能直接在qml使用。除非是声明为槽函数或者用Q_INVOKABLE声明函数.

  1. 和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&#xff0c;提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。即使编译器不支持RTTI&#xff08;RTTI的实现耗费了很大的时间和存储空间&#xff0c;这就会降低程序的性能&#xff09;&…...

2024年MathorCup数学建模A题移动通信网络中PCI规划问题解题文档与程序

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

Learn something about front end——颜色

​ 好装的标题啊哈哈哈哈哈哈 最近get了一个学习前端的网站叫FreeCodeCamp 原色&#xff1a;rgb三个值的其中一个值拉满&#xff0c;比如说rgb(255,0,0)是红色这样&#xff0c;三个主色&#xff1a; 红色 rgb(255, 0, 0) #FF0000绿色 rgb(0, 255, 0) #00FF00蓝色 rgb(0, 0, …...

各大厂都推出鸿蒙APP了,你就一定要学习一下鸿蒙APP测试了!

2023年8月&#xff0c;华为推出鸿蒙4.0&#xff0c;由于其广泛的用户基础和品牌传播力&#xff0c;在短短几个月的时间&#xff0c;使用鸿蒙4.0系统的设备就达到千万级别&#xff0c;并且在9月份发售Mate 6之后&#xff0c;还在装机量的增长更加迅猛。 基于此&#xff0c;11月…...

ppt里的音乐哪里来的?

心血来潮&#xff0c;想照着大神的模板套一个类似于快闪的ppt。 ppt里是有一段音乐的&#xff0c;那段音乐就是从幻灯片第二页开始响起的。 但是我就找不到音乐在哪。 甚至我把ppt里的所有素材都删除了&#xff0c;再看动画窗格&#xff0c;仍然是空无一物&#xff0c;显然&…...

【算法】标签算法及其运作流程

标签算法 1. 标签算法及其运作流程2. 标签算法主要有哪些&#xff1f;3.用python语言举例实现聚类 1. 标签算法及其运作流程 标签算法是一种用于自动为数据或文本内容添加标签或分类的算法。这些标签可以帮助组织、检索和理解数据&#xff0c;是信息管理和数据挖掘中的重要工具…...

【数据结构】习题之链表的回文结构和相交链表

&#x1f451;个人主页&#xff1a;啊Q闻 &#x1f387;收录专栏&#xff1a;《数据结构》 &#x1f389;前路漫漫亦灿灿 前言 今日的习题是关于链表的&#xff0c;分别是链表的回文结构和相交链表的判断。 链表的回文结构 题目为&#xff1a;链表的回文结…...

5个常见的前端手写功能:New、call apply bind、防抖和节流、instanceof、ajax

实现New 首先创建一个新的空对象设置原型&#xff0c;将对象的原型设置为函数的prototype对象让函数的this指向这个对象&#xff0c;执行构造函数的代码判断函数的返回值类型&#xff0c;如果是值类型&#xff0c;返回创建的对象。如果是引用类型&#xff0c;就返回这个引用类…...

WPF 跨线程-Dispatcher:详解与示例

在 WPF 应用程序中&#xff0c;UI 线程负责处理用户界面元素的所有操作&#xff0c;例如绘制、布局和事件处理。由于 WPF 控件是线程敏感的&#xff0c;只能在 UI 线程上访问它们。如果我们想在后台线程中执行 UI 操作&#xff0c;我们就需要使用 Dispatcher 来确保这些操作在正…...

[c++][netcdf]通过c\c++读取字段的scale_factor与add_offset

函数&#xff1a;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 控件

作者&#xff1a;Daniel Roth 排版&#xff1a;Alan Wang AI 的最新进展有望彻底改变我们与软件交互和使用软件的方式。然而&#xff0c;将 AI 功能集成到现有软件中可能面临一些挑战。因此&#xff0c;我们开发了新的 .NET 智能组件&#xff0c;这是一组真正有用的 AI 支持的 …...

保护C#代码的艺术:深入浅出代码混淆技术

摘要 在C#开发中&#xff0c;代码的保护是一个不可忽视的问题。本文深入探讨了几种常用的C#代码混淆工具&#xff0c;帮助开发者理解如何有效地保护代码不被反编译。同时&#xff0c;本文也对混淆技术的优缺点进行了分析&#xff0c;并提供了一些实际使用的建议。 引言 C#是…...

多线程CountDownLatch使用

1、简介 CountDownLatch是一个同步工具类&#xff0c;用来携调多个线程之间的同步&#xff0c;它是是使用一个计数器进行实现的&#xff0c;计数器初始值为线程数量。当每一个线程完成自己任务后&#xff0c;计数器的值就会减1。当计数器的值为0时&#xff0c;表示所有的线程都…...

高校心理教育辅导系统|基于Springboot的高校心理教育辅导系统设计与实现(源码+数据库+文档)

高校心理教育辅导系统目录 目录 基于Springboot的高校心理教育辅导系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、学生功能模块的实现 &#xff08;1&#xff09;学生登录界面 &#xff08;2&#xff09;留言反馈界面 &#xff08;3&#xff09;试卷列表界…...

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++

报错信息 由于刚换电脑不久&#xff0c;新建native c工程时&#xff0c;出现报错如下&#xff1a; :app debug:armeabi-v7a failed to configure C/C null java.lang.NullPointerExceptionat com.android.build.gradle.tasks.CmakeQueryMetadataGenerator.getProcessBuilder(…...

计算机网络——应用层(4)DHCP和套接字编程

一、动态主机配置协议DHCP 1、关于协议配置&#xff1a; 在协议软件中&#xff0c;给协议参数赋值的动作就叫协议配置一个协议软件在使用前必须已被正确配置&#xff0c;具体的配置信息取决于协议栈连接到互联网的计算机的协议软件需要正确配置的参数包括①IP地址&#xff1b…...

TF-IDF演算法(Term Frequency - Inverse Document Frequency)最好懂筆記

前情提要 BoW (Bag of Words) 演算法 假设现在有M篇文章&#xff0c;一共使用了N个词汇&#xff08;term&#xff09;&#xff0c;我们就可以将文章转换成以下类型的矩阵&#xff0c;其中column1和row1的“10”表示“文章1”中出现了10次“词汇1”&#xff0c;“文章1”也可以…...

2024年4月最新版GPT

2024年4月最新版ChatGPT/GPT4, 附上最新的使用教程。 随着人工智能技术的不断发展&#xff0c;ChatGPT和GPT4已经成为了人们日常生活中不可或缺的助手。2024年4月,OpenAI公司推出了最新版本的GPT4,带来了更加强大的功能和更加友好的用户体验。本文将为大家带来最新版GPT4的实用…...

机器学习——模型评价

概述 在机器学习中&#xff0c;模型评价是评估和比较不同模型性能的关键步骤之一。它是通过对模型的预测结果与真实标签进行比较&#xff0c;从而量化模型的预测能力、泛化能力和稳定性。模型评价旨在选择最佳的模型&#xff0c;理解模型的行为&#xff0c;并为模型的改进提供…...

ARP代理

10.1.0.1/8 和10.2.0.1/8是在同一个网段 10.1.0.2/16 和10.2.0.2/16 不在同一个网段 10.1.0.1/8 和10.1.0.2/16 是可以ping通的 包发出来了&#xff0c;报文有发出来&#xff0c;目的地址是广播包 广播请求&#xff0c;发到路由器的接口G 0/0/0 target不是本接口&#xff0…...

手写前端控制并发任务

思路&#xff1a; 主要通过异步等待队列执行的原理。 当前执行的任务数达到最大值的时候&#xff0c;再继续执行的任务会放入等待队列里&#xff0c;直到当前任务执行结束后&#xff0c;减少一个当前任务数&#xff0c;并且判断队列中是否有任务&#xff0c;如果有则按顺序执…...

好用的Python开发工具合集

​ Python是一种功能强大且易于学习的编程语言&#xff0c;被广泛应用于数据科学、机器学习、Web开发等领域。随着Python在各个领域的应用越来越广泛&#xff0c;越来越多的Python开发工具也涌现出来。但是&#xff0c;对于新手来说&#xff0c;选择一款合适的Python开发工具可…...

近屿智能全新推出AI培训产品:AIGC大模型工程师与产品经理学习路径图

如今&#xff0c;人工智能和自然语言处理技术的发展&#xff0c;使得AI生成的内容&#xff08;AIGC&#xff0c;AI Generated Content&#xff09;领域开发出了巨大的潜力。就像业内巨头OpenAI公司&#xff0c;开发出了一系列自然语言处理模型ChatGPT&#xff0c;不仅带动了全世…...

Vue 3中的反向代理 和如何在服务器配置反向代理

如何在Vue 3项目中配置反向代理&#xff0c;让前端开发变得爽到爆&#xff01;还有个小插曲&#xff0c;Vite为我们提供了更简单的方式&#xff0c;就像找对象一样直接。 首先&#xff0c;我们来谈谈反向代理是什么。简单来说&#xff0c;反向代理就像是前端和后端之间的婚姻介…...

【机器学习】贝叶斯算法在机器学习中的应用与实例分析

贝叶斯算法在机器学习中的应用与实例分析 一、贝叶斯算法原理及重要性二、朴素贝叶斯分类器的实现三、贝叶斯网络在自然语言处理中的应用四、总结与展望 在人工智能的浪潮中&#xff0c;机器学习以其独特的魅力引领着科技领域的创新。其中&#xff0c;贝叶斯算法以其概率推理的…...

回归预测 | Matlab实现SSA-GRNN麻雀算法优化广义回归神经网络多变量回归预测(含优化前后预测可视化)

回归预测 | Matlab实现SSA-GRNN麻雀算法优化广义回归神经网络多变量回归预测(含优化前后预测可视化) 目录 回归预测 | Matlab实现SSA-GRNN麻雀算法优化广义回归神经网络多变量回归预测(含优化前后预测可视化)预测效果基本介绍程序设计参考资料预测效果...

SQL SERVER的安装

目录 1.百度SQL SERVER找到图下的所显示的&#xff0c;点击进去 2.找到图下红色框起来的&#xff0c;点击立即下载 3.下载好之后点开&#xff0c;选择下载介质 4.SQLSERVER下载成功之后选择打开文件夹 6.双击后缀名是.iso的镜像文件 7.双击setup.exe进行安装 8.安装成功…...

(十一)C++自制植物大战僵尸游戏客户端更新实现

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/cFP3z 更新检查 游戏启动后会下载服务器中的版本号然后与本地版本号进行对比&#xff0c;如果本地版本号小于服务器版本号就会弹出更新提示。让用户选择是否更新客户端。 在弹出的更新对话框中有显示最新版本更新的内容…...

第三方网站做企业满意度调查/北京互联网公司排名

由于网络的数据流量多集中在中心服务器一端&#xff0c;所以现在所说的负载均衡&#xff0c;多指的是对访问服务器的负载进行均衡&#xff08;或者说分担&#xff09;措施。负载均衡&#xff0c;从结构上分为本地负载均衡和地域负载均衡(全局负载均衡)&#xff0c;前一种是指对…...

邮箱域名怎么填写/网络关键词优化方法

在以前分析过ORA-600[729](SGA内存泄露),这次遇到ORA-600[723](PGA内存泄露)操作系统数据库信息ORACLE V9.2.0.3.0 - Production vsnsta0vsnsql12 vsnxtr3Windows 2000 Version 5.2 Service Pack 2, CPU type 586Oracle9i Enterprise Edition Release 9.2.0.3.0 - ProductionWi…...

东莞企业免费建站/站长平台

都说Android最近行情不好&#xff0c;很多人都遇到瓶颈或放弃或转行。其实这种情况17年18年也是如此&#xff0c;相对比之下&#xff0c;个人认为今年比去年好多了&#xff0c;Android接下来将会走向复苏的春天。 自从Google开始推出AMP项目已经有一年了。除此之外&#xff0c;…...

六安seo网站推广报价/免费职业技能培训网

启动和关闭——管理员手册作者: yangtingkun(http://yangtingkun.itpub.net)发表于: 2004.12.27 18:49分类: 读书笔记出处: http://yangtingkun.itpub.net/post/468/11973---------------------------------------------------------------启动数据库时可以启动到不同的状态&am…...

搜狐快站怎么样/关键词优化技巧有哪些

Linux ***踪迹隐藏攻略 文章作者&#xff1a;xi4oyuLinux ***踪迹隐藏攻略v0.1免责声明&#xff1a;本文仅用于教学目的&#xff0c;如果因为本文造成的***后果本人概不负责,转载请保留。0&#xff0e;前言&#xff1a;被警察叔叔请去喝茶时间很痛苦的事情&#xff0c;各位道长…...

房产局网站建设方案/google国际版入口

解说一下DOS下telnet命令发送邮件 步骤&#xff0c;以我的163邮箱为例 1、開始-->cmd 进入到dos里面 2、输入telnet smtp.163.com 25 C: \Users \Administrator> telnet smtp.163.com 25 回车后返回220 220 163.com Anti-spam GT for Coremail System <…...