]>
Commit | Line | Data |
---|---|---|
1 | #---------------------------------------------------------------------- | |
2 | # Name: wxPython.lib.dialogs | |
3 | # Purpose: wxScrolledMessageDialog, wxMultipleChoiceDialog and | |
4 | # function wrappers for the common dialogs by Kevin Altis. | |
5 | # | |
6 | # Author: Various | |
7 | # | |
8 | # Created: 3-January-2002 | |
9 | # RCS-ID: $Id$ | |
10 | # Copyright: (c) 2002 by Total Control Software | |
11 | # Licence: wxWindows license | |
12 | #---------------------------------------------------------------------- | |
13 | # 12/01/2003 - Jeff Grimmett (grimmtooth@softhome.net) | |
14 | # | |
15 | # o Updated for 2.5 compatability. | |
16 | # | |
17 | # 12/18/2003 - Jeff Grimmett (grimmtooth@softhome.net) | |
18 | # | |
19 | # o wxScrolledMessageDialog -> ScrolledMessageDialog | |
20 | # o wxMultipleChoiceDialog -> MultipleChoiceDialog | |
21 | # | |
22 | ||
23 | import wx | |
24 | import layoutf | |
25 | ||
26 | #---------------------------------------------------------------------- | |
27 | ||
28 | class ScrolledMessageDialog(wx.Dialog): | |
29 | def __init__(self, parent, msg, caption, pos = wx.DefaultPosition, | |
30 | size = (500,300)): | |
31 | wx.Dialog.__init__(self, parent, -1, caption, pos, size) | |
32 | x, y = pos | |
33 | if x == -1 and y == -1: | |
34 | self.CenterOnScreen(wx.BOTH) | |
35 | ||
36 | text = wx.TextCtrl(self, -1, msg, wx.DefaultPosition, wx.DefaultSize, | |
37 | wx.TE_MULTILINE | wx.TE_READONLY) | |
38 | ||
39 | ok = wx.Button(self, wx.ID_OK, "OK") | |
40 | lc = layoutf.Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self,ok)) | |
41 | text.SetConstraints(lc) | |
42 | ||
43 | lc = layoutf.Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self,)) | |
44 | ok.SetConstraints(lc) | |
45 | self.SetAutoLayout(1) | |
46 | self.Layout() | |
47 | ||
48 | ||
49 | class MultipleChoiceDialog(wx.Dialog): | |
50 | def __init__(self, parent, msg, title, lst, pos = wx.DefaultPosition, | |
51 | size = (200,200), style = wx.DEFAULT_DIALOG_STYLE): | |
52 | wx.Dialog.__init__(self, parent, -1, title, pos, size, style) | |
53 | ||
54 | x, y = pos | |
55 | if x == -1 and y == -1: | |
56 | self.CenterOnScreen(wx.BOTH) | |
57 | ||
58 | dc = wx.ClientDC(self) | |
59 | height = 0 | |
60 | for line in msg.splitlines(): | |
61 | height = height + dc.GetTextExtent(line)[1] + 2 | |
62 | ||
63 | stat = wx.StaticText(self, -1, msg) | |
64 | self.lbox = wx.ListBox(self, 100, wx.DefaultPosition, wx.DefaultSize, | |
65 | lst, wx.LB_MULTIPLE) | |
66 | ||
67 | ok = wx.Button(self, wx.ID_OK, "OK") | |
68 | cancel = wx.Button(self, wx.ID_CANCEL, "Cancel") | |
69 | lc = layoutf.Layoutf('t=t10#1;l=l5#1;r=r5#1;h!%d' % (height,), (self,)) | |
70 | stat.SetConstraints(lc) | |
71 | ||
72 | lc = layoutf.Layoutf('t=b10#2;l=l5#1;r=r5#1;b=t5#3', (self, stat, ok)) | |
73 | self.lbox.SetConstraints(lc) | |
74 | ||
75 | lc = layoutf.Layoutf('b=b5#1;x%w25#1;w!80;h!25', (self,)) | |
76 | ok.SetConstraints(lc) | |
77 | ||
78 | lc = layoutf.Layoutf('b=b5#1;x%w75#1;w!80;h!25', (self,)) | |
79 | cancel.SetConstraints(lc) | |
80 | ||
81 | self.SetAutoLayout(1) | |
82 | self.lst = lst | |
83 | self.Layout() | |
84 | ||
85 | def GetValue(self): | |
86 | return self.lbox.GetSelections() | |
87 | ||
88 | def GetValueString(self): | |
89 | sel = self.lbox.GetSelections() | |
90 | val = [] | |
91 | ||
92 | for i in sel: | |
93 | val.append(self.lst[i]) | |
94 | ||
95 | return tuple(val) | |
96 | ||
97 | ||
98 | #---------------------------------------------------------------------- | |
99 | """ | |
100 | function wrappers for wxPython system dialogs | |
101 | Author: Kevin Altis | |
102 | Date: 2003-1-2 | |
103 | Rev: 3 | |
104 | ||
105 | This is the third refactor of the PythonCard dialog.py module | |
106 | for inclusion in the main wxPython distribution. There are a number of | |
107 | design decisions and subsequent code refactoring to be done, so I'm | |
108 | releasing this just to get some feedback. | |
109 | ||
110 | rev 3: | |
111 | - result dictionary replaced by DialogResults class instance | |
112 | - should message arg be replaced with msg? most wxWindows dialogs | |
113 | seem to use the abbreviation? | |
114 | ||
115 | rev 2: | |
116 | - All dialog classes have been replaced by function wrappers | |
117 | - Changed arg lists to more closely match wxWindows docs and wxPython.lib.dialogs | |
118 | - changed 'returned' value to the actual button id the user clicked on | |
119 | - added a returnedString value for the string version of the return value | |
120 | - reworked colorDialog and fontDialog so you can pass in just a color or font | |
121 | for the most common usage case | |
122 | - probably need to use colour instead of color to match the English English | |
123 | spelling in wxWindows (sigh) | |
124 | - I still think we could lose the parent arg and just always use None | |
125 | """ | |
126 | ||
127 | class DialogResults: | |
128 | def __init__(self, returned): | |
129 | self.returned = returned | |
130 | self.accepted = returned in (wx.ID_OK, wx.ID_YES) | |
131 | self.returnedString = returnedString(returned) | |
132 | ||
133 | def __repr__(self): | |
134 | return str(self.__dict__) | |
135 | ||
136 | def returnedString(ret): | |
137 | if ret == wx.ID_OK: | |
138 | return "Ok" | |
139 | elif ret == wx.ID_CANCEL: | |
140 | return "Cancel" | |
141 | elif ret == wx.ID_YES: | |
142 | return "Yes" | |
143 | elif ret == wx.ID_NO: | |
144 | return "No" | |
145 | ||
146 | ||
147 | ## findDialog was created before wxPython got a Find/Replace dialog | |
148 | ## but it may be instructive as to how a function wrapper can | |
149 | ## be added for your own custom dialogs | |
150 | ## this dialog is always modal, while wxFindReplaceDialog is | |
151 | ## modeless and so doesn't lend itself to a function wrapper | |
152 | def findDialog(parent=None, searchText='', wholeWordsOnly=0, caseSensitive=0): | |
153 | dlg = wx.Dialog(parent, -1, "Find", wx.DefaultPosition, (370, 120)) | |
154 | ||
155 | wx.StaticText(dlg, -1, 'Find what:', (7, 10)) | |
156 | wSearchText = wx.TextCtrl(dlg, -1, searchText, (70, 7), (195, -1)) | |
157 | wSearchText.SetValue(searchText) | |
158 | wx.wxButton(dlg, wx.ID_OK, "Find Next", (280, 5), wx.DefaultSize).SetDefault() | |
159 | wx.wxButton(dlg, wx.ID_CANCEL, "Cancel", (280, 35), wx.DefaultSize) | |
160 | wWholeWord = wx.CheckBox(dlg, -1, 'Match whole word only', | |
161 | (7, 35), wx.DefaultSize, wx.NO_BORDER) | |
162 | ||
163 | if wholeWordsOnly: | |
164 | wWholeWord.SetValue(1) | |
165 | ||
166 | wCase = wx.CheckBox(dlg, -1, 'Match case', (7, 55), wx.DefaultSize, wx.NO_BORDER) | |
167 | ||
168 | if caseSensitive: | |
169 | wCase.SetValue(1) | |
170 | ||
171 | wSearchText.SetSelection(0, len(wSearchText.GetValue())) | |
172 | wSearchText.SetFocus() | |
173 | ||
174 | result = DialogResults(dlg.ShowModal()) | |
175 | result.text = wSearchText.GetValue() | |
176 | result.wholeword = wWholeWord.GetValue() | |
177 | result.casesensitive = wCase.GetValue() | |
178 | dlg.Destroy() | |
179 | return result | |
180 | ||
181 | ||
182 | def colorDialog(parent=None, colorData=None, color=None): | |
183 | if colorData: | |
184 | dialog = wx.ColourDialog(parent, colorData) | |
185 | else: | |
186 | dialog = wx.ColourDialog(parent) | |
187 | dialog.GetColourData().SetChooseFull(1) | |
188 | ||
189 | if color is not None: | |
190 | dialog.GetColourData().SetColour(color) | |
191 | ||
192 | result = DialogResults(dialog.ShowModal()) | |
193 | result.colorData = dialog.GetColourData() | |
194 | result.color = result.colorData.GetColour().Get() | |
195 | dialog.Destroy() | |
196 | return result | |
197 | ||
198 | ||
199 | ## it is easier to just duplicate the code than | |
200 | ## try and replace color with colour in the result | |
201 | def colourDialog(parent=None, colourData=None, colour=None): | |
202 | if colourData: | |
203 | dialog = wx.ColourDialog(parent, colourData) | |
204 | else: | |
205 | dialog = wx.ColourDialog(parent) | |
206 | dialog.GetColourData().SetChooseFull(1) | |
207 | ||
208 | if colour is not None: | |
209 | dialog.GetColourData().SetColour(color) | |
210 | ||
211 | result = DialogResults(dialog.ShowModal()) | |
212 | result.colourData = dialog.GetColourData() | |
213 | result.colour = result.colourData.GetColour().Get() | |
214 | dialog.Destroy() | |
215 | return result | |
216 | ||
217 | ||
218 | def fontDialog(parent=None, fontData=None, font=None): | |
219 | if fontData is None: | |
220 | fontData = wx.FontData() | |
221 | ||
222 | if font is not None: | |
223 | aFontData.SetInitialFont(font) | |
224 | ||
225 | dialog = wx.FontDialog(parent, fontData) | |
226 | result = DialogResults(dialog.ShowModal()) | |
227 | ||
228 | if result.accepted: | |
229 | fontData = dialog.GetFontData() | |
230 | result.fontData = fontData | |
231 | result.color = fontData.GetColour().Get() | |
232 | result.colour = result.color | |
233 | result.font = fontData.GetChosenFont() | |
234 | else: | |
235 | result.color = None | |
236 | result.colour = None | |
237 | result.font = None | |
238 | ||
239 | dialog.Destroy() | |
240 | return result | |
241 | ||
242 | ||
243 | def textEntryDialog(parent=None, message='', title='', defaultText='', | |
244 | style=wx.OK | wx.CANCEL): | |
245 | dialog = wx.TextEntryDialog(parent, message, title, defaultText, style) | |
246 | result = DialogResults(dialog.ShowModal()) | |
247 | result.text = dialog.GetValue() | |
248 | dialog.Destroy() | |
249 | return result | |
250 | ||
251 | ||
252 | def messageDialog(parent=None, message='', title='Message box', | |
253 | aStyle = wx.OK | wx.CANCEL | wx.CENTRE, | |
254 | pos=wx.DefaultPosition): | |
255 | dialog = wx.MessageDialog(parent, message, title, aStyle, pos) | |
256 | result = DialogResults(dialog.ShowModal()) | |
257 | dialog.Destroy() | |
258 | return result | |
259 | ||
260 | ||
261 | ## KEA: alerts are common, so I'm providing a class rather than | |
262 | ## requiring the user code to set up the right icons and buttons | |
263 | ## the with messageDialog function | |
264 | def alertDialog(parent=None, message='', title='Alert', pos=wx.DefaultPosition): | |
265 | return messageDialog(parent, message, title, wx.ICON_EXCLAMATION | wx.OK, pos) | |
266 | ||
267 | ||
268 | def scrolledMessageDialog(parent=None, message='', title='', pos=wx.DefaultPosition, | |
269 | size=(500,300)): | |
270 | ||
271 | dialog = ScrolledMessageDialog(parent, message, title, pos, size) | |
272 | result = DialogResults(dialog.ShowModal()) | |
273 | dialog.Destroy() | |
274 | return result | |
275 | ||
276 | ||
277 | def fileDialog(parent=None, title='Open', directory='', filename='', wildcard='*.*', | |
278 | style=wx.OPEN | wx.MULTIPLE): | |
279 | ||
280 | dialog = wx.FileDialog(parent, title, directory, filename, wildcard, style) | |
281 | result = DialogResults(dialog.ShowModal()) | |
282 | if result.accepted: | |
283 | result.paths = dialog.GetPaths() | |
284 | else: | |
285 | result.paths = None | |
286 | dialog.Destroy() | |
287 | return result | |
288 | ||
289 | ||
290 | ## openFileDialog and saveFileDialog are convenience functions | |
291 | ## they represent the most common usages of the fileDialog | |
292 | ## with the most common style options | |
293 | def openFileDialog(parent=None, title='Open', directory='', filename='', | |
294 | wildcard='All Files (*.*)|*.*', | |
295 | style=wx.OPEN | wx.MULTIPLE): | |
296 | return fileDialog(parent, title, directory, filename, wildcard, style) | |
297 | ||
298 | ||
299 | def saveFileDialog(parent=None, title='Save', directory='', filename='', | |
300 | wildcard='All Files (*.*)|*.*', | |
301 | style=wx.SAVE | wx.HIDE_READONLY | wx.OVERWRITE_PROMPT): | |
302 | return fileDialog(parent, title, directory, filename, wildcard, style) | |
303 | ||
304 | ||
305 | def dirDialog(parent=None, message='Choose a directory', path='', style=0, | |
306 | pos=wx.DefaultPosition, size=wx.DefaultSize): | |
307 | ||
308 | dialog = wx.DirDialog(parent, message, path, style, pos, size) | |
309 | result = DialogResults(dialog.ShowModal()) | |
310 | if result.accepted: | |
311 | result.path = dialog.GetPath() | |
312 | else: | |
313 | result.path = None | |
314 | dialog.Destroy() | |
315 | return result | |
316 | ||
317 | directoryDialog = dirDialog | |
318 | ||
319 | ||
320 | def singleChoiceDialog(parent=None, message='', title='', lst=[], | |
321 | style=wx.OK | wx.CANCEL | wx.CENTRE): | |
322 | dialog = wx.SingleChoiceDialog(parent, message, title, lst, style) | |
323 | result = DialogResults(dialog.ShowModal()) | |
324 | result.selection = dialog.GetStringSelection() | |
325 | dialog.Destroy() | |
326 | return result | |
327 | ||
328 | ||
329 | def multipleChoiceDialog(parent=None, message='', title='', lst=[], pos=wx.DefaultPosition, | |
330 | size=(200,200)): | |
331 | ||
332 | dialog = MultipleChoiceDialog(parent, message, title, lst, pos, size) | |
333 | result = DialogResults(dialog.ShowModal()) | |
334 | result.selection = dialog.GetValueString() | |
335 | dialog.Destroy() | |
336 | return result | |
337 | ||
338 | ||
339 | if __name__ == '__main__': | |
340 | class MyApp(wx.App): | |
341 | ||
342 | def OnInit(self): | |
343 | frame = wx.Frame(None, -1, "Dialogs", size=(400, 200)) | |
344 | panel = wx.Panel(frame, -1) | |
345 | self.panel = panel | |
346 | ||
347 | frame.Show(1) | |
348 | ||
349 | dialogNames = [ | |
350 | 'alertDialog', | |
351 | 'colorDialog', | |
352 | 'directoryDialog', | |
353 | 'fileDialog', | |
354 | 'findDialog', | |
355 | 'fontDialog', | |
356 | 'messageDialog', | |
357 | 'multipleChoiceDialog', | |
358 | 'openFileDialog', | |
359 | 'saveFileDialog', | |
360 | 'scrolledMessageDialog', | |
361 | 'singleChoiceDialog', | |
362 | 'textEntryDialog', | |
363 | ] | |
364 | self.nameList = wx.ListBox(panel, -1, (0, 0), (130, 180), dialogNames, style=wx.LB_SINGLE) | |
365 | self.Bind(wx.EVT_LISTBOX, self.OnNameListSelected, id=self.nameList.GetId()) | |
366 | ||
367 | tstyle = wx.TE_RICH2 | wx.TE_PROCESS_TAB | wx.TE_MULTILINE | |
368 | self.text1 = wx.TextCtrl(panel, -1, pos=(150, 0), size=(200, 180), style=tstyle) | |
369 | ||
370 | self.SetTopWindow(frame) | |
371 | ||
372 | return 1 | |
373 | ||
374 | def OnNameListSelected(self, evt): | |
375 | import pprint | |
376 | sel = evt.GetString() | |
377 | result = None | |
378 | if sel == 'alertDialog': | |
379 | result = alertDialog(message='Danger Will Robinson') | |
380 | elif sel == 'colorDialog': | |
381 | result = colorDialog() | |
382 | elif sel == 'directoryDialog': | |
383 | result = directoryDialog() | |
384 | elif sel == 'fileDialog': | |
385 | wildcard = "JPG files (*.jpg;*.jpeg)|*.jpeg;*.JPG;*.JPEG;*.jpg|GIF files (*.gif)|*.GIF;*.gif|All Files (*.*)|*.*" | |
386 | result = fileDialog(None, 'Open', '', '', wildcard) | |
387 | elif sel == 'findDialog': | |
388 | result = findDialog() | |
389 | elif sel == 'fontDialog': | |
390 | result = fontDialog() | |
391 | elif sel == 'messageDialog': | |
392 | result = messageDialog(None, 'Hello from Python and wxPython!', | |
393 | 'A Message Box', wx.wxOK | wx.wxICON_INFORMATION) | |
394 | #wx.wxYES_NO | wx.wxNO_DEFAULT | wx.wxCANCEL | wx.wxICON_INFORMATION) | |
395 | #result = messageDialog(None, 'message', 'title') | |
396 | elif sel == 'multipleChoiceDialog': | |
397 | result = multipleChoiceDialog(None, "message", "title", ['one', 'two', 'three']) | |
398 | elif sel == 'openFileDialog': | |
399 | result = openFileDialog() | |
400 | elif sel == 'saveFileDialog': | |
401 | result = saveFileDialog() | |
402 | elif sel == 'scrolledMessageDialog': | |
403 | msg = "Can't find the file dialog.py" | |
404 | try: | |
405 | # read this source file and then display it | |
406 | import sys | |
407 | filename = sys.argv[-1] | |
408 | fp = open(filename) | |
409 | message = fp.read() | |
410 | fp.close() | |
411 | except: | |
412 | pass | |
413 | result = scrolledMessageDialog(None, message, filename) | |
414 | elif sel == 'singleChoiceDialog': | |
415 | result = singleChoiceDialog(None, "message", "title", ['one', 'two', 'three']) | |
416 | elif sel == 'textEntryDialog': | |
417 | result = textEntryDialog(None, "message", "title", "text") | |
418 | ||
419 | if result: | |
420 | #self.text1.SetValue(pprint.pformat(result.__dict__)) | |
421 | self.text1.SetValue(str(result)) | |
422 | ||
423 | app = MyApp(True) | |
424 | app.MainLoop() | |
425 | ||
426 |