03-1_Qt 5.9 C++开发指南_Qt核心特点(元对象系统特性:属性系统;信号与槽机制、动态类型转换;元对象特性测试实例)

news2024/12/27 10:37:54

Qt 是一个用标准 C++编写的跨平台开发类库,它对标准 C++进行了扩展,引入了元对象系统信号与槽、属性等特性,使应用程序的开发变得更高效。本章将介绍 Qt 的这些核心特点,对于理解和编写高效的 Ot C++程序是大有帮助的;还介绍头文件中 Qt 的一些全局定义,包括数据类型、函数和宏等,介绍 Ot的容器类及其相应迭代器的使用方法;Qt 类库中大量的类是以模块形式分类组织的,包括基本模块和扩展模块等,本章对这些模块做个总体的介绍一个模块通常就是一个编程主题,如数据库、图表、网络等,后面的章节般是每章介绍一个编程主题。

文章目录

  • 1. 元对象系统
    • 1.1 元对象系统由以下三个基础组成:
    • 1.2 元对象系统工作原理
    • 1.3 元对象提供的其他功能
  • 2. 属性系统
    • 2.1 属性定义
    • 2.2 属性的使用
    • 2.3 动态属性
    • 2.4 类的附加信息
  • 3. 信号与槽
    • 3.1 connect()函数的不同参数形式
    • 3.2 信号与槽之间的关联形式Qt::ConnectionType
    • 3.3 使用 sender()获得信号发射者
    • 3.4 自定义信号及其使用
  • 4. 元对象特性测试实例
    • 4.1 qperson.h
    • 4.2 qperson.cpp
    • 4.3 qmywidget.h
    • 4.4 qmywidget.cpp
    • 4.5 qmywidget.ui
    • 4.6 运行结果
  • 5.源码下载

Qt核心特点包括:

  • Qt 本身并不是一种编程语言,它实质上是一个跨平台的 C++开发类库,是用标准 C++编写的类库,它为开发 GUI 应用程序和非 GUI应用程序提供了各种类。
  • Qt 的元对象编译器(Meta-Object Compiler,MOC)是一个预处理器,在源程序被编译前先将这些Qt 特性的程序转换为标准 C++兼容的形式,然后再由标准 C++编译器进行编译。这就是为什么在使用信号与槽机制的类里,必须添加一个Q_OBJECT 宏的原因,只有添加了这个宏,moc 才能对类里的信号与槽的代码进行预处理。
  • Qt Core 模块是 Qt 类库的核心,所有其他模块都依赖于此模块,如果使用 qmake 来构建项目,Qt Core 模块则是被自动加入的。
  • Qt为 C++语言增加的特性就是在 Qt Core 模块里实现的,这些扩展特性由 Qt 的元对象系统实现,包括信号与槽机制属性系统动态类型转换等。

1. 元对象系统

Qt 的元对象编译器(Meta-Object Compiler,MOC)提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统

1.1 元对象系统由以下三个基础组成:

  • QObject 类是所有使用元对象系统的类的基类。
  • 在一个类的 private 部分声明Q_OBJECT 宏,使得类可以使用元对象的特性,如动态属性、信号与槽。
  • MOC(元对象编译器)为每个 QObject 的子类提供必要的代码来实现元对象系统的特性。

1.2 元对象系统工作原理

构建项目时,MOC 工具读取 C++源文件,当它发现类的定义里有 Q_OBJECT 宏时,它就会为这个类生成另外一个包含有元对象支持代码的 C++源文件,这个生成的源文件连同类的实现文件一起被编译和连接。

1.3 元对象提供的其他功能

  • QObject::metaObject()函数返回类关联的元对象,元对象类 QMetaObiect 包含了访问元对象的一些接口函数,例如QMetaObject::className()函数可在运行时返回类的名称字符串。
QObject *obj = new QPushButton;
obj->metaObject()->className();// 返回“QPushButton"
  • QMetaObject::newInstance()函数创建类的一个新的实例
  • QObject::inherits(const char *className)函数判断一个对象实例是否是名称为 className的类或 QObject 的子类的实例。例如:
