Qt元对象系统

第二章Qt元对象系统

文章目录

  • 第二章Qt元对象系统
  • 1.什么是元对象?
  • 2.元对象系统组成
  • 3.信号与槽
    • 信号和槽的本质
    • 绑定信号与槽
    • 自定义槽
      • 定义槽函数必须遵循一下规则
      • 槽函数的类型
      • 自定义槽案例
    • 自定义信号
      • 自定义信号需要遵循以下规则
      • 信号和槽重载二义性问题
  • 4.内存管理
    • 1. 简介
    • 2.关联图
    • 3.详解
    • 4.智能指针
  • 5.属性系统
    • 获取/设置属性值
    • 自己声明属性值
    • 绑定属性
    • QObjectBindableProperty
  • 6.实时类型信息
  • 枚举
  • QMetaObject元信息

元对象系统是一个基于标准C++的扩展,为QT提供了新号与槽机制、实时类型信息、动态属性系统

1.什么是元对象?

在计算机科学中,元对象是这样一个东西:它可以操纵、创建、描述或执行其他对象。元对象描述的的对象称为基对象。元对象可能存在这样的信息:基础对象的类型、接口、类、方法、属性、变量、控制结构等。

2.元对象系统组成

  • QObject
    是QT对象模型的核心,绝大部分的QT类都是从这个类继承而来

  • Q_OBJECT
    Q_OBJECT宏必须出现在类定义的私有部分,用来开启信号和槽、动态属性系统,或QT元对象系统提供的其他服务

  • MOC
    MOC编译器为QObject子类提供了一些实现元对象特性所需要的一些代码。比如说信号,大家只是在类声明的时候声明了所需要的信息,在MOC编译时,会为信号添加函数定义。

3.信号与槽

所谓信号槽,实际就是观察者模式(发布-订阅模式)。当某个时间发生之后,比如按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽-slot)绑定来处理这个信号。也就是说,信号发出时,被连接的槽函数会自动被回调。

信号和槽的本质

信号是由对象发射出去的消息,信号实际上是一个特殊的函数,不需要由程序员实现,而是由QT的moc实现。
槽实际上就是普通的函数。
当我们把对象的信号和槽绑定在一起之后,当信号触发时,与之绑定的槽函数将会自动调用,并把信号参数传递给槽函数。

绑定信号与槽

使用QObject::connect()函数实现

#	Mainwindow.ui
# 创建一个PushButton
# 	Mainwindow.h 在下面加入代码
public slots:
   void onButtonClicked();
# Mainwindow.cpp
#include "MainWindow.h"
#include "./ui_MainWindow.h"

MainWindow::MainWindow(QWidget *parent)
   : QMainWindow(parent)
   , ui(new Ui::MainWindow)
{
   ui->setupUi(this);
   auto con =connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(onButtonClicked()));

   QObject::connect(ui->pushButton_2,&QPushButton::clicked,this,&MainWindow::onButtonClicked);

   //lambda函数写法
   connect(ui->pushButton_3,&QPushButton::clicked,[=](){
       disconnect(con);
       qInfo()<<"断开1的连接";
   });
}
MainWindow::~MainWindow()
{
   delete ui;
}

void MainWindow::onButtonClicked()
{
   qInfo()<<"我被点击了";
}

自定义槽

槽函数就是信号的处理动作,自定义槽函数和自定义的普通函数写法是一样的。只不过自定义的槽函数一般放在public slots:后面。

定义槽函数必须遵循一下规则

  1. 槽函数的返回类型必须是void
  2. 槽函数的参数必须等于或少于信号的参数
  3. 当信号与槽函数的参数数量相同时,它们参数类型要完全一致。

槽函数的类型

  • 成员函数
    • 普通成员函数
    • 静态成员函数
  • 全局函数
  • lambda表达式

自定义槽案例

#include <QApplication>
#include <QWidget>
#include<QPushButton>

