【QT八股文】系列之篇章2 | QT的信号与槽机制及通讯流程

news/2024/7/20 18:31:19/文章来源:https://blog.csdn.net/qq_41895003/article/details/139076766

【QT八股文】系列之篇章2 | QT的信号与槽机制及通讯流程

  • 前言
  • 2. 信号与槽
    • 信号与槽机制介绍/本质/原理,什么是Qt信号与槽机制?如何在Qt中使用?
    • 信号与槽机制原理,解析流程
    • Qt信号槽的调用流程
    • 信号与槽机制的优缺点
    • 信号与槽机制需要注意的问题
    • 信号的注意点
    • 信号与槽与回调函数区别
    • Qt信号与槽的多种用法
    • PYQT5 connect 函数
    • Qt connect 函数的连接方式
    • PYQT5信号槽的链接方式
    • 信号槽同步与异步/多线程下,信号槽分别在什么线程中执行,如何控制——`Qt connect 函数的连接方式`来控制
  • 3. 通讯流程
    • QT的TCP通讯流程
    • QT的UDP通讯流程
  • 下一章笔记
  • 说明

前言

第一篇章主要是基础定义及QT中重要的事件机制
笔记链接:【QT八股文】系列之篇章1 | QT的基础知识及事件/机制

这里我们在了解了QT的大概后,我们将来了解QT中的核心机制:信号与槽
因为介绍到信号与槽,所以笔者我会讲通讯流程提前在前面来介绍

原创文章,未经同意请勿转载

2. 信号与槽

信号与槽机制介绍/本质/原理,什么是Qt信号与槽机制?如何在Qt中使用?

在这里插入图片描述

  • 定义
    Qt信号与槽机制是一种基于事件机制的编程模型,用于对象之间的通信。信号是由发送方对象发射的事件,而槽是接收方对象用于处理这些事件的函数。在Qt中,我们可以使用QObject类中的信号和槽机制来实现对象间的通信。通过定义信号和槽函数,在信号发射时,会自动调用对应的槽函数进行处理。

  • 使用
    PyQt的内置信号是自动定义的,使用PyQt5.QtCore.pyqtSignal函数可以为QObject对象创建一个信号,使用pyqtSignal函数可以把信号定义为类的属性。使用connect函数可以将信号绑定到槽函数上,使用disconnect函数可以解除信号与槽函数的绑定,使用emit函数可以发射信号。

  • 本质(就是回调函数)
    在事件的处理方面,信号槽相比回调函数,具有类型安全、松耦合、任意参数的优势,但执行效率会有一点损失。信号相当于传递参数(指实参,用于传递值/动作变化),槽函数像用于传递函数体(形参/函数体,用于接收值/根据动作变化来做出对应操作。)

  • 原理

    1. Qt 中的信号与槽机制是一种事件处理机制,它允许程序在接收到特定事件时执行特定的操作。在 Qt 中,信号与槽机制被广泛应用于组件之间的通信和事件处理。
    2. 具体来说,Qt 中的信号与槽机制是基于 QObject 类的。任何一个 QObject 对象都可以作为一个信号源,它可以通过 emit() 方法发出信号。同时,任何一个 QObject 对象都可以作为一个槽,它可以接受并处理来自信号源的信号。当一个信号源发出信号时,它会连接到相应的槽。这些槽可以是与信号源同一个对象,也可以是其他 QObject 对象。当信号源接收到信号时,它会将信号传递给所有已经连接到该槽的对象。这些对象会在接收到信号时执行相应的操作。

信号与槽机制原理,解析流程

在这里插入图片描述

  • 原理

    1. Qt 中的信号与槽机制是一种事件处理机制,它允许程序在接收到特定事件时执行特定的操作。在 Qt 中,信号与槽机制被广泛应用于组件之间的通信和事件处理。
    2. 具体来说,Qt 中的信号与槽机制是基于 QObject 类的。任何一个 QObject 对象都可以作为一个信号源,它可以通过 emit() 方法发出信号。同时,任何一个 QObject 对象都可以作为一个槽,它可以接受并处理来自信号源的信号。当一个信号源发出信号时,它会连接到相应的槽。这些槽可以是与信号源同一个对象,也可以是其他 QObject 对象。当信号源接收到信号时,它会将信号传递给所有已经连接到该槽的对象。这些对象会在接收到信号时执行相应的操作。
  • 解析流程

    1. moc查找头文件中的signals,slots,标记出信号和槽。
    2. 将信号槽信息存储到类静态变量staticMetaObject中,并且按声明顺序进行存放,建立索引。
    3. 当发现有connect连接时,将信号槽的索引信息放到一个map中,彼此配对。
    4. 当调用emit时,调用信号函数,并且传递发送信号的对象指针,元对象指针,信号索引,参数列表到active函数
    5. 通过active函数找到在map中找到所有与信号对应的槽索引
    6. 根据槽索引找到槽函数,执行槽函数。

