【QT八股文】系列之篇章2 | QT的信號與槽機制及通訊流程

【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.pswp.cn/bicheng/14598.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/14598.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/14598.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深入分析 Android Activity (三)

深入分析 Android Activity (三) 1. Activity 的配置變化處理 當設備配置&#xff08;如屏幕方向、語言、屏幕大小等&#xff09;發生變化時&#xff0c;默認情況下&#xff0c;Android 會銷毀并重新創建當前的 Activity。這種行為確保了新配置能夠正確應用&#xff0c;但在某…

HTML5 性能優化和計算機硬件使用

目錄 啟用硬件加速圖像與媒體優化資源加載與緩存CSS與布局優化JavaScript性能優化瀏覽器兼容性與特性檢測啟用硬件加速 Canvas繪圖 <canvas> 元素支持硬件加速,可以顯著提升圖形繪制和動畫的性能。確保在支持的瀏覽器中啟用硬件加速,如使用translate3d(0, 0, 0) hack…

解鎖Android高效數據傳輸的秘鑰 - Parcelable剖析

作為Android開發者&#xff0c;我們經常需要在不同的組件(Activity、Service等)之間傳輸數據。這里的"傳輸"往往不僅僅是簡單的數據復制&#xff0c;還可能涉及跨進程的內存復制操作。當傳輸的數據量較大時&#xff0c;這種操作可能會帶來嚴重的性能問題。而Android系…

web自動化之PO模式

PO模式 1、為什么需要PO思想&#xff1f; 首先我們觀察和思考一下&#xff0c;目前我們寫的作業腳本的問題&#xff1a; 元素定位和操作動 作寫到一起了&#xff0c;這就就會用導致一個問題&#xff1a; UI的頁面元素比較容易變化的&#xff0c;所以元素定位和腳本操作寫到一…

如何將照片從 iPhone 傳輸到閃存驅動器【無質量損壞】

概括 人們喜歡用 iPhone 拍照&#xff0c;因為照片通常都很漂亮&#xff0c;這都要歸功于 iPhone 令人驚嘆的技術。但照片更新后會占用更多空間&#xff0c;并且您可能會開始收到沒有存儲空間的通知。因此&#xff0c;您可以將照片傳輸到 USB 驅動器&#xff0c;然后從 iPhone…

Spring Boot構建mvc項目

好的,以下是一個簡單的Java MVC(Model-View-Controller)項目示例,使用Spring Boot框架和MySQL數據庫。這個項目包括基本的CRUD操作。 項目結構 src/ └── main/├── java/│ └── com/│ └── example/│ └── demo/│ ├──…

springboot-阿里羚羊 服務端埋點

官方文檔 集成Java SDK 手動引入jar包「quickaplus-log-collector-java-sdk-1.0.1-SNAPSHOT.jar」 <dependency><groupId>com.alibaba.lingyang</groupId><artifactId>quickaplus-log-collector-java-sdk</artifactId><version>1.0.1&l…

應用案例 | 如何實時監測和管理冷鏈倉庫溫濕度?

一、項目背景 冷鏈倉庫溫濕度管理的重要性在于確保倉庫內產品的質量和安全。通過遵循相關法規和標準&#xff0c;滿足客戶對產品質量的需求&#xff0c;同時實施有效的溫濕度管理措施&#xff0c;可以降低成本并提高倉庫作業效率。該項目的實施旨在幫助客戶保證產品的新鮮度&a…

Java - AbstractQueuedSynchronizer

AQS簡介 AQS全稱AbstractQueuedSynchronizer&#xff0c;抽象隊列同步器&#xff0c;是一個實現同步組件的基礎框架。AQS使用一個int類型的成員變量state維護同步狀態&#xff0c;通過內置的同步隊列&#xff08;CLH鎖、FIFO&#xff09;完成線程的排隊工作&#xff0c;底層主…

echarts 散點圖修改散點圖中圖形形狀顏色大小

話不多說&#xff0c;直接上代碼 let option {color:[xxx, xxx, xxx, xxx], //直接設置color可修改圖形顏色title: {text: 散點圖圖形,},tooltip: {trigger: axis,axisPointer: {type: cross}},legend: {top: 2,right:2,itemWidth: 10,itemHeight: 10,textStyle:{fontSize:14}…

