Hallo, ich möchte ein Programm mit einer GUI mit wxPython schreiben. Ich habe verschiedenen Klassen definiert, in denen die Daten gespeichert werden sollen (diese werden dann an andere Funktionsklassen übergeben und berechnen das Ergebnis. Das Backend ist fertig.). Die GUI habe ich als wx.Notebook konzipiert. Nun frage ich mich, wie bzw. wo ich sie Daten der Klassen speichern soll. Die Daten sollen z.b. mit einem wx.TextCtrl auf einem Panel eingegeben werden und bei einem Event (Button, Change ...) kann ich die Eingabe des TextCtrl dann einer Instanz der Klasse übergeben. Die Frage ist, wo "deklariere" ich diese? Quick und Dirty wäre natürlich das global zu machen. Alternativ könnte ich mir vorstellen das z.B. an den Frame oder das Panel anzuhängen. Dann muss man aber z.B. über GetParent() darauf zugreifen und wenn man später an der Struktur der GUI was ändert, dann muss man auch alles überarbeiten. Gibt es bessere Möglichkeiten?
MVC ist bekannt? Die Klassendeklaration gehören ins model, der controller zieht die Daten aus der view, sobald das entsprechende Ereignis eingetreten ist, und setzt sie zu einer Instanz deiner Datenklasse zusammen. Dann wird sie dort entweder weiterverarbeitet oder geht zwecks Persistenz ins model. Da die Geschichte nun leider schon halb fertig gestrickt ist, könnte es etwas fummelig werden, diese Struktur nachträglich herzustellen. Das ist die Folge davon, sich über solche Dinge nicht Gedanken zu machen, bevor auch nur eine einzige Zeile Code geschrieben ist. Keine Panik, nächstes mal machst du es besser. MaWin schrieb: > Code zeigen Hör auf, die Leute zu nerven. Wozu soll das auf diesem Abstraktionsniveau gut sein?
1 | #!/usr/bin/env python3
|
2 | # -*- coding: utf-8 -*-
|
3 | """
|
4 | @author:
|
5 | """
|
6 | |
7 | import wx |
8 | import wx.dataview as dv |
9 | import os |
10 | import sys |
11 | from scr.entry import * |
12 | |
13 | |
14 | _ = wx.GetTranslation |
15 | |
16 | |
17 | def getNextImageID(count): |
18 | imID = 0 |
19 | while True: |
20 | yield imID |
21 | imID += 1 |
22 | if imID == count: |
23 | imID = 0 |
24 | class MyDisplaySettings(): |
25 | def __init__(self): |
26 | '''Settings for various Displays |
27 |
|
28 | ToolSize - Symboly of ToolBar
|
29 | FrameSize - Main Window
|
30 | BookSize - Symbols of Toolbook
|
31 | ''' |
32 | |
33 | #get horizontal resulution of smalest Display
|
34 | MinHorSize = 10000 |
35 | Displays = (wx.Display(i) for i in range(wx.Display.GetCount())) |
36 | Sizes = [Display.GetGeometry().GetSize() for Display in Displays] |
37 | for size in Sizes: |
38 | if size[0] < MinHorSize: |
39 | MinHorSize = size[0] |
40 | #MinHorSize = 1000
|
41 | if MinHorSize < 1024: |
42 | self.ToolSize = (24,24) |
43 | self.FrameSize = (800,600) |
44 | self.BookSize = (36,36) |
45 | else: |
46 | self.ToolSize = (48,48) |
47 | self.FrameSize = (1440,900) |
48 | self.BookSize = (72,72) |
49 | self.ProjectParameterColumn = int((self.FrameSize[0]-self.BookSize[0])/4) |
50 | |
51 | class MyApp(wx.App): |
52 | locale = None |
53 | |
54 | def OnInit(self): |
55 | print('Running wxPython ' + wx.version()) |
56 | # Set Current directory to the one containing this file
|
57 | os.chdir(os.path.dirname(os.path.abspath(__file__))) |
58 | self.SetAppName('Helical_pile_GUI') |
59 | self.InitLanguage() |
60 | # Create the main window
|
61 | myFrame = MyFrame() |
62 | self.SetTopWindow(myFrame) |
63 | myFrame.Show() |
64 | return True |
65 | |
66 | |
67 | def InitLanguage(self): |
68 | '''Load language settings''' |
69 | #https://wiki.wxpython.org/How%20to%20use%20the%20Internationalization%20-%20i18n%20%28Phoenix%29?action=AttachFile&do=view&target=source.zip
|
70 | langsAvail = { |
71 | "System default" : wx.LANGUAGE_DEFAULT, |
72 | "English" : wx.LANGUAGE_ENGLISH, |
73 | "German" : wx.LANGUAGE_GERMAN, |
74 | }
|
75 | lang = wx.LANGUAGE_DEFAULT |
76 | wx.Locale.AddCatalogLookupPathPrefix("locale") |
77 | self.locale = wx.Locale() |
78 | if not self.locale.Init(lang): |
79 | wx.LogWarning("This language is not supported by the system.") |
80 | if not self.locale.AddCatalog("GUI"): |
81 | wx.LogError("Couldn't find/load the 'GUI' catalog for locale '" + self.locale.GetCanonicalName() + "'.") |
82 | |
83 | class MyFrame(wx.Frame): |
84 | def __init__(self): |
85 | '''Main Frame with Toolbar, Statusbar and Toolbook''' |
86 | DS = MyDisplaySettings() |
87 | super().__init__(None, title=_('GUI'), size = DS.FrameSize) |
88 | self.CreateStatusBar() |
89 | self.MakeToolBar() |
90 | panel = wx.Panel(self) |
91 | notebook = MyToolbook(panel) |
92 | sizer = wx.BoxSizer(wx.VERTICAL) |
93 | sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5) |
94 | panel.SetSizer(sizer) |
95 | self.Layout() |
96 | self.Show() |
97 | def MakeToolBar(self): |
98 | '''Init Toolbar with Buttons''' |
99 | DS = MyDisplaySettings() |
100 | myToolBar = self.CreateToolBar(wx.TB_TEXT) |
101 | # New Button to start new Project
|
102 | new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, DS.ToolSize) |
103 | self.ButtonNew = myToolBar.AddTool(10, "New", new_bmp, wx.NullBitmap, wx.ITEM_NORMAL, "New", "Long help for 'New'", None) |
104 | self.Bind(wx.EVT_TOOL, self.OnToolClick, id=10) |
105 | self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolClick, id=10) |
106 | #print(self.ButtonNew.GetId())
|
107 | #Open Button
|
108 | open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, DS.ToolSize) |
109 | |
110 | def OnToolClick(self,event): |
111 | print('Click') |
112 | |
113 | class MyMainPanel(wx.Panel): |
114 | def __init__(self, parent): |
115 | super().__init__(parent) |
116 | myToolbook = MyToolbook(self) |
117 | |
118 | class MyToolbook(wx.Toolbook): |
119 | def __init__(self, parent): |
120 | super().__init__(parent, style = wx.BK_LEFT) |
121 | self.DS = MyDisplaySettings() |
122 | |
123 | # make an image list using ./img folder
|
124 | il = wx.ImageList(self.DS.BookSize[0], self.DS.BookSize[1]) |
125 | bmp = self.scale_bitmap(wx.Bitmap('./img/prj.png', wx.BITMAP_TYPE_PNG)) |
126 | il.Add(bmp) |
127 | bmp = self.scale_bitmap(wx.Bitmap('./img/soil.png', wx.BITMAP_TYPE_PNG)) |
128 | il.Add(bmp) |
129 | bmp = self.scale_bitmap(wx.Bitmap('./img/strat.png', wx.BITMAP_TYPE_PNG)) |
130 | il.Add(bmp) |
131 | bmp = self.scale_bitmap(wx.Bitmap('./img/geom.png', wx.BITMAP_TYPE_PNG)) |
132 | il.Add(bmp) |
133 | self.AssignImageList(il) |
134 | |
135 | panel = MyToolbookPanelMaster(self) |
136 | PanelProject = MyToolbookProject(self) |
137 | self.AddPage(PanelProject,_('Project'), imageId=0) |
138 | self.AddPage(panel,_('Soil'), imageId=1) |
139 | self.AddPage(panel,_('Layering'), imageId=2) |
140 | self.AddPage(panel,_('Geometry'), imageId=3) |
141 | |
142 | |
143 | def scale_bitmap(self, bitmap): |
144 | image = bitmap.ConvertToImage() |
145 | image = image.Scale(self.DS.BookSize[0], self.DS.BookSize[1], wx.IMAGE_QUALITY_HIGH) |
146 | result = wx.Bitmap(image) |
147 | return result |
148 | |
149 | class MyToolbookPanelMaster(wx.Panel): |
150 | def __init__(self, parent): |
151 | super().__init__(parent) |
152 | self.SetBackgroundColour(wx.WHITE) |
153 | |
154 | class MyToolbookProject(MyToolbookPanelMaster): |
155 | def __init__(self, parent): |
156 | super().__init__(parent) |
157 | DS = MyDisplaySettings() |
158 | BS = wx.BoxSizer(wx.VERTICAL) |
159 | |
160 | |
161 | self.listctrl = listctrl = dv.DataViewListCtrl(self, style = dv.DV_ROW_LINES | dv.DV_VERT_RULES | dv.DV_MULTIPLE | dv.DV_HORIZ_RULES | dv.DV_VARIABLE_LINE_HEIGHT) |
162 | |
163 | |
164 | listctrl.AppendTextColumn(_("Parameter"), width = DS.ProjectParameterColumn) #flags=dv.DATAVIEW_COL_RESIZABLE |
165 | listctrl.AppendTextColumn(_("Value"), width = DS.ProjectParameterColumn*2, mode=dv.DATAVIEW_CELL_EDITABLE) |
166 | |
167 | self.data = data = Project() |
168 | data.Name = "Spannendes Projekt" |
169 | data.Location = "an einem geheimen Ort" |
170 | data.Description = "Eine spannende Konstruktion zur zur Ausführung toller Sachen" |
171 | |
172 | self.datalist = [[_('Name'), data.Name], |
173 | [_('Location'), data.Location], |
174 | [_('Description'), data.Description]] |
175 | |
176 | for Item in self.datalist: |
177 | listctrl.AppendItem(Item) |
178 | |
179 | self.Bind(dv.EVT_DATAVIEW_ITEM_EDITING_DONE, self.edit_done, listctrl) |
180 | BS.Add(listctrl, 1, wx.EXPAND, 20) #wx.EXPAND wx.ALL wx.SHAPED |
181 | self.SetSizer(BS) |
182 | |
183 | def edit_done(self,event): |
184 | print(self.listctrl.GetSelectedRow()][1]) |
185 | #Hier die Daten aus der listctrl und an Project übergeben
|
186 | #aber wo soll man Project speichern um es später z.b. auf
|
187 | #Toolbook-Page Geometry zu verwenden?
|
188 | |
189 | if __name__ == '__main__': |
190 | app = MyApp() |
191 | app.MainLoop() |
Ich hänge bei
1 | class MyToolbookProject |
bzw. dort bei
1 | def edit_done(self,event): |
Die Klasse Project ist dabei das Trivialste und hat nur die 3 Member. Aber andere Klassen sind da etwas komplizierter gestrickt.
Später soll natürlich auch ein Speicher-Button in die Toolbar, womit dann die ganzen Daten der Objekte (also Project, Soil ...) auf der Festplatte gespeichert werden können.
Karl schrieb: > Alternativ könnte ich mir > vorstellen das z.B. an den Frame oder das Panel anzuhängen. Dann muss > man aber z.B. über GetParent() darauf zugreifen Nicht unbedingt. Klassen, die Zugriff auf die Datenhaltung benötigen können dies auf mehrere Arten bekommen: - Wie du schon sagtest indirekt über die GUI-Hierarchie. - Man kann bei der Erstellung der Klassen bereits eine Referenz auf die Datenhaltung mitgeben. - Jede Klasse kann ihren Parent fragen, ob dieser eine Referenz auf die Daten hat. Wenn nicht, wird die Anfrage an den Parent weitergereicht. Bis man irgendwann oben angekommen ist, bei einer Klasse, die die Anfrage befriedigen kann. Das ist im Prinzip das umgekehrte Design des vorherigen Punkts. Bei Änderung der Daten oder Ablagestruktur ändert sich nichts an den weiterreichenden Schichten. - Global. Ja, kann man machen. Wenn man absolut ausschließen kann, dass man die Hierarchie mehrfach instanziieren können muss. Aber wäre jetzt auch nicht meine erste Lösung.
Heiner schrieb: > MVC ist bekannt? War mir nicht bekannt, ich kannte nur Entity-control-boundary. Heiner schrieb: > Da die Geschichte nun leider schon halb fertig gestrickt ist, könnte es > etwas fummelig werden, diese Struktur nachträglich herzustellen. Ist noch weit weg von halb fertig. Ich denke es lässt sich relativ einfach noch ergänzen. Heiner schrieb: > MaWin schrieb: >> Code zeigen > > Hör auf, die Leute zu nerven. Wozu soll das auf diesem > Abstraktionsniveau gut sein? Ich hatte beim erstellen schon überlegt, den Code mitzugeben, dann aber mich restmal für die "Abstraktion" entschieden. Ich kann MaWins wünsch nachvollziehen. Ich werde eine Controllerklasse schreiben und die als Referenz mitgeben. Auf das implementieren eines "Beobachter" werde ich aber wohl verzichten. Prinzipiell wäre es sicher Toll, die Software am Reißbrett zu entwerfen und dann umzusetzen, abe ich bin kein Informatiker und das Gesamtprojekt ist doch ehr überschaubar.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.