Qt信号槽的调用流程

注意:信号槽的实现:元对象编译器MOC,MOC的本质就是反射器

  • MOC(元对象编译器)查找头文件中的signal与slots,标记出信号槽。将信号槽信息储存到类静态变量staticMetaObject中,并按照声明的顺序进行存放,建立索引。
  • connect链接,将信号槽的索引信息放到一个双向链表中,彼此配对。
  • emit被调用,调用信号函数,且传递发送信号的对象指针,元对象指针,信号索引,参数列表到active函数。
  • active函数在双向链表中找到所有与信号对应的槽索引,根据槽索引找到槽函数,执行槽函数。

信号与槽机制的优缺点

  • 优点
    • 类型安全。需要关联的信号槽的签名必须是等同的。即信号的参数类型和参数个数同接受该信号的槽的参数类型和参数个数相同。若信号和槽签名不一致,编译器会报错。信号的参数可以多于槽,槽参数数量不能大于于信号

      💡 槽函数的参数是否可以比信号的参数多?
      也可以。唯一的情况就是槽函数参数带有默认参数,除去默认参数外,槽函数的参数必须小于等于信号的参数。

    • 松散耦合。QT的信号槽的建立和解除绑定十分自由。信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无需知道是那个对象的那个信号槽接收它发出的信号,它只需在适当的时间发送适当的信号即可,而不需要关心是否被接受和那个对象接受了。Qt就保证了适当的槽得到了调用,即使关联的对象在运行时被删除。程序也不会奔溃。

      💡 信号重载了,如何确定连接哪个信号?
      采用函数指针确定连接哪个信号。

    • 灵活性。一个信号可以关联多个槽,或多个信号关联同一个槽。

  • 不足
    • 速度较慢。与回调函数相比,信号和槽机制运行速度比直接调用非虚函数慢10倍。信号槽同真正的回调函数比起来时间的耗损还是很大的,所以在嵌入式实时系统中应当慎用。
      • 原因:
        • ①需要定位接收信号的对象。
        • ②安全地遍历所有关联槽。
        • ③编组、解组传递参数。
        • ④多线程的时候,信号需要排队等待。(然而,与创建对象的new操作及删除对象的delete操作相比,信号和槽的运行代价只是他们很少的一部分。信号和槽机制导致的这点性能损耗,对实时应用程序是可以忽略的。
    • 不能出现宏定义。信号槽的参数限定很多例如不能携带模板类参数,不能出现宏定义等等。

信号与槽机制需要注意的问题

信号与槽机制是比较灵活的,但有些局限性我们必须了解,这样在实际的使用过程中才能够做到有的放矢,避免产生一些错误。下面就介绍一下这方面的情况。

  • 信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活 性,因此在速度上还是有所损失,当然这种损失相对来说是比较小的,通过在一台 i586- 133 的机器上测试是 10 微秒(运行 Linux),可见这种机制所提供的简洁性、灵活性还是 值得的。但如果我们要追求高效率的话,比如在实时系统中就要尽可能的少用这种机制。
  • 信号与槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时也有可能 产生死循环。因此,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射 所接收到的同样信号。
  • 如果一个信号与多个槽相关联的话,那么,当这个信号被发射时,与之相关的槽被 激活的顺序将是随机的,并且我们不能指定该顺序。
  • 宏定义不能用在 signal 和 slot 的参数中。
  • 构造函数不能用在 signals 或者 slots 声明区域内。
  • 函数指针不能作为信号或槽的参数。
  • 信号与槽不能有缺省参数。
  • 信号与槽也不能携带模板类参数。

信号的注意点

  • 所有的信号声明都是公有的,所以Qt规定不能在signals前面加public,private, protected。
  • 所有的信号都没有返回值,所以返回值都用void。
  • 所有的信号都不需要定义。
  • 必须直接或间接继承自QOBject类,并且开头私有声明包含Q_OBJECT。
  • 在同一个线程中,当一个信号被emit发出时,会立即执行其槽函数,等槽函数执行完毕后,才会执行emit后面的代码,如果一个信号链接了多个槽,那么会等所有的槽函数执行完毕后才执行后面的代码,槽函数的执行顺序是按照它们链接时的顺序执行的。不同线程中(即跨线程时),槽函数的执行顺序是随机的。
  • 在链接信号和槽时,可以设置链接方式为:在发出信号后,不需要等待槽函数执行完,而是直接执行后面的代码,是通过connect的第5个参数。
  • 信号与槽机制要求信号和槽的参数一致,所谓一致,是参数类型一致。如果不一致,允许的情况是,信号的参数可以比槽函数的参数多,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少),但是不能说信号根本没有这个数据,你就要在槽函数中使用(就是槽函数的参数比信号的多,这是不允许的)。