class MyWindow:public QWidget
{
    Q_OBJECT
public:
    MyWindow():QWidget(NULL){}
public slots:
    void showWindow()
    {
        this->show();
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QPushButton* btn = new QPushButton("打开");
    btn->show();
    MyWindow *mw=new MyWindow();
    auto con = QObject::connect(btn,&QPushButton::clicked,mw,&MyWindow::showWindow);
    return a.exec();
}

#include "main.moc"

自定义信号

Qt框架提供的信号在某些特定场景下是无法满足我们的项目需求的,因此我们还设计自己需要的信号,同样还是使用connect()对接

自定义信号需要遵循以下规则

  • 信号是类的成员函数,并且返回类型必须是void
  • 信号函数只需要声明,不需要定义
  • 参数可以随意指定,信号也支持重载
  • 信号需要使用signals关键字进行声明
  • 在程序中发送自定义信号:发送信号的本质就是调用信号函数emit mysignals()
  • emit是个空宏,没有特殊含义,仅用来表示这个语句是发射一个信号,不写可以,但不推荐
#include <QApplication>
#include <QWidget>
#include<QPushButton>

class MyWindow:public QWidget
{
    Q_OBJECT
public:
    MyWindow():QWidget(NULL){}
signals:
    void isShow(QString text);
public slots:
    void showWindow()
    {
        this->show();
        emit isShow("我出来了");
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QPushButton* btn = new QPushButton("打开");
    btn->show();
    MyWindow *mw=new MyWindow();
    auto con = QObject::connect(btn,&QPushButton::clicked,mw,&MyWindow::showWindow);

    QObject::connect(mw,&MyWindow::isShow,btn,&QPushButton::setText);
    return a.exec();
}

#include "main.moc"

信号和槽重载二义性问题

解决方法


#include <QApplication>
#include <QWidget>
#include<QPushButton>

class MyWindow:public QWidget
{
    Q_OBJECT
public:
    MyWindow():QWidget(NULL){}
signals:
    void isShow();
    void isShow(QString text);

public slots:
    void showWindow()
    {
        this->show();
        emit isShow("我出来了");
    }
    void showWindow(bool t)
    {
        this->close();
        emit isShow();
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QPushButton* btn = new QPushButton("打开");
    btn->move(10,10);
    btn->show();
    QPushButton* btn1 = new QPushButton("关闭");
    btn1->move(10,100);
    MyWindow *mw=new MyWindow();
    //用overload重载
    QObject::connect(btn,&QPushButton::clicked,mw,QOverload<>::of(&MyWindow::showWindow));
    QObject::connect(mw,QOverload<QString>::of(&MyWindow::isShow),btn,&QPushButton::setText);
    //用qt4方式SIGNAL和SLOT宏
    QObject::connect(btn1,SIGNAL(clicked(bool)),mw,SLOT(showWindow(bool)));//SIGNAL和SLOT要前后一致
    QObject::connect(mw,SIGNAL(isShow()),btn1,SLOT(close()));
    QObject::connect(mw,SIGNAL(isShow(QString)),btn1,SLOT(show()));
    return a.exec();
}

#include "main.moc"

4.内存管理

1. 简介

C++中new 和delete必须配对使用,防止内存泄露。Qt中使用了new却很少delete,因为Qt实现了其独特的内存管理机制。
QObject以对象树的形式组织起来。当为一个对象创建子对象时,子对象会自动地添加到父对象的children()列表中。父对象拥有子对象的所有权,比如父对象可以在自己的析构函数中删除它的子对象。使用findChild()或findChildren()通过名字和类型查询孩子对象。

QObject(QObject *parent=nullptr)
  1. QObject及其派生类的对象,如果其parent非nullptr,那么其parent析构时会析构该对象。
  2. 父子关系:父对象、子对象、父子关系。这是Qt中所特有的,与类的继承关系无关,传递参数是与parent有关

2.关联图

在Qt中,最基础和核心的类是QObject,QObject内部有一个名为children的QObjectList列表,会保存所有子对象,还有一个指针parent,用来指向父对象,当自己析构时,会先把自己从parent列表中删除,并且析构所有的child
在这里插入图片描述

3.详解