QTimer *timer = new QTimer;  // QTimer 是 QObject 的子类
timer->inherits("QTimer");  // 返回 true
timer->inherits("OObject");  // 返回 true
timer->inherits("QAbstractButton");//返回 false,不是QAbstractButton的子类
  • QObiect::tr()和 QObiect::trUtf8()函数可翻译字符串,用于多语言界面设计,在后面会专门介绍多语言界面设计。
  • QObject::setProperty()和 QObject:property()函数用于通过属性名称动态设置和获取属性值
  • 动态投射(dynamic cast),使用动态投射,使得程序可以在运行时对不同的对象做不同的处理,详细使用方法见下:
    对于 QObject 及其子类,还可以使用 qobject cast()函数进行动态投射 (dynamic cast)。例如,假设 QMyWidget 是 QWidget 的子类并且在类定义中声明了Q_OBJECT宏。创建实例使用下面的语句:
    QObject *obj = new QMyWidget;
    变量 obj 定义为 QObject 指针,但它实际指向 QMyWidget 类,所以可以正确投射为 QWidget,即:
    QWidget *widget = qobject_cast <QWidget *> (obj);
    从QObject 到 QWidget 的投射是成功的,因为 obj 实际是 QMyWidget 类,是 QWidget 的子类也可以将其成功投射为 QMyWidget,即:
    QMywidget *myWidget = qobject_cast <QMyWidget *> (obj);
    投射为QMyWidget 是成功的,因为 qobject cast0并不区分 Qt 内建的类型和用户自定义类型。但是,若要将 obj 投射为 QLabel 则是失败的,即:
    QLabel *label =qobject_cast <QLabel *> (obj);
    这样投射是失败的,返回指针 label为 NULL,因为QMyWidget 不是 QLabel 的子类。

2. 属性系统

2.1 属性定义

Qt 提供一个 Q_PROPERTY()宏可以定义属性,它也是基于元对象系统实现的。Qt 的属性系统与C++编译器无关,可以用任何标准的 C++编译器编译定义了属性的 Qt C++程序。
在 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 的属性
  • READ getFunction [WRITE setFunction] 提供一个读取属性的getFunction函数,[WRITE setFunction] 用 READ、WRITE 关键字定义属性的读取,setFunction表示写入函数,[]代表可选的,这里WRITE setFunction是可以不写的
  • MEMBER memberName [(READ getFunction | WRITE setFunction)]类中的成员变量与属性关联
    还有其他的一些关键字定义属性的一些操作特性。属性的类型可以是 QVariant 支持的任何类型,也可以用户自定义类型。

Q_PROPERTY宏定义属性的一些主要关键字的意义如下:

  • READ 指定一个读取属性值的函数,没有 MEMBER 关键字时必须设置 READ
  • WRITE 指定一个设定属性值的函数,只读属性没有 WRITE 设置。
  • MEMBER 指定一个成员变量与属性关联,成为可读可写的属性,无需再设置 READ和WRITE。
  • RESET 是可选的,用于指定一个设置属性缺省值的函数。
  • NOTIFY 是可选的,用于设置一个信号,当属性值变化时发射此信号。
  • DESIGNABLE 表示属性是否在 Qt Designer 里可见,缺省为 true。
  • CONSTANT 表示属性值是一个常数,对于一个对象实例,READ 指定的函数返回值是常数,但是每个实例的返回值可以不一样。具有 CONSTANT 关键字的属性不能有 WRITE和NOTIFY 关键字。
  • FINAL 表示所定义的属性不能被子类重载。

QWidget 类定义属性的一些例子如下:

Q_PROPERTY(bool focus READ  hasFocus) //属性 focus的只读函数hasFocus
Q_PROPERTY(bool  enabled READ isEnabled WRITE setEnabled) //属性enable的读函数为isEnabled,写函数为setEnabled
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor )

2.2 属性的使用

不管是否用READ和WRITE定义了接口函数,只要知道属性名称,就可以通过Object::property()读取属性值,并通过 QObject::setProperty()设置属性值。例如:

QPushButton *button = new QPushButton;
QObject *object = button;
object->setProperty("flat",true);
bool isFlat = object->property ("flat");

2.3 动态属性

  • **QObject::setProperty()函数可以在运行时为类定义一个新的属性,称之为动态属性。**动态属性是针对类的实例定义的。

  • 动态属性可以使用Object::property()查询,就如类定义里用Q_PROPERTY宏定义的属性一样

