最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

PyQt5通過(guò)信號(hào)實(shí)現(xiàn)MVC的示例

 更新時(shí)間:2021年02月06日 11:22:14   作者:Just for Life  
這篇文章主要介紹了PyQt5通過(guò)信號(hào)實(shí)現(xiàn)MVC的示例,幫助大家更好的理解和使用pyqt5,感興趣的朋友可以了解下

眾所周知MVC是個(gè)好東西。前陣子網(wǎng)上搜了下,但關(guān)于用PyQt5實(shí)現(xiàn)MVC的中文文檔缺少之又少,優(yōu)質(zhì)的文檔只搜到了一篇。既然這樣,來(lái),開(kāi)個(gè)坑,學(xué)習(xí)新知識(shí),吸引流量。話說(shuō),關(guān)于PyQt5,布局那里需要好好看看,容器類(lèi)控件需要好好看看,還有多線程和自動(dòng)化測(cè)試那塊。但要寫(xiě)出完美GUI需要大量的代碼經(jīng)驗(yàn)和文檔查詢(xún)的能力。然后,嗯,這部分坑就填完了。

扯回正題:假設(shè)此時(shí)面臨的場(chǎng)景是,一個(gè)軟件涉及好幾個(gè)頁(yè)面,每個(gè)頁(yè)面是單獨(dú)的代碼。且每個(gè)頁(yè)面需要有自己的controller,最終所有的controller匯總到一起,統(tǒng)一管理。

本文中,文字只是輔助理解,務(wù)必讀懂代碼。

信號(hào)

眾所周知,GUI中當(dāng)一個(gè)控件的狀態(tài)改變時(shí)需要通知另一個(gè)控件,也就是實(shí)現(xiàn)了對(duì)象間的通信。當(dāng)事件發(fā)生或狀態(tài)改變時(shí),就會(huì)發(fā)出信號(hào),信號(hào)會(huì)觸發(fā)與這個(gè)事件相關(guān)聯(lián)的函數(shù),我們這個(gè)函數(shù)為槽。信號(hào)與槽可以是多對(duì)多的關(guān)系。信號(hào)在類(lèi)創(chuàng)建時(shí)定義,即需要在初始化的前面定義。

自定義信號(hào)與槽

別問(wèn),靜靜感受以下代碼。以下的代碼中,已經(jīng)包含了信號(hào)的定義、指定參數(shù)的類(lèi)型、發(fā)射、綁定槽函數(shù)等一系列過(guò)程。

from PyQt5.QtCore import QObject, pyqtSignal

# 信號(hào)對(duì)象
class QSignal(QObject):
  # 定義信號(hào)
  # 在類(lèi)創(chuàng)建時(shí)定義,不能在類(lèi)創(chuàng)建后作為類(lèi)的屬性而添加
  # 指定信號(hào)傳遞參數(shù)的數(shù)量,類(lèi)型等
  send_msg = pyqtSignal(str, str)

  def __init__(self):
    super(QSignal, self).__init__()

  def run(self):
    # 信號(hào)發(fā)射
    self.send_msg.emit('First arg', 'Second arg')

# 槽對(duì)象
class QSlot(QObject):
  def __init__(self):
    super(QSlot, self).__init__()

  def get(self, *args):
    # 信號(hào)接收
    print("Get message =>" + args[0], args[1], sep=', ')

if __name__ == '__main__':
  send = QSignal()
  slot = QSlot()

  # 將信號(hào)與槽函數(shù)綁定
  send.send_msg.connect(slot.get)
  # 外部調(diào)用 發(fā)射信號(hào)
  send.run()
  # 信號(hào)與槽解除關(guān)聯(lián)
  send.send_msg.disconnect(slot.get)
  send.run()

內(nèi)置信號(hào)綁定自定義槽