  1. 指定父对象释放,自己也释放

#include <QApplication>
#include <QWidget>
#include<QPushButton>

class MyWindow:public QWidget
{
    Q_OBJECT
public:
    MyWindow(QWidget* parent=nullptr):QWidget(parent){}
    ~MyWindow()
    {
        qInfo()<<__FUNCTION__<<"释放了";
    }
signals:
    void isShow();
    void isShow(QString text);

public slots:
    void showWindow()
    {
        this->show();
        emit isShow("我出来了");
    }
    void showWindow(bool t)
    {
        this->close();
        emit isShow();
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QPushButton* btn = new QPushButton("打开");
    btn->move(10,10);
    btn->show();
    QPushButton* btn1 = new QPushButton("关闭");
    btn1->move(10,100);
    MyWindow *mw=new MyWindow(btn1);
    //用overload重载
    QObject::connect(btn,&QPushButton::clicked,mw,QOverload<>::of(&MyWindow::showWindow));
    QObject::connect(mw,QOverload<QString>::of(&MyWindow::isShow),btn,&QPushButton::setText);
    //用qt4方式SIGNAL和SLOT宏
    QObject::connect(btn1,SIGNAL(clicked(bool)),mw,SLOT(showWindow(bool)));//SIGNAL和SLOT要前后一致
    QObject::connect(mw,SIGNAL(isShow()),btn1,SLOT(close()));
    QObject::connect(mw,SIGNAL(isShow(QString)),btn1,SLOT(show()));
    btn1->deleteLater();
    return a.exec();
}

#include "main.moc"

  1. 查找子对象
	mw->setObjectName("window");
    auto wd =btn1->findChild<MyWindow*>("window"); //找子对象
    if(wd)
        qInfo()<<"存在";

4.智能指针

智能指针描述
QPointerQObject或子类对象释放时会自动指向nullpter
QScopedPointer【独享指针】超出作用域自动释放管理的对象
QSharedPoiner【共享指针】
QWeakPointer【监视指针】
QScopedArrayPointer【独享数组指针】超出作用域自动释放管理的对象数组
QSharedDataPointer【隐式共享指针】读时共享,写时拷贝
QExplicitlySharedDataPointer【显式共享指针】读时共享,写时需要手动拷贝(通过detach()函数)
  • 使用方法
	#include<QPointer>
	
    QPointer<QPushButton> btn1 = new QPushButton("关闭");
    btn1->move(10,100);
    MyWindow *mw=new MyWindow(btn1.data());
	#include<QSharedPointer>
	
	QSharedPointer<QPushButton> btn1(new QPushButton("关闭"));
    QObject::connect(btn1.data(),SIGNAL(clicked(bool)),mw,SLOT(showWindow(bool)));//SIGNAL和SLOT要前后一致
    QObject::connect(mw,SIGNAL(isShow()),btn1.data(),SLOT(close()));
    QObject::connect(mw,SIGNAL(isShow(QString)),btn1.data(),SLOT(show()));
	#include<QScopedArrayPointer>
	
    QScopedArrayPointer<int> arrptr(new int[10]);
    arrptr[1] = 666;

5.属性系统

属性的行为类似于数据成员,但它具有通过元对象系统访问的附加特性
在这里插入图片描述

获取/设置属性值

获取

    MyWindow *mw=new MyWindow();
    mw->show();
	 qInfo()<< mw->property("pos");//结果QVariant(QPoint, QPoint(639,249))

设置