例如,在数据表编辑界面上,一些字段是必填字段,就可以在初始化界面时为这些字段的关联显示组件定义一个新的 required 属性,并设置值为“true”,如:

editName->setProperty("required""true");
comboSex->setPropert("required""true");
checkAgree->setProperty("required""true");

然后,可以应用下面的样式定义将这种必填字段的背景颜色设置为亮绿色
[required="true"] {background-color: lime]

2.4 类的附加信息

属性系统还有一个宏Q_CLASSINFO(),可以为类的元对象定义“名称-值”信息,如:

class QMyclass:public QObject
{
Q_OBJECT
Q_CLASSINFO(“author”,"Wang")
Q_CLASSINFO(“company”,"UPC")
Q_CLASSINFO(“version”,"4 ")
}

public:
....

用Q_CLASSINFO()宏定义附加类信息后,可以通过元对象的一些函数获取类的附加信息,如classInfo(int)获取某个附加信息,函数原型定义为:
QMetaClassInfo QmetaObject:classInfo(int index) const
返回值是QMetaClassInfo类型,有name()和value()两个函数,可获得类附加信息的名称和值

QMyWidget * myWidget = new QMyWidget;
qDebug()<<myWidget->metaObject()->classInfo(0).name();
qDebug()<<myWidget->metaObject()->classInfo(0).value();
qDebug()<<myWidget->metaObject()->classInfo(1).name();
qDebug(<<myWidget->metaObject()->classInfo(1).value();

3. 信号与槽

上章中已经简单介绍了信号和槽的使用,其是Qt的核心特点,使对象间进行通信的机制,需要元对象系统支持才可以实现。
Qt的信号与槽机制与Delphi 和 C++ Builder的“事件-响应”类似,但是更加灵活。对于某些开发架构使用回调函数(callback) 实现对象间通信,信号槽执行速度会慢些,这是因为需要查找连接的对象和槽函数,但对于程序运行时是感觉不到的。
在上章介绍的基础上,此处对信号槽的特点和用法做一些补充:

3.1 connect()函数的不同参数形式

QObject::connect()函数有多重参数形式
(1)一种参数形式的函数原型是:
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
使用这种参数形式的 connect0)进行信号与槽函数的连接时,一般句法如下:
connect(sender,SIGNAL(signal()), receiver, SLOT(slot()));

这里使用了宏 SIGNAL()和 SLOT()指定信号和槽函数,而且如果信号和槽函数带有参数,还需注明参数类型,如:

 QLabel *label = new QLabel;
  QScrollBar *scrollBar = new QScrollBar;
  QObject::connect(scrollBar, SIGNAL(valueChanged(int)),
                   label,  SLOT(setNum(int)));

(2)另一种connect()函数参数形式的函数原型是:
QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection)

对于具有默认参数的信号与槽(即信号名称是唯一的,没有参数不同而同名的两个信号),可以使用这种函数指针形式进行关联,如:
connect(lineEdit,&QLineEdit::textChanged,this,&widget::on_textChanged);
QLineEdit 只有一个信号 textChanged(QString),在自定义窗体类 widget 里定义一个槽函数on_textChanged(QString),就可以用上面的语句将此信号与槽关联起来,无需出现函数参数。这在信号的参数比较多时更简便一些。
而对于具有不同参数的同名信号就不能采用函数指针的方式进行信号与槽的关联,例如QSpinBox 有两个 valueChanged()信号,分别是:

void QSpinBox::valueChanged(int i)
void QSpinBox::valueChanged(const QString &text)

使用下面的语句进行关联时,编译就会报错
connect(spinNum, &QSpinBox::valueChanged, this,&widget::onValueChanged);

3.2 信号与槽之间的关联形式Qt::ConnectionType

