Geçmişte bu konu hakkında çok şey okudum ve Bob Amca'nın bu gibi ilginç konuşmalarını izledim . Yine de, masaüstü uygulamalarımı düzgün bir şekilde tasarlamak ve hangisinin UI tarafında ve hangilerinin mantık tarafında olması gerektiğini ayırt etmek oldukça zor buluyorum .
İyi uygulamaların çok kısa bir özeti böyle bir şeydir. Mantığınızı kullanıcı arayüzünden ayrıştırılmış olarak tasarlamalısınız, böylece hangi tür arka uç / kullanıcı arayüzü çerçevesi olursa olsun kütüphanenizi (teorik olarak) kullanabilirsiniz. Bunun anlamı, temel olarak UI'nin mümkün olduğunca kukla olması ve ağır işlemin mantık tarafında yapılmasıdır. Aksi takdirde, güzel kütüphanemi bir konsol uygulaması, bir web uygulaması veya bir masaüstü uygulamasıyla tam anlamıyla kullanabilirim.
Ayrıca, Bob Amca, hangi teknolojinin kullanılacağına dair size çok fazla fayda (iyi arayüzler) sunacak farklı tartışmalar önerir, bu erteleme kavramı, kulağa harika gelen ama yine de zor olan, son derece ayrıştırılmış iyi test edilmiş varlıklara sahip olmanızı sağlar.
Bu sorunun, tüm internette ve ayrıca tonlarca iyi kitapta birçok kez tartışılan oldukça geniş bir soru olduğunu biliyorum. İyi bir şey elde etmek için pyqt üzerinde MCV kullanmaya çalışan çok az kukla bir örnek yayınlayacağım:
import sys
import os
import random
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
random.seed(1)
class Model(QtCore.QObject):
item_added = QtCore.pyqtSignal(int)
item_removed = QtCore.pyqtSignal(int)
def __init__(self):
super().__init__()
self.items = {}
def add_item(self):
guid = random.randint(0, 10000)
new_item = {
"pos": [random.randint(50, 100), random.randint(50, 100)]
}
self.items[guid] = new_item
self.item_added.emit(guid)
def remove_item(self):
list_keys = list(self.items.keys())
if len(list_keys) == 0:
self.item_removed.emit(-1)
return
guid = random.choice(list_keys)
self.item_removed.emit(guid)
del self.items[guid]
class View1():
def __init__(self, main_window):
self.main_window = main_window
view = QtWidgets.QGraphicsView()
self.scene = QtWidgets.QGraphicsScene(None)
self.scene.addText("Hello, world!")
view.setScene(self.scene)
view.setStyleSheet("background-color: red;")
main_window.setCentralWidget(view)
class View2():
add_item = QtCore.pyqtSignal(int)
remove_item = QtCore.pyqtSignal(int)
def __init__(self, main_window):
self.main_window = main_window
button_add = QtWidgets.QPushButton("Add")
button_remove = QtWidgets.QPushButton("Remove")
vbl = QtWidgets.QVBoxLayout()
vbl.addWidget(button_add)
vbl.addWidget(button_remove)
view = QtWidgets.QWidget()
view.setLayout(vbl)
view_dock = QtWidgets.QDockWidget('View2', main_window)
view_dock.setWidget(view)
main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, view_dock)
model = main_window.model
button_add.clicked.connect(model.add_item)
button_remove.clicked.connect(model.remove_item)
class Controller():
def __init__(self, main_window):
self.main_window = main_window
def on_item_added(self, guid):
view1 = self.main_window.view1
model = self.main_window.model
print("item guid={0} added".format(guid))
item = model.items[guid]
x, y = item["pos"]
graphics_item = QtWidgets.QGraphicsEllipseItem(x, y, 60, 40)
item["graphics_item"] = graphics_item
view1.scene.addItem(graphics_item)
def on_item_removed(self, guid):
if guid < 0:
print("global cache of items is empty")
else:
view1 = self.main_window.view1
model = self.main_window.model
item = model.items[guid]
x, y = item["pos"]
graphics_item = item["graphics_item"]
view1.scene.removeItem(graphics_item)
print("item guid={0} removed".format(guid))
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# (M)odel ===> Model/Library containing should be UI agnostic, right now it's not
self.model = Model()
# (V)iew ===> Coupled to UI
self.view1 = View1(self)
self.view2 = View2(self)
# (C)ontroller ==> Coupled to UI
self.controller = Controller(self)
self.attach_views_to_model()
def attach_views_to_model(self):
self.model.item_added.connect(self.controller.on_item_added)
self.model.item_removed.connect(self.controller.on_item_removed)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
form = MainWindow()
form.setMinimumSize(800, 600)
form.show()
sys.exit(app.exec_())
Yukarıdaki snippet çok sayıda kusur içeriyor, daha açık olan model UI çerçevesine (QObject, pyqt sinyalleri) bağlanıyor. Örnek gerçekten kukla ve tek bir QMainWindow kullanarak birkaç satır kod olabilir biliyorum ama amacım daha büyük bir pyqt uygulaması düzgün bir şekilde nasıl mimar anlamak için.
SORU
İyi genel uygulamaları takip ederek MVC kullanarak büyük bir PyQt uygulamasını nasıl düzgün şekilde tasarlarsınız?
REFERANSLAR
Burada buna benzer bir soru yaptım