    QObject::connect(btn,&QPushButton::clicked,[&](){
        auto pos = mw->property("pos").toPoint();
        mw->setProperty("pos",QPoint(pos.x()-2,pos.y()-2));
    });

自己声明属性值

要声明属性,请在继承QObject的类中使用Q_PROPERTY()宏

Q_PROPRETY(type name
		(READ getFunction [WRITE setFunction]|
		MEMBER memberName [(READ getFunction|WRITE setFunction)])
		[RESET restFunction]
		[NOTIFY notifySignal]
		[REVISION int | REVISION(int[,int])]
		[DESIGNABLE bool]
		[SCRIPTABLE bool]
		[STORED bool]
		[USER bool]
		[BINDABLE bindableProperty]
		[CONSTANT]
		[FINAL]
		[REQUIRED])

属性的行为类似于数据成员,但它具有通过元对象系统访问的附加特性。

  • 如果未指定MEMBER变量,则需要READ访问器函数。它用于读取属性值。理想情况下,const函数用于此目的,它必须返回属性的类型或对该类型的const引用。例如,QWidget::focus是一个带有READ函数的只读属性,QWidget::hasFocus()。
  • WRITE访问器函数是可选的。它用于设置属性值。它必须返回void并且必须只接受一个参数,该参数可以是属性类型,也可以是指向该类型的指针或引用。例如,QWidget::enabled具有WRITE函数QWidget::setEnabled()。只读属性不需要WRITE函数。例如,QWidget::focus没有Write功能。
  • 如果未指定READ访问器函数,则需要MEMBER变量关联。这使得给定的成员变量可读可写,而无需创建READ和WRITE访问器函数。如果您需要控制变量访问,除了MEMBER变量关联之外,仍然可以使用READ或WRITE访问器函数。
  • RESET功能是可选的。它用于将属性设置回特定于上下文的默认值。
  • NOTIFY信号是可选的。如果已定义,则应指定该类中的一个现有信号,该信号在属性值更改时发出。MEMBER变量的NOTIFY信号必须采用零个或一个参数,该参数必须与属性的类型相同。该参数将采用属性的新值。NOTIFY信号只应在属性真正被更改时发出,以避免在QML中不必要地重新评估绑定。
  • REVISION编号或REVISION()宏是可选的。如果包含,它定义了要在API的特定修订版中使用的属性及其通知信号(通常用于暴露于QML)。如果不包含,则默认为0.
  • DESIGNABLE属性指示该属性是否应在GUI设计工具(如Qt Designer)的属性编辑器中可见。大多数属性是可设计的(默认为true)。有效值为真和假。
  • SCRIPTABLE属性指示脚本引擎是否可以访问此属性(默认为true)。有效值为真和假。
  • STORED属性指示该属性是否应该被认为是独立存在的,或取决于其他值。它还指示在存储对象的状态时是否必须保存属性值。大多数属性值是STORED的(默认为true)。
  • USER属性指示该属性是被指定为该类的面向用户的属性还是用户可编辑的属性。通常,每个类只有一个USER属性(默认false)。
  • BINDABLE bindableProperty属性表明该属性支持绑定,并且可以通过对元对象系统设置和检查该属性的绑定。bindableProperty命名QBindable类型的类成员,其中T是属性类型。
  • CONSTANT属性的存在表明属性值是常量。对于给定的对象实例,常量属性的READ方法在每次调用时都必须返回相同的值。对于对象的不同实例,该常数值可能不同。常量属性不能有WRITE方法或NOTIFY信号。
  • FINAL属性的存在表明该属性不会被派生类覆盖。这在某些情况下可用于性能优化,但并非由moc强制执行。必须注意永远不要覆盖FINAL属性。
  • REQUIRED属性的存在表明该属性应该由该类的用户设置。这不是由moc强制执行的,并且对于暴露给QML的类最有用。在QML中除非设置了所有的REQUIRED属性,否则无法实例化具有REQUIRED属性的类。

#include <QApplication>
#include <QWidget>
#include<QPushButton>
#include<QPointer>

class MyWindow:public QWidget
{
    Q_OBJECT
    Q_PROPERTY(QString name READ getname WRITE setname NOTIFY nameChanged FINAL)
    QString m_name;
public:
    MyWindow(QWidget* parent=nullptr):QWidget(parent){}
    ~MyWindow()
    {
        qInfo()<<__FUNCTION__<<"释放了";
    }
signals:
    void isShow();
    void isShow( QString text);
signals:
    void nameChanged();
public slots:
    QString getname()
    {
        qInfo()<<__FUNCTION__;
        return m_name;
    }
    void setname(QString name)
    {
        qInfo()<<__FUNCTION__;
        m_name = name;
        emit nameChanged();
    }
public slots:
    void showWindow()
    {
        this->show();
        emit isShow("我出来了");
    }
    void showWindow(bool t)
    {
        this->close();
        emit isShow();
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QPushButton* btn = new QPushButton("打开");
    btn->move(10,10);
    btn->show();
    MyWindow *mw=new MyWindow();
    mw->showWindow();

    QObject::connect(btn,&QPushButton::clicked,[=](){
        auto pos = mw->property("pos").toPoint();
        mw->setProperty("pos",QPoint(pos.x()-2,pos.y()-2));
        mw->setProperty("name","abc");//自定义的name属性改变
    });

    QObject::connect(mw,&MyWindow::nameChanged,[&,btn](){
        auto windowName = mw->property("name");
        btn->setText(windowName.toString());
    });


    return a.exec();
}

#include "main.moc"

直接关联也可以