信号与槽与回调函数区别

  1. 链接的不同

    • 回调函数使用函数指针来实现的,如果多个类都关注一个类的动态变化,这样就会需要写出一个比较长的列表来管理这些类之间的关系。稍微在编码方面不那么灵活,稍显冗余。
    • QT使用信号与槽来解决这个连接问题,这种方式比较清晰简单一些,一个类只需要清楚自己有几个槽函数有几个信号,然后将信号与槽进行连接,QT会自己处理函数的调用关系。这样在软件设计角度更加的清晰,灵活,不容易出错。
  2. 执行顺序/时间的不同

    • Qt 信号与槽机制中的槽函数在接收到信号时会自动执行,而回调函数通常是在调用时立即执行。Qt 信号与槽机制可以在信号触发时立即执行槽函数,也可以延迟执行槽函数,而回调函数通常是立即执行的。
    • 信号与槽机制中的信号与槽之间的执行顺序是不确定的,可以是任意顺序,也可以是逆序;而回调函数机制中的回调函数之间的执行顺序通常是确定的,按照函数声明的顺序执行。
  3. 对象绑定

    信号与槽机制可以实现对象之间的动态绑定,可以在运行时动态地绑定信号与槽;而回调函数机制通常只能在程序启动时进行绑定。

  4. 主要用途不同

    信号和槽机制是用于在程序运行时传递数据和事件的机制,而回调函数则通常被用于函数或方法的调用。因此,信号和槽机制可以用于模块之间的通信和交互,而回调函数则通常用于函数或方法的调用。

Qt信号与槽的多种用法

  • 一个信号可以和多个槽相连
    这时槽的执行顺序和在不在同一个线程上有关,同一线程,槽的执行顺序和声明顺序有关,跨线程时,执行顺序是不确定的。
  • 多个信号可以连接到一个槽
    只要任意一个信号发出,这个槽就会被调用。
  • 一个信号可以连接到另外的一个信号
    当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。
  • 槽可以被取消链接
    这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽。想主动取消连接就用disconnect()函数中添加任何实现。
  • 可以使用Lambda 表达式
    在使用 Qt 5 的时候,能够支持 Qt 5 的编译器都是支持 Lambda 表达式的。

PYQT5 connect 函数

注:在Qt中第五个参数用于指定信号与槽的匹配规则。而PYQT5是第四个参数
在 PyQt5 中,connect 函数【connect: PyQt5.QtWidgets.QSignalMapper()】是一个用于连接信号与槽的函数。它通常被用于将对象的信号与槽函数进行连接。

列子:mapper = Qt.QSignalMapper() mapper.setMapping(button, button.clicked.connect(mapper.setCurrentIndex))

第一个参数是一个可选的参数,用于指定要连接的信号源。如果该参数为 None,则表示连接的是系统提供的信号。如果该参数不为 None,则表示要连接自定义信号。

第二个参数是一个可选的参数,用于指定要连接的槽函数。如果该参数为 None,则表示连接的是默认槽函数。如果该参数不为 None,则表示要连接指定的槽函数。

第三个参数是一个字符串,用于指定信号与槽之间的映射关系。该字符串通常由信号名称和槽函数名称组成。例如,“clicked” 表示将按钮的点击信号与按钮的 clicked 槽函数进行连接。

第四个参数是一个 PyQt5 中的 QSignalMapper 对象,用于指定信号与槽的匹配规则。该对象应该实现 QSignalMapper 类中的方法,例如 setMapping() 和 currentIndex() 等。