不管是哪种参数形式的 connect()函数,最后都有一个参数 QtConnectionType type,缺省值为Qt::AutoConnection。枚举类型 Qt::ConnectionType 表示了信号与槽之间的关联方式,有以下几种取值。

  • Qt:AutoConnection(缺省值): 如果信号的接收者与发射者在同一个线程,就使用 Qt::DirectConnection 方式:否则使用 Ot::QueuedConnection 方式,在信号发射时自动确定关联方式。
  • Qt::DirectConnection:信号被发射时槽函数立即执行,槽函数与信号在同一个线程。
  • Qt::QueuedConnection: 在事件循环回到接收者线程后执行槽函数,槽函数与信号在不同的线程。
  • Qt::BlockingQueuedConnection: 与 Qt:QueuedConnection 相似,只是信号线程会阻塞直到槽函数执行完毕。当信号与槽函数在同一个线程时绝对不能使用这种方式,否则会造成死锁。

3.3 使用 sender()获得信号发射者

在槽函数里,使用 QObject::sender()可以获取信号发射者的指针。如果知道信号发射者的类型可以将指针投射为确定的类型,然后使用这个确定类的接口函数。
例如,在QSpinBox的 valueChanged(int )信号的槽函数里,可以通过 sender0 和 qobject_cast获得信号发射者的指针,从而对信号发射者进行操作。
QSpinBox *spinBox = qobject_cast<QSpinBox *>(sender());

3.4 自定义信号及其使用

在自己设计的类里也可以自定义信号,信号就是在类定义里声明的一个函数,但是这个函数无需实现,只需发射 (emit)。
例如,在下面的自定义类QPerson 的 signals 部分定义一个信号ageChanged(int)。

class QPerson: public QObject
{
Q_OBJECT
private:
int m_age=10;
public:
void incAge();
signals:
void ageChanged( int value) ;
}

信号函数必须是无返回值的函数,但是可以有输入参数。信号函数无需实现,只需在某些条件下发射信号。例如,在 incAge()函数中发射信号,其代码如下。

void QPerson::incAge()
{ m_age++;
emit ageChanged(m_age);//发射信号
}

在 incAge()函数里,当私有变量 m_age 变化后,发射信号 ageChanged(int),表示年龄发生了变化。至于是否有与此信号相关联的槽函数,信号发射者并不管。如果在使用 OPerson 类对象的程序中为此信号关联了槽函数,在 incAge0函数里发射此信号时,就会执行相关联的槽函数。至于是否立即执行槽函数,发射信号的线程是否等待槽函数执行完之后再执行后面的代码,与connect()函数设置信号与槽关联时设置的连接类型以及信号与槽是否在同一个线程有关。

4. 元对象特性测试实例

实例的整体框架如下图:

在这里插入图片描述

4.1 qperson.h

#ifndef QPERSON_H
#define QPERSON_H

#include <QObject>

class QPerson : public QObject
{
    Q_OBJECT

    Q_CLASSINFO("author","Wang")
    Q_CLASSINFO("company","UPC")
    Q_CLASSINFO("version","1.0.0")

    //属性age绑定读函数age、绑定写函数setAge、当age发生变化时触发信号ageChanged
    Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged)
    //属性name绑定成员变量m_name
    Q_PROPERTY(QString name MEMBER m_name)
    Q_PROPERTY(int score MEMBER m_score)
private:
    int  m_age=10;
    QString m_name;
    int     m_score=79;
public:
    explicit QPerson(QString fName, QObject *parent = nullptr);

    int     age();
    void    setAge(int value);

    void    incAge();
signals:
    void    ageChanged( int  value);

public slots:
};

#endif // QPERSON_H

4.2 qperson.cpp

#include "qperson.h"

QPerson::QPerson(QString fName,QObject *parent) : QObject(parent)
{ //构造函数
    m_name=fName;
}

int QPerson::age()
{ //返回age
    return  m_age;
}

void QPerson::setAge(int value)
{//设置age
    m_age=value;
    emit ageChanged(m_age); //发射信号
}

void QPerson::incAge()
{
    m_age++;
    emit ageChanged(m_age);//发射信号
}

4.3 qmywidget.h

#ifndef QMYWIDGET_H
#define QMYWIDGET_H

#include <QWidget>
#include    "qperson.h"

namespace Ui {
class QmyWidget;
}

