[[oktatas:programozás:python:wxpython_gui|< wxPython GUI]] ====== Glade MVC ====== * **Szerző:** Sallai András * Copyright (c) Sallai András, 2020, 2021 * Licenc: [[https://creativecommons.org/licenses/by-sa/4.0/|CC Attribution-Share Alike 4.0 International]] * Web: https://szit.hu ===== Külön osztályba rendezés ===== Végezzük el a következő beállításokat: * A **Tree** ablakban válasszuk ki az "Application" gyökércsomópontot. * A **Properties** ablakban * **Separate file for each class** rádiógombot jelöljük be. * A **Properties** ablakban, az "Application" fülön: * Az **Output path** mezőbe, ilyenkor egy könyvtár legyen beállítva. * A könyvtárnak léteznie kell. * A könyvtár lehet (.) pont is, vagyis az aktuális könyvtár * Példa 1: . * Példa 2: views * A **Tree** ablakban * Válasszuk ki a kívánt komponenst, amit külön szeretnénk tenni. * A **Properties** ablakban, kikeressük a **Class** mezőt. * Írjuk át a kívánt névre. Ezek után, ha kódot generálunk, külön állományokba fog minden osztályt kerülni, aminek a nevét átírtunk. ===== A program indítása ===== A program mindig a wx.App osztályból származtatott objektummal indul. Alapesetben, ez egy app.py nevű fájlban található. MVC esetén a wxGalde segítségével a nézetfájlokat egy views könyvtárba szokás generálni. Viszont itt fog létrejönni az app.py állomány is, ami probléma a controllers models és views könyvtárak elérése miatt. Az app.py fájlt a views könyvtárral egy szintre kell tenni. Ilyen esetben az app.py állomány létrehozását magunknak kell megoldani. Ehhez a következőket tegyük: * Jelöljük ki az "Application" a fanézetben. * A "Properties" ablakban, "Application" fül. * Vegyük ki a pipát a Name és Class feliratok mellett: * Name [ ] * Class [ ] projekt01/ `-src/ |-controllers/ |-models/ |-views/ `-app.py Az app.py fájlból hívjuk a controllers könyvtárban található MainController-t. A MainController-ben példányosítjuk a models könyvtárban található MainModel osztályt, a views könyvtárban található MainFrame osztályt. Mivel az alkalmazás az src könyvtárból indul, ezért a controllers könyvtárban található kontrollerosztályokban látszanak a többi könyvtárak osztályai. ===== A program.wxg fájl helye ===== A .wxg fájl lehet a controllers, models és views könyvtárak mellet, de elhelyezhetjük a views könyvtárban is tetszés szerint. * Ha views könyvtárba tettük, az "Output path" értéke legyen egy pont (.). * Ha views könyvtár mellé tettük, akkor az "Output path" értéke legyen "views". projekt01/ `-src/ |-controllers/ |-models/ |-views/ `-projekt01.wxg projekt01/ `-src/ |-controllers/ |-models/ `-views/ `-projekt01.wxg ===== Általános példa ===== ==== UML diagram ==== {{:oktatas:programozas:python:wxpython_gui:wxgalde_mvc.png|}} ==== Könyvtárszerkezet ==== projekt01/ `-src/ |-controllers/ | `-main_controller.py |-models/ | `-main_model.py |-views/ | `-MainFrame.py | `-projekt01.wxg `-projekt01.py A **views** könyvtár állományait a **wxGlade programmal** készítjük, amíg a többit tetszőleges kódszerkesztővel. A wxGalde használata során megkötés, hogy nem lehet különböző neve az osztálynak és a fájlnak. Ezért MainFrame.py nevű fájlt hozunk létre, MainFrame osztállyal. ==== Kód ==== import wx from controllers.main_controller import MainController class Projekt01App(wx.App): def OnInit(self): MainController() return True app = Projekt01App(False) app.MainLoop() import wx from views.MainFrame import MainFrame from models.main_model import MainModel class MainController: def __init__(self): main_frame = MainFrame(None, wx.ID_ANY, "") main_frame.Show() class MainModel: def get_name(): return 'János' # -*- coding: UTF-8 -*- # # generated by wxGlade 1.0.0a9 on Sat Nov 28 23:23:19 2020 # import wx # begin wxGlade: dependencies # end wxGlade # begin wxGlade: extracode # end wxGlade class MainFrame(wx.Frame): def __init__(self, *args, **kwds): # begin wxGlade: MainFrame.__init__ kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) self.SetSize((400, 300)) self.SetTitle("frame") self.panel_1 = wx.Panel(self, wx.ID_ANY) sizer_1 = wx.BoxSizer(wx.VERTICAL) self.button_1 = wx.Button(self.panel_1, wx.ID_ANY, "button_1") sizer_1.Add(self.button_1, 0, wx.ALL, 5) self.panel_1.SetSizer(sizer_1) self.Layout() # end wxGlade # end of class MainFrame 400, 300 frame wxVERTICAL 5 wxALL ==== Minta ==== {{:oktatas:programozas:python:wxpython_gui:wxglade_gomb_ablakon_pelda.png|}} ===== MVC wx.App osztállyal ===== Ebben a példában, meghagytuk az App osztály generálást. Így az app osztály példánya nem egy kontrollert hív, hanem előbb MainFrame osztályt. {{:oktatas:programozas:python:wxpython_gui:tarol.png|}} Az osztály nevét így adjuk meg: views.LeftPanel A nevet a views. szóval vezettük be. A views egy könyvtár lesz, amit a wxGlade automatikusan létrehoz. Az alkalmazásosztályt ne tegyük a views könyvtárba, mert felesleges, annak helye az src könyvtár marad. Az Output path src legyen. Nem szükséges elé pont és per, vagy utána / karakter. * Properties > Common > Class: view.LeftPanel * Properties > Output path: src Így következő szerkezetet kapjuk: tarol/ |--src/ |--views/ | |--LeftPanel.py | `--MainFrame.py `--app.py Így elkészíthetjük az src könyvtárban a controllers és models könyvtárakat. ==== Kontroller és modell hozzáadása ==== tarol/ `--src/ |--controllers/ | `--LeftController.py |--models/ | `--LeftModel.py |--views/ | |--LeftPanel.py | `--MainFrame.py `--app.py ==== Eseménykezelés ==== Az eseménykezelést, most **ne** bízzuk a wxGlade-re, azt mi fogjuk megvalósítani a LeftController.py állományban. ==== Forrás ==== Az app.py fájlhoz nem nyúlunk. Ezt minden esetben újragenerálja a wxGlade. #!/usr/bin/env python # -*- coding: UTF-8 -*- # # generated by wxGlade 0.9.6 on Tue Aug 11 01:18:08 2020 # # This is an automatically generated file. # Manual changes will be overwritten without warning! import wx from views.MainFrame import MainFrame class TarolApp(wx.App): def OnInit(self): self.frame = MainFrame(None, wx.ID_ANY, "") self.SetTopWindow(self.frame) self.frame.Show() return True # end of class TarolApp if __name__ == "__main__": tarol = TarolApp(0) tarol.MainLoop() Írjunk egy LeftModel osztályt, amelnyek van egy szoveg adattagja, és egy setValue() metódusa: class LeftModel: def __init__(self): self.szoveg = None def setValue(self, szoveg): self.szoveg = szoveg print("Model ok") Írjunk egy LeftController osztályt: import wx from views.LeftPanel import LeftPanel from models.LeftModel import LeftModel class LeftController: def __init__(self, panel: LeftPanel): self.panel = panel self.panel.Bind(wx.EVT_BUTTON, self.onClickGoButton, self.panel.goButton) self.leftModel = LeftModel() def onClickGoButton(self, event): valtozo = self.panel.text1.GetValue() self.leftModel.setValue(valtozo) Legyen egy Panel: # -*- coding: UTF-8 -*- # # generated by wxGlade 0.9.6 on Tue Aug 11 01:26:08 2020 # import wx # begin wxGlade: dependencies # end wxGlade # begin wxGlade: extracode # end wxGlade class LeftPanel(wx.Panel): def __init__(self, *args, **kwds): # begin wxGlade: LeftPanel.__init__ kwds["style"] = kwds.get("style", 0) wx.Panel.__init__(self, *args, **kwds) self.text1 = wx.TextCtrl(self, wx.ID_ANY, "") self.goButton = wx.Button(self, wx.ID_ANY, "Mehet") self.__set_properties() self.__do_layout() # end wxGlade def __set_properties(self): # begin wxGlade: LeftPanel.__set_properties pass # end wxGlade def __do_layout(self): # begin wxGlade: LeftPanel.__do_layout sizer_2 = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, u"Tevékenységek"), wx.VERTICAL) sizer_2.Add(self.text1, 0, wx.ALL | wx.EXPAND, 6) sizer_2.Add(self.goButton, 0, wx.ALL | wx.EXPAND, 6) self.SetSizer(sizer_2) sizer_2.Fit(self) self.Layout() # end wxGlade # end of class LeftPanel Hívjuk meg a MainFrame osztályban a LeftController-t. # -*- coding: UTF-8 -*- # # generated by wxGlade 0.9.6 on Mon Aug 10 18:01:18 2020 # import wx from controllers.LeftController import LeftController # begin wxGlade: dependencies from views.LeftPanel import LeftPanel # end wxGlade # begin wxGlade: extracode # end wxGlade class MainFrame(wx.Frame): def __init__(self, *args, **kwds): # begin wxGlade: MainFrame.__init__ kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, *args, **kwds) self.SetSize((400, 300)) self.leftPanel = LeftPanel(self, wx.ID_ANY) self.__set_properties() self.__do_layout() # end wxGlade LeftController(self.leftPanel) def __set_properties(self): # begin wxGlade: MainFrame.__set_properties self.SetTitle("frame") # end wxGlade def __do_layout(self): # begin wxGlade: MainFrame.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_1.Add(self.leftPanel, 1, wx.ALL | wx.EXPAND, 6) self.SetSizer(sizer_1) self.Layout() # end wxGlade # end of class MainFrame