第五个参数是一个可选的参数,用于指定信号中断连接的函数。如果连接的信号源对象被删除或重新分配,则连接将被中断。默认情况下,连接不会自动中断。

Qt connect 函数的连接方式

  1. 自动连接Qt::AutoConnection
    默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用
    多线程时为队列连接函数,单线程时为直接连接函数。

  2. 直接连接Qt::DirectConnection
    == 如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。==
    Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数和信号发送者在同一线程。效果看上去就像是直接在信号发送位置调用了槽函数,效果上看起来像函数调用,同步执行。
    emit语句后面的代码将在与信号关联的所有槽函数执行完毕后才被执行。
    信号/槽在信号发出者所在的线程中执行

  3. 队列连接Qt::QueuedConnection
    信号发出后,信号会暂时被放到一个消息队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,然后执行和信号关联的槽函数,这种方式既可以在同一线程内传递消息也可以跨线程操作。
    emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕
    信号在信号发出者所在的线程中执行,槽函数在信号接收者所在的线程中执行

  4. Qt::BlockingQueuedConnection
    槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。而且接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

  5. Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是为了避免重复连接。

PYQT5信号槽的链接方式

在 PyQt5 中,信号与槽的连接方式有两种:1. 使用 connect() 函数;2. 装饰器@pyqtSlot() 。

@pyqtSlot()优点是方式书写比较简洁。缺点是但函数名称不能自由定义,在想自定义参数时没有详细说明。

connect()方式优点是理解和学习起来比较简单,而且函数名称可以自由定义。缺点是但如果信号比较多时,书写就比较混乱。

使用信号处理器的优点是可以在信号发生时执行复杂的操作,而缺点是连接信号处理器需要花费更多的内存和时间,并且连接信号处理器需要手动管理连接关系。因此,使用信号处理器仅适用于需要执行复杂操作的情况。

  1. 装饰器方法:@pyqtSlot()装饰器

    @pyqtSlot():修饰关键词,表明下面是完整的信号槽函数

    # 需要引入 pyqtSlot 库函数
    from PyQt5.QtCore import pyqtSlot@pyqtSlot() #装饰器,此函数没有connect直接通过装饰器初始化连接槽函数
    def on_pushButton_clicked(self)print("我点击了")
    

    在@pyqtSlot()方式里,函数名称有特殊要求,如下:

    def  on_(控件对象名)_信号名(self,内置参数)

    @pyqtSlot()控制控件的多信号

    @pyqtSlot()
    def on_lineEdit_returnPressed(self):print('触发了信号 returnPressed')def on_lineEdit_textChanged(self):print('触发了信号 textChanged')
    

    注意:一个控件同时要写多个信号与槽函数时,只需要写一遍@pyqtSlot()关键词,中间可以有其他函数隔开。一定是一个类里面的,一个控件只写一遍@pyqtSlot(),不是所有控件信号只写一次@pyqtSlot(),有多少控件的信号还是要写。

  2. connect连接法

    使用 connect() 函数将信号与槽函数连接起来。connect() 函数接受两个参数:要连接的信号和要连接的槽函数。连接成功后,当信号发生时,槽函数将被调用。

    # 在初始化函数中信号连接槽函数
    self.pushButton.clicked.connect(self.test)
    # 槽函数
    def test(self):print("点击了一下")
    

    规则:

    • 语法规则:self.控件对象名称.信号名称.connect(self.槽函数名称)
    • 有参数时,槽函数名称部分写成lambda 参数名: 函数名(参数名)
    • 没有参数时,槽函数不用写括号()

信号槽同步与异步/多线程下,信号槽分别在什么线程中执行,如何控制——Qt connect 函数的连接方式来控制

可以通过QT的connect函数的第五个参数(PYQT5中是第四个参数)来控制, 信号槽执行时所在的线程。