這樣,再來(lái)看一個(gè)和窗口結(jié)合的實(shí)例。窗口中有一個(gè)按鈕,點(diǎn)擊按鈕就退出窗口。雖然這個(gè)例子很簡(jiǎn)單,不用信號(hào)和槽也能實(shí)現(xiàn)。但這里給個(gè)例子靜心感受下:信號(hào)連接、發(fā)射、接收的全邏輯。

import sys
from functools import partial
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import (QMainWindow, QApplication, QPushButton, QWidget, 
               QHBoxLayout)


class MainWindow(QMainWindow):
  btn_signal = pyqtSignal()
  def __init__(self):
    super(MainWindow, self).__init__()

    a = QPushButton("退出")
    # 給綁定的槽函數(shù)增加額外信息
    a.clicked.connect(partial(self.btn_clicked, 1))
    self.btn_signal.connect(self.close)

    self.setWindowTitle("演示")

    main_widget = QWidget()
    layout = QHBoxLayout()
    layout.addWidget(a)
    main_widget.setLayout(layout)
    # QMainWindow 不能設(shè)置布局
    self.setCentralWidget(main_widget)

  def btn_clicked(self, n):
    print(n)
    self.btn_signal.emit()

  def close(self):
    app = QApplication.instance()
    app.quit()


if __name__ == "__main__":
  # 在shell中執(zhí)行
  app = QApplication(sys.argv)
  mywin = MainWindow()
  mywin.show()
  # 開(kāi)始主循環(huán),直到退出
  sys.exit(app.exec())

這里,想給綁定的槽函數(shù)btn_clicked傳遞額外參數(shù),但信號(hào)綁定時(shí)不能添加額外參數(shù)。對(duì)應(yīng)到上述例子中,close()可以通過(guò)指定信號(hào)的參數(shù)和類(lèi)型來(lái)增加參數(shù),但btn_clicked()不能。一種解決方案是掏出萬(wàn)能的partial函數(shù),將函數(shù)和參數(shù)綁定在一起。

至此,應(yīng)該了解了信號(hào)的工作方式和原理。而關(guān)于信號(hào)更多的內(nèi)容,如重載、裝飾器等,這里不做更多介紹,詳情參考官方文檔。話說(shuō),也佩服當(dāng)年的學(xué)習(xí)方式:『把所有代碼敲一遍』。時(shí)至今日也忘記了大多控件的含義和各種樣式的代碼,變成了:到時(shí)候去查API。

MVC

MVC的大名應(yīng)該都聽(tīng)說(shuō)過(guò),model, view 和 control,即數(shù)據(jù)庫(kù)、頁(yè)面和處理邏輯相分離,這樣寫(xiě)出來(lái)的代碼更加專(zhuān)一化。這里給份代碼感受下,三個(gè)內(nèi)容用三個(gè)類(lèi)所實(shí)現(xiàn),個(gè)人不建議這樣寫(xiě),建議將文件放到三個(gè)文件夾下,而不是扔進(jìn)一份代碼里:

import sys
from PyQt5 import QtCore
from PyQt5.QtWidgets import (QWidget, QHBoxLayout, QPushButton, QMessageBox, 
               QLineEdit, QApplication)

# View
class MainWindow(QWidget):
  verifySignal = QtCore.pyqtSignal()

  def __init__(self, *args, **kwargs):
    super(MainWindow, self).__init__(*args, **kwargs)
    self.id_line = QLineEdit()
    self.id_line.setPlaceholderText("請(qǐng)輸入賬號(hào)")
    self.psd_line = QLineEdit()
    self.psd_line.setPlaceholderText("請(qǐng)輸入密碼")

    self.init()

  def init(self):

    layout = QHBoxLayout()
    self.setLayout(layout)

    self.button = QPushButton("登錄")
    layout.addWidget(self.button)

    layout.addWidget(self.id_line)
    layout.addWidget(self.psd_line)
  
    # 連接定義的信號(hào)
    self.button.clicked.connect(self.verify_emit)

  def verify_emit(self):
    self.verifySignal.emit()

  def verify_ok(self):
    QMessageBox.about(self, "密碼正確", "已經(jīng)登錄")

  def verify_no(self):
    QMessageBox.about(self, "你犯了一個(gè)粗誤", "請(qǐng)重新檢查輸入")

