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