 Q_PROPERTY(QString name  MEMBER m_name NOTIFY nameChanged FINAL)

绑定属性


#include <QApplication>
#include<QProperty>


struct Rectangle
{
    Rectangle() {}
    int w,h,area;
    Rectangle(int w,int h):w(w),h(h)
    {
        area = this->w*this->h;
    }
};
struct Rect
{
    Rect() {}
    QProperty<int> w,h,area;
    Rect(int w,int h):w(w),h(h)
    {
        //设置绑定属性
        area.setBinding([&]{return this->w*this->h;});
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    //没设置绑定属性
    Rectangle rl(10,10);
    qInfo()<<rl.area;
    rl.h =20;
    qInfo()<<rl.area;
    //2个结果一样,都是100,没改变

    //设置绑定属性后
    Rect r(10,10);
    qInfo()<<r.area;
    r.h = 20;
    qInfo()<<r.area;
    //结果分别是100,和200
    return a.exec();
}

QObjectBindableProperty


#include <QApplication>
#include<QProperty>
#include<QWidget>
#include <QPushButton>


class MyWindow:public QWidget
{
    Q_OBJECT
public:
    MyWindow(QWidget* parent=nullptr):QWidget(parent){}

signals:
    void myxChanged();

public:
    Q_OBJECT_BINDABLE_PROPERTY(MyWindow,int,myx,&MyWindow::myxChanged);

};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QPushButton* btn = new QPushButton("打开");
    btn->move(10,10);
    btn->show();
    MyWindow* mw = new MyWindow();
    QObject::connect(btn,&QPushButton::clicked,[=]{
        static int a=0;
        mw->show();
        mw->myx = ++a;
    });
    QObject::connect(mw,&MyWindow::myxChanged,[&]{
        qInfo()<<"x修改了";
    });

    return a.exec();
}

#include "main.moc"

6.实时类型信息

判断继承自XX类

qInfo()<<mw->inherits("QObject");//true

枚举

#include <QMetaEnum>

namespace Yerennuo {
//命名空间
Q_NAMESPACE
enum Type
{
    Player,
    Enemy,
    Bullet
};
//注册枚举
Q_ENUM_NS(Type)
}


qInfo()<< Yerennuo::Type::Bullet;//Yerennuo::Bullet

也可以在类里面

class Test:public QObject
{
    Q_OBJECT
public:
    enum Type
    {
        Player,
        Enemy,
        Bullet
    };
    Q_ENUM(Type)
};

    qInfo()<<Test::Type::Player;//Test::Player

QMetaObject元信息


#include "qmetaobject.h"
#include <QApplication>
#include<QWidget>
#include <QMetaObject>


class MyWindow:public QWidget
{
    Q_OBJECT
    Q_CLASSINFO("author","yerennuo")
public:
    MyWindow(QWidget* parent=nullptr):QWidget(parent){}

};



int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MyWindow* mw = new MyWindow();