class QmyWidget : public QWidget
{
    Q_OBJECT

private:
    QPerson *boy;
    QPerson *girl;

public:
    explicit QmyWidget(QWidget *parent = 0);
    ~QmyWidget();

private:
    Ui::QmyWidget *ui;

signals:

private slots:
//自定义槽函数
    void   on_ageChanged(int  value);
    void   on_spin_valueChanged(int arg1);

//界面按钮的槽函数
    void on_btnClear_clicked();
    void on_btnBoyInc_clicked();
    void on_btnGirlInc_clicked();
    void on_btnClassInfo_clicked();
};

#endif // QMYWIDGET_H

4.4 qmywidget.cpp

#include "qmywidget.h"
#include "ui_qmywidget.h"
#include    <QMetaProperty>

QmyWidget::QmyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::QmyWidget)
{//构造函数
    ui->setupUi(this);

    boy=new QPerson("wang xiaoming");
    boy->setProperty("score",95);
    boy->setProperty("age",10);
    boy->setProperty("sex","Boy");//动态属性
//    connect(boy,SIGNAL(ageChanged(int)),this,SLOT(on_ageChanged(int)));
    connect(boy,&QPerson::ageChanged,this,&QmyWidget::on_ageChanged);

    girl=new QPerson("zhang xiaoli");
    girl->setProperty("score",81);
    girl->setProperty("age",20);
    girl->setProperty("sex","Girl");//动态属性
    connect(girl,&QPerson::ageChanged,this,&QmyWidget::on_ageChanged);

    ui->spinBoy->setProperty("isBoy",true); //动态属性
    ui->spinGirl->setProperty("isBoy",false);

//  不能使用此形式,因为QSpinBox有两种参数形式的valueChanged()信号
//    connect(ui->spinGirl,&QSpinBox::valueChanged,
//            this,&QmyWidget::on_spinBoy_valueChanged);
    connect(ui->spinGirl,SIGNAL(valueChanged(int)),
            this,SLOT(on_spin_valueChanged(int)));
    connect(ui->spinBoy,SIGNAL(valueChanged(int)),
            this,SLOT(on_spin_valueChanged(int)));
}

QmyWidget::~QmyWidget()
{
    delete ui;
}

//获取不同对象对应的属性值,并显示在textEdit上
void QmyWidget::on_ageChanged( int value)
{//响应QPerson的ageChanged()信号
    Q_UNUSED(value);
    QPerson *aPerson = qobject_cast<QPerson *>(sender()); //类型投射
    QString hisName=aPerson->property("name").toString(); //姓名
//    QString hisName=aPerson->name(); //获取姓名,错误
    QString hisSex=aPerson->property("sex").toString(); //动态属性
    int hisAge=aPerson->age();//通过接口函数获取年龄
//    int hisAge=aPerson->property("age").toInt();//通过属性获得年龄

    ui->textEdit->appendPlainText(hisName+","+hisSex
                               +QString::asprintf(",age=%d",hisAge));
}

void QmyWidget::on_btnClear_clicked()
{//"清空文本框"按钮
    ui->textEdit->clear();
}

void QmyWidget::on_btnBoyInc_clicked()
{//"boy长大一岁"按钮
    boy->incAge();
}

void QmyWidget::on_btnGirlInc_clicked()
{//"girl长大一岁"按钮
    girl->incAge();
}

//根据isBoy属性判断信号来自于哪个对象,从而实现不同功能
//一般会写两个槽函数,此处加了判断,减少了一个槽函数,不错的思路
void QmyWidget::on_spin_valueChanged(int arg1)
{//响应界面上spinBox的valueChanged(int)信号
    Q_UNUSED(arg1);
    QSpinBox *spinBox = qobject_cast<QSpinBox *>(sender());
    if (spinBox->property("isBoy").toBool())
        boy->setAge(spinBox->value());
    else
        girl->setAge(spinBox->value());
}