# model
class Student(object):

  def __init__(self):
    self.name = "aaa"
    self.password = "aaa"

# control
class LoginControll(object):

  def __init__(self):
    # 不需要從命令行輸入?yún)?shù)
    self._app = QApplication([])
    self._model = Student()
    self._view = MainWindow()
    self.init()

  def init(self):
    self._view.verifySignal.connect(self.verify_user)

  def verify_user(self):
    id_ = self._view.id_line.text()
    psd_ = self._view.psd_line.text()

    if id_ == self._model.name and psd_ == self._model.password:
      self._view.verify_ok()
    else:
      self._view.verify_no()

  def run(self):
    self._view.show()
    # 事件循環(huán),直到應(yīng)用退出
    return self._app.exec_()

# main.py
if __name__ == "__main__":
  login_control_ = LoginControll()
  # 退出主程序
  sys.exit(login_control_.run())

在這個(gè)例子里需要注意的是,將model,view和controller分成了三個(gè)類(lèi)。在view中定義信號(hào)以及信號(hào)何時(shí)發(fā)射,在controller中定義信號(hào)發(fā)射后連接的槽函數(shù),即觸發(fā)何種的響應(yīng)。這樣,通過(guò)信號(hào)的發(fā)射與連接,就將view和controller綁定在了一起。view負(fù)責(zé)頁(yè)面展示與信號(hào)定義,controller負(fù)責(zé)信號(hào)的連接與功能的實(shí)現(xiàn),完美。

MVC實(shí)現(xiàn)

單頁(yè)面

如果讀懂以上內(nèi)容,那么應(yīng)該可以實(shí)戰(zhàn)了。首先給出一個(gè)demo,就是將上面最簡(jiǎn)單的MVC的例子拆分為三個(gè)文件。這里不便代碼展示,請(qǐng)移步到我的github進(jìn)行觀看,這是文件結(jié)構(gòu),這是主文件

多頁(yè)面

在實(shí)現(xiàn)個(gè)復(fù)雜點(diǎn)的邏輯,多個(gè)頁(yè)面,多個(gè)controller,文件結(jié)構(gòu)如下所示,一個(gè)主文件,配三個(gè)文件夾,完美。這里命名時(shí)盡量規(guī)范,文件名、類(lèi)名、函數(shù)名,不然容易把自己搞暈了。python main.py執(zhí)行。

MVC-demo
├─ main.py
├─ UI
│  ├─ leftbtn_ui.py
│  ├─ login_ui.py
│  ├─ main_window_ui.py
│  └─ verify_ui.py
├─ control
│  ├─ controller.py
│  ├─ leftbtn_control.py
│  ├─ login_control.py
│  └─ verify_control.py
└─ model
    └─ model.py

調(diào)用關(guān)系如下:

這里需要注意的是變量的生存周期,main調(diào)用controller,controller調(diào)用其它的子controller,很容易在聲明一個(gè)類(lèi)后局部變量消失,導(dǎo)致信號(hào)無(wú)法連接。如在controller.py中,典型錯(cuò)誤的寫(xiě)法:

class Controll(object):

  def __init__(self):

    self._app = QApplication([])

    self._stu = Student()

    self._view = MainWindow()
    self.init()

  def init(self):
    # 子 controller 作為局部變量,調(diào)用完后立刻消失,所以無(wú)法連接信號(hào)和槽
    # 這個(gè)問(wèn)題困擾了我三天,可真是滑稽
    login_controller = login_control.Controller(self._view, self._stu.name, self._stu.password)

因?yàn)榇a文件實(shí)在太多且混亂,就不在這里展示了,不然讀者會(huì)更容易感到亂。這里只展示一個(gè)效果,完整代碼見(jiàn)我的github。其實(shí)看一個(gè)例子,就啥都懂了。