    auto metaobj = mw->metaObject();
     qInfo()<<"key="<<metaobj->classInfo(0).name()
             <<"value="<<metaobj->classInfo(0).value();
	//key= author value= yerennuo
    return a.exec();
}

#include "main.moc"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/509422.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PFA(可溶性聚四氟乙烯)弯嘴洗瓶

PFA材质&#xff0c;又称可溶性聚四氟乙烯&#xff0c;是进口的高纯原材料&#xff0c;耐强酸强碱耐腐蚀和各种有机溶剂。 常用规格:30ml/60ml/100ml/250ml/500ml 产品特性 1、耐高低温&#xff1a;使用温度可达-200~260℃&#xff1b; 2、可打刻度&#xff0c;高度透明&#x…

20240330-0402-湖南长沙之旅-橘子洲,五一广场,国金广场,湖南博物馆

0330 复试&#xff0c;无语中&#xff0c;面试中文部分居然也是拉了坨大的 0331 晚上 感觉忙完复试&#xff0c;有种偶然感&#xff0c;跟自己设想的又不一样&#xff0c;感觉方向感真的差&#xff0c;压中得没多少。 刚忙完考试&#xff0c;去五一附近住&#xff0c;还是一…

wpf 自定义命令

自定义命令 MyCommand.cs public class MyCommand : ICommand {private readonly Action<Object> execAction;private readonly Func<Object,bool> changedFunc;public event EventHandler? CanExecuteChanged;public MyCommand(Action<object> execAction…

微信开发工具——进行网页授权

微信开发工具——进行网页授权 微信公众平台设置 1.在首页创建好自己的订阅号 网站&#xff1a;https://mp.weixin.qq.com/ 点击立即注册,在选择订阅号&#xff08;个人创建使用&#xff09; 之后按流程填写后&#xff0c;点击设置与开发-------->基本配置&#xff0c;这…

C++ //练习 11.4 扩展你的程序,忽略大小写和标点。例如,“example.“、“exmaple,“和”Example“应该递增相同的计数器。

C Primer&#xff08;第5版&#xff09; 练习 11.4 练习 11.4 扩展你的程序&#xff0c;忽略大小写和标点。例如&#xff0c;“example.”、"exmaple,"和”Example"应该递增相同的计数器。 环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工…

泰迪智能科技携手韶关学院共建实训基地

3月28日&#xff0c;韶关学院数学与统计学院院长宋杰、数学与统计学院副院长李少勇、数学与统计学院骨干教师邓四清、邝神芬、付林林莅临广东泰迪智能科技股份有限公司产教融合实训基地开展“韶关学院实习基地”揭牌仪式。泰迪智能科技高校事业部负责人施兴、培训业务部孙学镂、…

parallel linux虚拟机没有root权限

前言 今天刚在parallel上装上linux虚拟机&#xff0c;安装的是Debian发行版。用终端输入命令时&#xff0c;无意间发现当前用户竟然不是root用户&#xff0c;岂有此理&#xff01;众所周知&#xff0c;Linux系统一般安装之后都是默认root用户的&#xff0c;但是可能parallel先…

《系统架构设计师教程(第2版)》第8章-系统质量属性与架构评估-02-系统架构评估

文章目录 1. 一些重要概念1.1 敏感点 (Sensitivity Point)1.2 权衡点 (Tradeoff Point)1.3 风险承担者 (Stakeholders)1.3.1 系统生产者1.3.2 系统消费者1.3.3 系统服务人员1.3.4 其它人员 1.4 场景 (scenarios) 2. 系统架构评估方法2.1 基于场景的架构分析方法&#xff08;SAA…

【算法刷题day10】Leetcode:232.用栈实现队列、225. 用队列实现栈

文章目录 Leetcode 232.用栈实现队列解题思路代码总结 Leetcode 225. 用队列实现栈解题思路代码总结 stack、queue和deque对比 草稿图网站 java的Deque Leetcode 232.用栈实现队列 题目&#xff1a;232.用栈实现队列 解析&#xff1a;代码随想录解析 解题思路 一个栈负责进&a…

《编程菜鸟学 Python 数据分析》让工作自动化起来!

随着我国企业数字化和信息化的深入&#xff0c;企业对办公自动化的效率和灵活性要求越来越高。Python作为一种开源的软件应用开发方式&#xff0c;通过提供强大丰富的库文件包&#xff0c;极大地简化了应用开发过程&#xff0c;降低了技术门槛。Python开发有哪些优势、挑战以及…

【数据库】实践:博物馆藏品管理系统

目录 一、选题 二、需求分析 2.1数据库系统的业务描述 2.2主要逻辑业务 2.3 数据字典 2.4 数据流图&#xff1a; 2.5 模块介绍&#xff1a; 三、概念模型设计&#xff08;画局部E-R图&#xff0c;再合并画整体E-R图&#xff09; 四、逻辑结构设计——数据库关系模式 …

认知觉醒读书笔记之三重大脑(一)

引言 《认知觉醒》这本书太经典了&#xff0c;反复读了多次还是爱不释手&#xff0c;因此决定针对它写写读书笔记。今天主要针对这本书的三重大脑理论进行讲解 三重大脑 作者认为人类的大脑分为三重分别是本能脑、情绪脑以及理智脑&#xff0c;三者的区别如下图(从书中拷贝的…

多线程。

1. Thread创建的写法 1.继承Thread&#xff0c;重写run 2.实现Runnable&#xff0c;重写run 3.继承Thread&#xff0c;重写run&#xff0c;使用内部匿名类 4实现Runnable&#xff0c;重写run&#xff0c;使用内部匿名类 5使用lambda方法 Thread中的一些核心属性和方法 idn…

书生浦语全链条开源开放体系

开放了高质量语料数据 预训练 微调 评测 评测框架 部署 智能体 例如把openlab对于计算机视觉的封装

用python爬虫追踪知乎/B站大V排行

最近&#xff0c;我在学习和实践 python 的数据分析&#xff0c;前几周把知乎、B站、虎扑上的各种信息都抓了个遍&#xff0c;比如粉丝数、关注关系、发布时间、阅读量、回复数、标题关键字、地域分布……然后又对这些数据进行了整理&#xff0c;将数据通过各类图表进行可视化&…

【Python从入门到进阶】52、CrawlSpider链接提取器的使用

接上篇《51、电影天堂网站多页面下载实战》 上一篇我们采用Scrapy框架多页面下载的模式来实现电影天堂网站的电影标题及图片抓取。本篇我们来学习基于规则进行跟踪和自动爬取网页数据的“特殊爬虫”CrawlSpider。 一、什么是CrawlSpider&#xff1f; 1、CrawlSpider的概念 Cr…

动画效果-精灵图人物移动

效果&#xff1a;人物跑步移动 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&…

高风险IP来自哪里:探讨IP地址来源及其风险性质

在网络安全领域&#xff0c;高风险IP地址是指那些可能涉及恶意活动或网络攻击的IP地址。了解这些高风险IP地址的来源可以帮助网络管理员更好地识别和应对潜在的安全威胁。本文将探讨高风险IP地址的来源及其风险性质&#xff0c;并提供一些有效的应对措施。 风险IP查询&#xf…

每日一题(力扣136):只出现一次的数字

利用哈希&#xff1a;时间复杂度O(n)&#xff0c;空间复杂度O(n) class Solution { public:int singleNumber(vector<int>& nums) {if (nums.size() 1){return nums[0];}unordered_map<int, int> map;int len nums.size();for (int i 0; i < len; i){if…

PCL 计算点与圆的距离(3D)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 3D中的圆可以有圆心、半径以及法线来进行表示,如下图所示: 这里我们假设: Δ = P − C \Delta=P-C Δ