void QmyWidget::on_btnClassInfo_clicked()
{//"类的元对象信息"按钮,显示的时类的信息,不管是boy或者girl都是可以的
//    const QMetaObject *meta=boy->metaObject();
    const QMetaObject *meta=girl->metaObject(); //获取元对象
//    const QMetaObject *meta=ui->spinBoy->metaObject();
    ui->textEdit->clear();

    ui->textEdit->appendPlainText("==MetaObjectInfo==\n");
    ui->textEdit->appendPlainText(QString("ClassName: %1\n").arg(meta->className()));

    ui->textEdit->appendPlainText("property");
    for (int i=meta->propertyOffset();i<meta->propertyCount();i++)
    {
        const char* propName=meta->property(i).name();
        ui->textEdit->appendPlainText(
           QString("PropertyName=%1, PropertyValue=%2").arg(propName).arg(boy->property(propName).toString()));
    }

    ui->textEdit->appendPlainText("");
    ui->textEdit->appendPlainText("classInfo");
    for (int i=meta->classInfoOffset();i<meta->classInfoCount();++i)
    {
       QMetaClassInfo classInfo=meta->classInfo(i);
        ui->textEdit->appendPlainText(
           QString("Name=%1; Value=%2").arg(classInfo.name()).arg(classInfo.value()));
    }

}

4.5 qmywidget.ui

在这里插入图片描述

4.6 运行结果

在这里插入图片描述

5.源码下载

有需要源码的可以至03-1-Qt 5.9 C++开发指南-Qt核心特点源码进行下载

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Servlet 项目创建和部署

目录 创建步骤&#xff1a; 1.创建项目 ​编辑2. 引入依赖 3.创建目录&#xff0c;复制内容 4.编写代码 5.打包 6.部署 7.验证 简化: 常见报错情况&#xff1a; 1.端口占用 2.路径错误 3.405 4.500 服务器代码抛出异常 5.依赖没下载好 创建步骤&#xff1a; 1.…

标注一致性计算

在统计学中&#xff0c;标注一致性&#xff08;Inter-annotation agreement, IAA&#xff09;用于评价独立观察者之间对同一现象进行评估时的一致程度。因此&#xff0c;本文讨论最多的是多位标注员对相同数据进行标注时的一致性评估方法。 一、Kappa统计量 评估一致性最简单…

Mysql高级篇(面试必看)

Mysql高级篇知识点&#xff0c;全篇手打&#xff0c;大家觉得有用的话点一个赞&#xff0c;持续更新 目录 1.Mysql锁的机制&#xff1a;粒度分类&#xff0c;思想分类&#xff0c;实现分类&#xff0c;状态分类&#xff0c;算法分类 2.Mysql的隔离级别&#xff1a;读未提交&…

视觉SLAM学习路线思维导图

整理了一下视觉SLAM学习路线的思维导图&#xff0c;防遗忘&#xff0c;不足的地方也希望各路大神能够不吝赐教。

Nginx(2)静态资源部署

静态资源 静态资源的配置指令静态资源优化配置静态资源压缩Gzip模块配置指令Gzip压缩功能的实例Gzip和sendfile共存问题gzip_static测试使用 静态资源的缓存处理浏览器缓存相关指令 Nginx的跨域问题解决静态资源防盗链防盗链的实现原理防盗链的具体实现 上网搜索访问资源是通过…

Java15——枚举类、注解、作业

1. 枚举类 跳了很多。。。 2. 注解 3. 作业 1. 注意&#xff1a;所有类共享静态属性 所以结果是 9&#xff0c;red 100&#xff0c;red package com.zsq.homework1;public class HM1 {public static void main(String[] args) {Cellphone cellphone new Cellphone();cel…

Java面试题大全(23年整理版)最新全面技巧讲解

程序员面试背八股&#xff0c;可以说是现在互联网开发岗招聘不可逆的形式了&#xff0c;其中最卷的当属 Java&#xff01;&#xff08;网上动不动就是成千上百道的面试题总结&#xff09;你要是都能啃下来&#xff0c;平时技术不是太差的话&#xff0c;面试基本上问题就不会太大…

如何在 MATLAB 中进行图像分割(matlab仿真与图像处理系列第7期)

在 MATLAB 中进行图像分割有多种方法,下面介绍一些常用的方法: 基于阈值的二值化分割这是一种最简单的分割方法,将图像分为两个部分:背景和前景。其主要思想是,选择一个阈值,将图像中的像素值与阈值进行比较,将像素值大于阈值的像素标记为前景(白色),将像素值小于阈值…

自动化测试练手项目推荐