以上就是PyQt5通過(guò)信號(hào)實(shí)現(xiàn)MVC的示例的詳細(xì)內(nèi)容,更多關(guān)于PyQt5通過(guò)信號(hào)實(shí)現(xiàn)MVC的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • python中os.stat().st_size、os.path.getsize()獲取文件大小

    python中os.stat().st_size、os.path.getsize()獲取文件大小

    本文介紹了使用os.stat()和os.path.getsize()函數(shù)獲取文件大小,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-01-01
  • Django視圖函數(shù)的具體使用

    Django視圖函數(shù)的具體使用

    這篇文章主要介紹了Django視圖函數(shù)的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Pytorch:Conv2d卷積前后尺寸詳解

    Pytorch:Conv2d卷積前后尺寸詳解

    這篇文章主要介紹了Pytorch:Conv2d卷積前后尺寸,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 如何實(shí)現(xiàn)在pycharm中將.ui文件轉(zhuǎn)化為.py文件

    如何實(shí)現(xiàn)在pycharm中將.ui文件轉(zhuǎn)化為.py文件

    這篇文章主要介紹了如何實(shí)現(xiàn)在pycharm中將.ui文件轉(zhuǎn)化為.py文件,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-06-06
  • 分享10個(gè)拿來(lái)即用的Python自動(dòng)化腳本

    分享10個(gè)拿來(lái)即用的Python自動(dòng)化腳本

    這篇文章主要來(lái)和大家分享10個(gè)拿來(lái)即用的Python自動(dòng)化腳本,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • Python3 ffmpeg視頻轉(zhuǎn)換工具使用方法解析

    Python3 ffmpeg視頻轉(zhuǎn)換工具使用方法解析

    這篇文章主要介紹了Python3 ffmpeg視頻轉(zhuǎn)換工具使用方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • python 如何實(shí)現(xiàn)遺傳算法

    python 如何實(shí)現(xiàn)遺傳算法

    這篇文章主要介紹了python 如何實(shí)現(xiàn)遺傳算法,幫助大家更好的利用python進(jìn)行數(shù)據(jù)分析、處理,感興趣的朋友可以了解下
    2020-09-09
  • python實(shí)現(xiàn)數(shù)據(jù)挖掘中分箱的示例代碼

    python實(shí)現(xiàn)數(shù)據(jù)挖掘中分箱的示例代碼

    數(shù)據(jù)分箱(英語(yǔ):Data?binning)是一種數(shù)據(jù)預(yù)處理方法,用于最大限度地減少小觀測(cè)誤差的影響,本文主要為大家介紹了python實(shí)現(xiàn)數(shù)據(jù)分箱的相關(guān)知識(shí),感興趣的可以了解下
    2024-01-01
  • jupyter中如何打開(kāi).ipynb文件

    jupyter中如何打開(kāi).ipynb文件

    這篇文章主要介紹了jupyter中如何打開(kāi).ipynb文件問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Ubuntu中配置TensorFlow使用環(huán)境的方法

    Ubuntu中配置TensorFlow使用環(huán)境的方法

    這篇文章主要介紹了Ubuntu中配置TensorFlow使用環(huán)境的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04

最新評(píng)論

穆棱市| 孟津县| 巍山| 珠海市| 黄龙县| 芜湖市| 宜昌市| 科尔| 香港 | 花垣县| 乌拉特中旗| 乐平市| 定陶县| 马龙县| 喀什市| 武隆县| 浦县| 荆州市| 临朐县| 闸北区| 嘉义县| 库尔勒市| 文安县| 耿马| 璧山县| 嘉荫县| 德钦县| 连云港市| 板桥市| 滕州市| 乐清市| 平昌县| 宁海县| 化州市| 喀喇| 湘潭县| 抚顺市| 蒲江县| 河北区| 讷河市| 天等县|