通常使用的connect,实际上最后一个参数使用的是Qt::AutoConnection类型:Qt支持6种连接方式,其中3中最主要:

  1. Qt::AutoConnection(自动方式)

    信号槽在信号发出者所在的线程中执行

    Qt的默认连接方式,如果信号的发出和接收这个信号的对象同属一个线程,那个工作方式与直连方式相同(会自动使用Qt::DirectConnection类型);否则工作方式与排队方式相同(会自动使用Qt::QueuedConnection类型)。

    即多线程时为队列连接函数,单线程时为直接连接函数。

  2. Qt::DirectConnection(直连方式)(信号与槽函数关系类似于函数调用,同步执行)

    当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。

  3. Qt::QueuedConnection(排队方式)(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信,异步执行)

    信号在信号发出者所在的线程中执行,槽函数在信号接收者所在的线程中执行

    当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,调用相应的槽函数。emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。

  4. Qt::BlockingQueuedConnection(信号和槽必须在不同的线程中,否则就产生死锁)

    这个是完全同步队列只有槽线程执行完成才会返回,否则发送线程也会一直等待,相当于是不同的线程可以同步起来执行

    与Qt::QueuedConnection相同,除了信号线程阻塞直到槽返回。如果接收方处于发送信号的线程中,则不能使用此连接,否则应用程序将死锁。

  5. Qt::UniqueConnection

    与默认工作方式相同,只是不能重复连接相同的信号和槽,因为如果重复连接就会导致一个信号发出,对应槽函数就会执行多次。

    这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是为了避免重复连接。

  6. Qt::AutoCompatConnection

    是为了连接Qt4与Qt3的信号槽机制兼容方式,工作方式与Qt::AutoConnection一样。

3. 通讯流程

QT的TCP通讯流程

在这里插入图片描述
QT如果要进行网络编程首先需要在.pro中添加如下代码:QT += network

  • 服务端:(QTcpServer)
    ① 创建QTcpServer对象
    ② 监听list需要的参数是地址和端口号
    ③ 当有新的客户端连接成功回发送newConnect信号
    ④ 在newConnection信号槽函数中,调用nextPendingConnection函数获取新连接QTcpSocket对象
    ⑤ 连接QTcpSocket对象的readRead信号
    ⑥ 在readRead信号的槽函数使用read接收数据
    ⑦ 调用write成员函数发送数据

  • 服务器端

    1. 创建用于监听的套接字

    2. 给套接字设置监听

    3. 如果有连接到来, 监听的套接字会发出信号newConnected

    4. 接收连接, 通过nextPendingConnection()函数, 返回一个QTcpSocket类型的套接字对象(用于通信)

    5. 使用用于通信的套接字对象通信 1>. 发送数据: write 2>. 接收数据: readAll/read

      • 代码

        Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
        {ui->setupUi(this);tcpServer = new QTcpServer;tcpServer->listen(QHostAddress("192.168.0.111"),1234);connect(tcpServer,SIGNAL(newConnection()),this,SLOT(new_connect()));
        }Widget::~Widget()
        {delete ui;
        }void Widget::new_connect()
        {qDebug("--new connect--");QTcpSocket* tcpSocket = tcpServer->nextPendingConnection();connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(read_data()));socketArr.push_back(tcpSocket);}void Widget::read_data()
        {for(int i=0; i<socketArr.size(); i++){if(socketArr[i]->bytesAvailable()){char buf[256] = {};socketArr[i]->read(buf,sizeof(buf));qDebug("---read:%s---",buf);}}
        }
        
  • 客户端:(QTcpSocket)
    ① 创建QTcpSocket对象
    ② 当对象与Server连接成功时会发送connected 信号
    ③ 调用成员函数connectToHost连接服务器,需要的参数是地址和端口号
    ④ connected信号的槽函数开启发送数据
    ⑤ 使用write发送数据,read接收数据

  • 客户端:

    1. 创建用于通信的套接字
    2. 连接服务器: connectToHost
    3. 连接成功与服务器通信
      1 >. 发送数据: write 2>. 接收数据: readAll/read
    • 代码

      Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
      {ui->setupUi(this);tcpSocket = new QTcpSocket;connect(tcpSocket,SIGNAL(connected()),this,SLOT(connect_success()));tcpSocket->connectToHost("172.20.10.3",1234);
      }Widget::~Widget()
      {delete ui;
      }void Widget::on_send_clicked()
      {std::string msg = ui->msg->text().toStdString();int ret = tcpSocket->write(msg.c_str(),msg.size()+1);qDebug("--send:%d--",ret);
      }void Widget::connect_success()
      {ui->send->setEnabled(true);
      }
      

QT的UDP通讯流程