最近收到许多自学自动化测试的小伙伴私信&#xff0c;学习了理论知识后&#xff0c;却没有合适的练手项目。 测试本身是一个技术岗位&#xff0c;如果只知道理论&#xff0c;没有实战经验&#xff0c;在面试中很难说服面试官&#xff0c;比如什么场景下需要添加显示等待&#x…

小白用旧手机搭建web服务器(一):实现局域网访问

1、首先要拥有一部安卓手机 2、下载ksweb 我们需要下载ksweb这款app&#xff0c;这是一位俄罗斯大神制作的&#xff0c;里面集成了Lighttpd、nginx、Apache的服务器&#xff0c;还有mysql服务器等&#xff0c;十分强大。 下载地址&#xff1a;KSWEB_3-93_kill_无ad.apk - 蓝…

大数据技术生态体系

6 大数据技术生态体系 图中涉及的技术名词解释如下: 1)Sqoop:Sqoop 是一款开源的工具,主要用于在 Hadoop、Hive 与传统的数据库(MySQL)间进行数据的传递,可以将一个关系型数据库(例如 :MySQL,Oracle 等)中的数据导进到 Hadoop 的 HDFS 中,也可以将 HDFS 的数据导进…

GPIO复用功能1——定时器输入捕获

文章目录 前言定时器输入捕获红外接收的数据分析捕获思路编程实践1.初始化时钟2.初始化GPIO3.配置定时器的时钟基准4.配置输入捕获参数5.中断配置6.中断服务函数7.处理数据帧 实现效果 总结 前言 前面介绍了GPIO的通用输入输出功能&#xff0c;以及其模拟时序的功能&#xff0c…

软件模拟实现SPI通信-GD32

软件模拟实现SPI通信-GD32 设计流程 #ifndef _SOFT_SPI_H #define _SOFT_SPI_H /** filename: soft_spi.h**/ #include "gd32f10x.h" #include "systick.h"//定义表示具体IO口的资源宏 #define SPI_PORT GPIOA #define SPI_MOSI GPIO_PIN_7 #define SP…

【华为OD机试】翻转骰子(python, java, c++, js)

翻转骰子 前言:本专栏将持续更新华为OD机试题目,并进行详细的分析与解答,包含完整的代码实现,希望可以帮助到正在努力的你。关于OD机试流程、面经、面试指导等,如有任何疑问,欢迎联系我,wechat:steven_moda;email:nansun0903@163.com;备注:CSDN。 题目描述 骰子是…

java中的knife4j、Swagger配置过程详解

knife4j的配置过程如下&#xff1a; 1、首先引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency><groupId>com.github…

CentOS Linux的替代品(四)_openEuler 22.03-LTS基础安装教程

文章目录 1 openEuler 22.03-LTS简介1.1 系统安装1.1.1 发布件1.1.2 最小硬件要求1.1.3 硬件兼容性 1.2 关键特性1.2.1 openEuler 22.03-LTS基于 Linux Kernel 5.10内核构建, 在进程调度、内存管理等方面带来10余处创新1.2.2 新介质文件系统1.2.3 内存分级扩展1.2.4 用户态协议…

Clouder Manager日常管理及使用

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

低代码:解放生产力的利器还是一场空洞的炒作?

低代码有人说是毒瘤&#xff0c;也有人说是银弹。到底应该怎么看呢&#xff1f;存在即合理。 “存在”包括两个角度&#xff1a; 银弹论毒瘤论 无论从哪个角度看&#xff0c;既然存在这样的论调&#xff0c;就有它们的合理性。 先把关注点移到低代码本身&#xff0c;低代码…

关联查询和子查询

关联查询和子查询&#xff1a; 二、关联查询&#xff1a; 1、全连接&#xff1a;两个表作笛卡尔积 2、内连接&#xff1a;找到两个表中的关联数据 3、外连接&#xff1a; 左外连接&#xff1a;grade中12无学生&#xff0c;但是还是会显示出来&#xff08;以左边的表为基准&am…

javascript 触发事件

在 JavaScript 中&#xff0c;原始方法 initEvent() 用于创建新事件。 最新更新添加了用于构建自定义事件的新关键字。 此外&#xff0c;在为 JavaScript 构建的清单中还有大量事件。 以下部分将预览预定义事件之一的示例及其触发方式。 还有一个定制的事件&#xff0c;将细节…