shell腳本條件語句和循環語句

文章目錄 一、條件語句測試比較整數數值字符串比較邏輯運算雙中括號&#xff08; &#xff09;{ }if語句結構case語句 二、循環語句基礎知識for循環whileuntil雙重循環及跳出循環 一、條件語句 測試 條件測試&#xff1a;判斷某需求是否滿足&#xff0c;需要由測試機制來實現…

視頻分類——C3D使用

整體比較分散&#xff0c;可能很多源碼都需要修改&#xff0c;需要有耐心。 一、數據準備 PS 調研后&#xff0c;上手容易代碼比較簡潔的是&#xff1a;https://github.com/Niki173/C3D/tree/main 因為源碼很多參數都寫死到了源碼中&#xff0c;沒有解耦&#xff0c;并且默…

CCF-CSP認證 2024年3月 4.化學方程式配平

題解&#xff1a;首先完成數據的讀入&#xff0c;然后高斯消元求秩按題意解即可 #pragma GCC optimize(2, 3, "Ofast", "inline") #include <bits/stdc.h> using namespace std; const int maxn 100;using matrix double[maxn][maxn]; using vect…

5.20Git

版本控制工具Git&#xff0c;其他的工具還有SVN 共享代碼&#xff0c;追溯記錄&#xff0c;存儲.c文件 Git實現的功能&#xff1a;回溯&#xff08;以前某個時間節點的數據情況&#xff09;共享&#xff08;大家共享修改&#xff09; Git&#xff1a;80% SVN&#xff…

QT tableWidget詳細分析

一.定義 QTableWidget是一個用于顯示表格數據的Qt控件&#xff0c;它是一個基于Qt Model/View框架的視圖組件。QTableWidget提供了一種簡單的方式來展示和編輯表格數據&#xff0c;用戶可以通過添加行、列和單元格來構建一個完整的數據表格。 下面是一些QTableWidget的主要特點…

The Missing Semester of Your CS Education(計算機教育中缺失的一課)

Shell 工具和腳本(Shell Tools and Scripting) 一、shell腳本 1.1、變量賦值 在bash中為變量賦值的語法是foobar&#xff0c;訪問變量中存儲的數值&#xff0c;其語法為 $foo。 需要注意的是&#xff0c;foo bar &#xff08;使用空格隔開&#xff09;是不能正確工作的&…

網工內推 | 香港移動,10年以上數通經驗,CCIE,5W-6W

01 香港移動招聘 &#x1f537;招聘崗位&#xff1a;網絡工程師 &#x1f537;崗位要求&#xff1a; 需要有10年及以上數通經驗&#xff0c;有CCIE 證書&#xff0c;懂技術管理&#xff0c;溝通暢通 &#x1f537;語言要求&#xff1a; 粵語英語 &#x1f537;薪資&#xff1…

基于灰狼優化算法優化RBF(GWO-RBF)的數據回歸預測(多輸入多輸出)

代碼原理及流程 基于灰狼優化算法優化多輸入多輸出&#xff08;MIMO&#xff09;的RBF神經網絡的數據回歸預測&#xff0c;可以采取以下步驟&#xff1a; 1. 數據準備&#xff1a;準備包含多個輸入特征和多個輸出目標的數據集&#xff0c;確保數據已經經過預處理和歸一化。 …

TCP - 半連接隊列和全連接隊列

目錄 一、半連接隊列和全連接隊列的概念 二、全連接隊列溢出 三、半連接隊列溢出 一、半連接隊列和全連接隊列的概念 1. 半連接隊列&#xff1a;服務端收到客戶端發送的 SYN 包時&#xff0c;內核會將該連接加入半連接 SYN 隊列&#xff0c;并向客戶端返回響應 2. 全連接隊…

CSS基礎(第二天)

Emmet語法 快速生成HTML結構語法 1. 生成標簽 直接輸入標簽名 按tab鍵即可 比如 div 然后tab 鍵&#xff0c; 就可以生成 <div></div> 2. 如果想要生成多個相同標簽 加上 * 就可以了 比如 div*3 就可以快速生成3個div 3. 如果有父子級關系的標簽&#xff0c;可以…