UDP(User Datagram Protocol即用户数据报协议)是一个轻量级的,不可靠的,面向数据报的无连接协议。在网络质量令人十分不满意的环境下,UDP协议数据包丢失严重。由于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。所以QQ这种对保密要求并不太高的聊天程序就是使用的UDP协议。

在Qt中提供了QUdpSocket 类来进行UDP数据报(datagrams)的发送和接收。Socket简单地说,就是一个IP地址加一个port端口 。

QT下UDP通信服务器端和客户端的关系是对等的, 做的处理也是一样的:

  1. 创建套接字对象 2. 如果需要接收数据, 必须绑定端口 3. 发送数据: writeDatagram 4. 接收数据: readDatagram

流程:①创建QUdpSocket套接字对象 ②如果需要接收数据,必须绑定端口 ③发送数据用writeDatagram,接收数据用 readDatagram 。

下一章笔记

下篇笔记链接:【QT的多线程以及QThread与QObject】
下篇笔记主要内容:QT的多线程以及QThread与QObject

说明

码字不易,可能当中存在某些字体错误(笔者我没有发现),如果有错误,欢迎大家指正。🤗
另外因为笔记是之前做的,这里我只把我之前做的搬移和重新排版过来,如果有知识上的错误也欢迎大家指正。

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

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

相关文章

猜猜我是谁游戏

猜谜过程 在TabControl控件中&#xff0c;第一个tab中放了一个PictureBox&#xff0c;里面有一张黑色的图片。 玩家点击显示答案按钮&#xff0c;切换图片。 设计器 private void button1_Click(object sender, EventArgs e){this.pictureBox1.Image Image.FromFile(&qu…

web自动化的断言和日志封装

断言 UI自动化常见的断言条件包括&#xff1a; 通过当前页面的URL地址通过当前页面的标题通过当前页面的提示文本信息通过当前页面的某些元素变化/显示 一句话总结&#xff1a;通过肉眼观察页面的变化检查。 【用代码模仿人的识别页面】 一般断言写一条就够了&#xff0c;如…

【基础算法总结】前缀和二

前缀和二 1.和为 K 的子数组2.和可被 K 整除的子数组3.连续数组4. 矩阵区域和 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.和为 K 的子数…

WPS PPT学习笔记 2 结构页的制作

制作PPT结构页 制作封面页、目录页、封底页。它们都属于结构页。而时间轴页&#xff0c;流程图页&#xff0c;框架图页这些属于内容页。 做一份PPT 讲一个故事 封面页 开头&#xff0c; 目录页 脉络&#xff0c; 各式内容页 详情&#xff0c; 封底页 结尾。 所有的结构页…

华为CE6851-48S6Q-HI升级设备版本及补丁

文章目录 升级前准备工作笔记本和交换机设备配置互联地址启用FTP设备访问FTP设备升级系统版本及补丁 升级前准备工作 使用MobaXterm远程工具连接设备&#xff0c;并作为FTP服务器准备升级所需的版本文件及补丁文件 笔记本和交换机设备配置互联地址 在交换机接口配置IP&#…

Ubuntu24.04安装tabby-terminal-1.0.207并处理依赖

1 下载 tabby-terminal-1.0.207 地址&#xff1a; https://github.com/Eugeny/tabby/releases 点击show all 36 assets 选择 tabby-1.0.207-linux-x64.deb 并下载。 2 依赖下载 gconf2_3.2.6-3ubuntu6_amd64.deb gconf2-common_3.2.6-3ubuntu6_all.deb gconf-service_3.2.6-…

fpga系列 HDL: 05 阻塞赋值(=)与非阻塞赋值(<=)

在Verilog硬件描述语言&#xff08;HDL&#xff09;中&#xff0c;信号的赋值方式主要分为两种&#xff1a;连续赋值和过程赋值。每种赋值方式有其独特的用途和语法&#xff0c;并适用于不同类型的电路描述。 1. 连续赋值&#xff08;Continuous Assignment,assign 和&#xf…

【Matlab函数分析】绘图函数:colormap查看并设置当前颜色图

&#x1f517; 运行环境&#xff1a;Matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

云计算-基础云架构(Fundamental Cloud Architectures)

工作负载分配架构&#xff08;Workload Distribution Architecture&#xff09; 工作负载分配架构是一种基础架构&#xff0c;它在一组相同的IT资源之间分配负载。其结构如图7.1所示&#xff08;更好的图示在教材中&#xff09;。 图&#xff1a;工作负载分配架构 这个结构中的…

