[[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
==== 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