Elasticsearch之入门与安装

Elaticsearch&#xff0c;简称为es&#xff0c; es是一个开源的高扩展的分布式全文检索引擎&#xff0c;它可以近乎实时的存储、检索数据&#xff1b;本身扩展性很好&#xff0c;可以扩展到上百台服务器&#xff0c;处理PB级别的数据。es也使用Java开发并使用Lucene作为其核心来…

【源码】一站式Java云商城系统源码,无后门

一站式Java云商城系统源码&#xff0c;无后门&#xff0c;不是java源代码&#xff0c;是编译后的。 系统对接 手动发货 自动发货 兑 换 码 订单监控 商品监控 对象存储 邮箱提醒 加价模板 密价功能 三方支付 会员体系 财务明细 交易分析 售后服务 技术支持 服务器建议配置&a…

网易面试:手撕定时器

概述&#xff1a; 本文使用STL容器-set以及Linux提供的timerfd来实现定时器组件 所谓定时器就是管理大量定时任务&#xff0c;使其能按照超时时间有序地被执行 需求分析&#xff1a; 1.数据结构的选择&#xff1a;存储定时任务 2.驱动方式&#xff1a;如何选择一个任务并执…

微信小程序中van-tab的title(动态)根据文本内容,自适应宽度

小程序van-tab的title&#xff08;动态&#xff09;根据文本内容&#xff0c;自适应宽度 效果图代码主要调整点 效果图 代码 <van-tabs color"#00aaff" active"{{ active }}" bind:click"onTabChange"><van-tab title"7天内&quo…

mac版本Phpstudy本地环境安装Discuz教程【2024】

此方法适用于m1版本的mac版本Phpstudy本地环境安装Discuz&#xff0c;当然同样使用更高版本的mac端。网上各种安装教程参差不齐&#xff0c;根本解决不了小白的入门需求&#xff0c;以下是最新且直接明了的安装教程。 Phpstudy本地环境安装Discuz教程&#xff1a; 1、安装Phps…

Activiti7_使用

Activiti7_使用 一、Activiti7二、绘制工作流三、通过代码部署流程&#xff0c;再对流程进行实例化&#xff0c;完整运行一遍流程即可四、在springbooot中使用 一、Activiti7 为了实现后端的咨询流转功能&#xff0c;学习Activiti7&#xff0c;记录下使用的过程及遇到的问题 二…

小牛翻译:图片翻译API+语音翻译API调用,保姆级使用教程

一、小牛翻译接口简介 图片翻译API 支持格式&#xff1a;png、jpg、jpeg、bmp支持图片尺寸&#xff1a;128px*128px~2048px*2048px支持最大图片大小&#xff1a;10M支持的语种&#xff1a;中、英、日、韩、俄 语音翻译API 支持格式&#xff1a;MP3、WAV支持语音时长&#x…

根据经纬度点计算经纬度点之间的距离

根据经纬度点计算经纬度点之间的距离 根据两点经纬度坐标计算直线距离 根据经纬度点计算经纬度点之间的距离 根据经纬度计算两地之间的距离 根据两点经纬度坐标计算距离 其实看第一个就够了 根据 半正矢公式&#xff08;Haversine formula&#xff09;即可计算 本计算式选取地…

2024电激世界脉动-中国汽车品牌全球化制胜手册

来源&#xff1a;奥美Ogilvy&#xff1a; 近期历史回顾&#xff1a; 2024中国宏观经济专题报告-数据要素市场建设 2023-2024年度报告.pdf 2024制药与生化医疗技术产业链白皮书.pdf 从可再生能源到绿氢-中国投资助力埃及能源转型.pdf 2024有机旅行中国行业指引.pdf 2024中国技术…

【常用的队列总结】

文章目录 队列的介绍Queue队列的基本概念与操作队列的基本概念 常见的队列介绍非阻塞队列LinkedList:ArrayDeque:PriorityQueue: 阻塞队列ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueue DelayQueueSynchronousQueue 队列的介绍 Queue队列的基本概念与操作 在 …

常见算法(1)

1.基本查找/顺序查找 核心&#xff1a;从0索引之后挨个查找 实现代码&#xff1a; public class test {public static void main(String [] arg) throws ParseException {int[] arr {121,85,46,15,55,77,63,49};int number55;System.out.println(bashi(arr,number));}publi…