]>
Commit | Line | Data |
---|---|---|
d14a1e28 RD |
1 | #---------------------------------------------------------------------- |
2 | # Name: wxPython.lib.filebrowsebutton | |
3 | # Purpose: Composite controls that provide a Browse button next to | |
4 | # either a wxTextCtrl or a wxComboBox. The Browse button | |
5 | # launches a wxFileDialog and loads the result into the | |
6 | # other control. | |
7 | # | |
8 | # Author: Mike Fletcher | |
9 | # | |
10 | # RCS-ID: $Id$ | |
11 | # Copyright: (c) 2000 by Total Control Software | |
12 | # Licence: wxWindows license | |
13 | #---------------------------------------------------------------------- | |
14 | ||
15 | from wxPython.wx import * | |
16 | import os, types | |
17 | ||
18 | #---------------------------------------------------------------------- | |
19 | ||
20 | class FileBrowseButton(wxPanel): | |
21 | """ A control to allow the user to type in a filename | |
22 | or browse with the standard file dialog to select file | |
23 | ||
24 | __init__ ( | |
25 | parent, id, pos, size -- passed directly to wxPanel initialisation | |
26 | style = wxTAB_TRAVERSAL -- passed directly to wxPanel initialisation | |
27 | labelText -- Text for label to left of text field | |
28 | buttonText -- Text for button which launches the file dialog | |
29 | toolTip -- Help text | |
30 | dialogTitle -- Title used in file dialog | |
31 | startDirectory -- Default directory for file dialog startup | |
32 | fileMask -- File mask (glob pattern, such as *.*) to use in file dialog | |
33 | fileMode -- wxOPEN or wxSAVE, indicates type of file dialog to use | |
34 | changeCallback -- callback receives all > > changes in value of control | |
35 | ) | |
36 | GetValue() -- retrieve current value of text control | |
37 | SetValue(string) -- set current value of text control | |
38 | label -- pointer to internal label widget | |
39 | textControl -- pointer to internal text control | |
40 | browseButton -- pointer to button | |
41 | """ | |
42 | def __init__ (self, parent, id= -1, | |
43 | pos = wxDefaultPosition, size = wxDefaultSize, | |
44 | style = wxTAB_TRAVERSAL, | |
45 | labelText= "File Entry:", | |
46 | buttonText= "Browse", | |
47 | toolTip= "Type filename or click browse to choose file", | |
48 | # following are the values for a file dialog box | |
49 | dialogTitle = "Choose a file", | |
50 | startDirectory = ".", | |
51 | initialValue = "", | |
52 | fileMask = "*.*", | |
53 | fileMode = wxOPEN, | |
54 | # callback for when value changes (optional) | |
55 | changeCallback= lambda x:x | |
56 | ): | |
57 | # store variables | |
58 | self.labelText = labelText | |
59 | self.buttonText = buttonText | |
60 | self.toolTip = toolTip | |
61 | self.dialogTitle = dialogTitle | |
62 | self.startDirectory = startDirectory | |
63 | self.initialValue = initialValue | |
64 | self.fileMask = fileMask | |
65 | self.fileMode = fileMode | |
66 | self.changeCallback = changeCallback | |
67 | self.callCallback = True | |
68 | ||
69 | ||
70 | # get background to match it | |
71 | try: | |
72 | self._bc = parent.GetBackgroundColour() | |
73 | except: | |
74 | pass | |
75 | ||
76 | # create the dialog | |
77 | self.createDialog(parent, id, pos, size, style ) | |
78 | # Setting a value causes the changeCallback to be called. | |
79 | # In this case that would be before the return of the | |
80 | # constructor. Not good. So a default value on | |
81 | # SetValue is used to disable the callback | |
82 | self.SetValue( initialValue, 0) | |
83 | ||
84 | ||
85 | def createDialog( self, parent, id, pos, size, style ): | |
86 | """Setup the graphic representation of the dialog""" | |
87 | wxPanel.__init__ (self, parent, id, pos, size, style) | |
88 | # try to set the background colour | |
89 | try: | |
90 | self.SetBackgroundColour(self._bc) | |
91 | except: | |
92 | pass | |
93 | box = wxBoxSizer(wxHORIZONTAL) | |
94 | ||
95 | self.label = self.createLabel( ) | |
96 | box.Add( self.label, 0, wxCENTER ) | |
97 | ||
98 | self.textControl = self.createTextControl() | |
99 | box.Add( self.textControl, 1, wxLEFT|wxCENTER, 5) | |
100 | ||
101 | self.browseButton = self.createBrowseButton() | |
102 | box.Add( self.browseButton, 0, wxLEFT|wxCENTER, 5) | |
103 | ||
104 | # add a border around the whole thing and resize the panel to fit | |
105 | outsidebox = wxBoxSizer(wxVERTICAL) | |
106 | outsidebox.Add(box, 1, wxEXPAND|wxALL, 3) | |
107 | outsidebox.Fit(self) | |
108 | ||
109 | self.SetAutoLayout(True) | |
110 | self.SetSizer( outsidebox ) | |
111 | self.Layout() | |
112 | if type( size ) == types.TupleType: | |
113 | size = apply( wxSize, size) | |
114 | self.SetDimensions(-1, -1, size.width, size.height, wxSIZE_USE_EXISTING) | |
115 | ||
116 | # if size.width != -1 or size.height != -1: | |
117 | # self.SetSize(size) | |
118 | ||
119 | def SetBackgroundColour(self,color): | |
120 | wxPanel.SetBackgroundColour(self,color) | |
121 | self.label.SetBackgroundColour(color) | |
122 | ||
123 | def createLabel( self ): | |
124 | """Create the label/caption""" | |
125 | label = wxStaticText(self, -1, self.labelText, style =wxALIGN_RIGHT ) | |
126 | font = label.GetFont() | |
127 | w, h, d, e = self.GetFullTextExtent(self.labelText, font) | |
128 | label.SetSize(wxSize(w+5, h)) | |
129 | return label | |
130 | ||
131 | def createTextControl( self): | |
132 | """Create the text control""" | |
133 | ID = wxNewId() | |
134 | textControl = wxTextCtrl(self, ID) | |
135 | textControl.SetToolTipString( self.toolTip ) | |
136 | if self.changeCallback: | |
137 | EVT_TEXT(textControl, ID, self.OnChanged) | |
138 | EVT_COMBOBOX(textControl, ID, self.OnChanged) | |
139 | return textControl | |
140 | ||
141 | def OnChanged(self, evt): | |
142 | if self.callCallback and self.changeCallback: | |
143 | self.changeCallback(evt) | |
144 | ||
145 | def createBrowseButton( self): | |
146 | """Create the browse-button control""" | |
147 | ID = wxNewId() | |
148 | button =wxButton(self, ID, self.buttonText) | |
149 | button.SetToolTipString( self.toolTip ) | |
150 | EVT_BUTTON(button, ID, self.OnBrowse) | |
151 | return button | |
152 | ||
153 | ||
154 | def OnBrowse (self, event = None): | |
155 | """ Going to browse for file... """ | |
156 | current = self.GetValue() | |
157 | directory = os.path.split(current) | |
158 | if os.path.isdir( current): | |
159 | directory = current | |
160 | current = '' | |
161 | elif directory and os.path.isdir( directory[0] ): | |
162 | current = directory[1] | |
163 | directory = directory [0] | |
164 | else: | |
165 | directory = self.startDirectory | |
166 | dlg = wxFileDialog(self, self.dialogTitle, directory, current, self.fileMask, self.fileMode) | |
167 | ||
168 | if dlg.ShowModal() == wxID_OK: | |
169 | self.SetValue(dlg.GetPath()) | |
170 | dlg.Destroy() | |
171 | ||
172 | ||
173 | def GetValue (self): | |
174 | """ Convenient access to text control value """ | |
175 | return self.textControl.GetValue() | |
176 | ||
177 | def SetValue (self, value, callBack=1): | |
178 | """ Convenient setting of text control value """ | |
179 | save = self.callCallback | |
180 | self.callCallback = callBack | |
181 | self.textControl.SetValue(value) | |
182 | self.callCallback = save | |
183 | ||
184 | ||
185 | def Enable (self, value): | |
186 | """ Convenient enabling/disabling of entire control """ | |
187 | self.label.Enable (value) | |
188 | self.textControl.Enable (value) | |
189 | return self.browseButton.Enable (value) | |
190 | ||
191 | def GetLabel( self ): | |
192 | """ Retrieve the label's current text """ | |
193 | return self.label.GetLabel() | |
194 | ||
195 | def SetLabel( self, value ): | |
196 | """ Set the label's current text """ | |
197 | rvalue = self.label.SetLabel( value ) | |
198 | self.Refresh( True ) | |
199 | return rvalue | |
200 | ||
201 | ||
202 | ||
203 | ||
204 | class FileBrowseButtonWithHistory( FileBrowseButton ): | |
205 | """ with following additions: | |
206 | __init__(..., history=None) | |
207 | ||
208 | history -- optional list of paths for initial history drop-down | |
209 | (must be passed by name, not a positional argument) | |
210 | If history is callable it will must return a list used | |
211 | for the history drop-down | |
212 | changeCallback -- as for FileBrowseButton, but with a work-around | |
213 | for win32 systems which don't appear to create EVT_COMBOBOX | |
214 | events properly. There is a (slight) chance that this work-around | |
215 | will cause some systems to create two events for each Combobox | |
216 | selection. If you discover this condition, please report it! | |
217 | As for a FileBrowseButton.__init__ otherwise. | |
218 | GetHistoryControl() | |
219 | Return reference to the control which implements interfaces | |
220 | required for manipulating the history list. See GetHistoryControl | |
221 | documentation for description of what that interface is. | |
222 | GetHistory() | |
223 | Return current history list | |
224 | SetHistory( value=(), selectionIndex = None ) | |
225 | Set current history list, if selectionIndex is not None, select that index | |
226 | """ | |
227 | def __init__( self, *arguments, **namedarguments): | |
228 | self.history = namedarguments.get( "history" ) | |
229 | if self.history: | |
230 | del namedarguments["history"] | |
231 | ||
232 | self.historyCallBack=None | |
233 | if callable(self.history): | |
234 | self.historyCallBack=self.history | |
235 | self.history=None | |
236 | apply( FileBrowseButton.__init__, ( self,)+arguments, namedarguments) | |
237 | ||
238 | ||
239 | def createTextControl( self): | |
240 | """Create the text control""" | |
241 | ID = wxNewId() | |
242 | textControl = wxComboBox(self, ID, style = wxCB_DROPDOWN ) | |
243 | textControl.SetToolTipString( self.toolTip ) | |
244 | EVT_SET_FOCUS(textControl, self.OnSetFocus) | |
245 | if self.changeCallback: | |
246 | EVT_TEXT(textControl, ID, self.changeCallback) | |
247 | EVT_COMBOBOX(textControl, ID, self.changeCallback) | |
248 | if self.history: | |
249 | history=self.history | |
250 | self.history=None | |
251 | self.SetHistory( history, control=textControl) | |
252 | return textControl | |
253 | ||
254 | ||
255 | def GetHistoryControl( self ): | |
256 | """Return a pointer to the control which provides (at least) | |
257 | the following methods for manipulating the history list.: | |
258 | Append( item ) -- add item | |
259 | Clear() -- clear all items | |
260 | Delete( index ) -- 0-based index to delete from list | |
261 | SetSelection( index ) -- 0-based index to select in list | |
262 | Semantics of the methods follow those for the wxComboBox control | |
263 | """ | |
264 | return self.textControl | |
265 | ||
266 | ||
267 | def SetHistory( self, value=(), selectionIndex = None, control=None ): | |
268 | """Set the current history list""" | |
269 | if control is None: | |
270 | control = self.GetHistoryControl() | |
271 | if self.history == value: | |
272 | return | |
273 | self.history = value | |
274 | # Clear history values not the selected one. | |
275 | tempValue=control.GetValue() | |
276 | # clear previous values | |
277 | control.Clear() | |
278 | control.SetValue(tempValue) | |
279 | # walk through, appending new values | |
280 | for path in value: | |
281 | control.Append( path ) | |
282 | if selectionIndex is not None: | |
283 | control.SetSelection( selectionIndex ) | |
284 | ||
285 | ||
286 | def GetHistory( self ): | |
287 | """Return the current history list""" | |
288 | if self.historyCallBack != None: | |
289 | return self.historyCallBack() | |
290 | else: | |
291 | return list( self.history ) | |
292 | ||
293 | ||
294 | def OnSetFocus(self, event): | |
295 | """When the history scroll is selected, update the history""" | |
296 | if self.historyCallBack != None: | |
297 | self.SetHistory( self.historyCallBack(), control=self.textControl) | |
298 | event.Skip() | |
299 | ||
300 | ||
301 | if wxPlatform == "__WXMSW__": | |
302 | def SetValue (self, value, callBack=1): | |
303 | """ Convenient setting of text control value, works | |
304 | around limitation of wxComboBox """ | |
305 | save = self.callCallback | |
306 | self.callCallback = callBack | |
307 | self.textControl.SetValue(value) | |
308 | self.callCallback = save | |
309 | ||
310 | # Hack to call an event handler | |
311 | class LocalEvent: | |
312 | def __init__(self, string): | |
313 | self._string=string | |
314 | def GetString(self): | |
315 | return self._string | |
316 | if callBack==1: | |
317 | # The callback wasn't being called when SetValue was used ?? | |
318 | # So added this explicit call to it | |
319 | self.changeCallback(LocalEvent(value)) | |
320 | ||
321 | ||
322 | class DirBrowseButton(FileBrowseButton): | |
323 | def __init__(self, parent, id = -1, | |
324 | pos = wxDefaultPosition, size = wxDefaultSize, | |
325 | style = wxTAB_TRAVERSAL, | |
326 | labelText = 'Select a directory:', | |
327 | buttonText = 'Browse', | |
328 | toolTip = 'Type directory name or browse to select', | |
329 | dialogTitle = '', | |
330 | startDirectory = '.', | |
331 | changeCallback = None, | |
332 | dialogClass = wxDirDialog): | |
333 | FileBrowseButton.__init__(self, parent, id, pos, size, style, | |
334 | labelText, buttonText, toolTip, | |
335 | dialogTitle, startDirectory, | |
336 | changeCallback = changeCallback) | |
337 | # | |
338 | self._dirDialog = dialogClass(self, | |
339 | message = dialogTitle, | |
340 | defaultPath = startDirectory) | |
341 | # | |
342 | def OnBrowse(self, ev = None): | |
343 | dialog = self._dirDialog | |
344 | if dialog.ShowModal() == wxID_OK: | |
345 | self.SetValue(dialog.GetPath()) | |
346 | # | |
347 | def __del__(self): | |
348 | if self.__dict__.has_key('_dirDialog'): | |
349 | self._dirDialog.Destroy() | |
350 | ||
351 | ||
352 | #---------------------------------------------------------------------- | |
353 | ||
354 | ||
355 | if __name__ == "__main__": | |
356 | #from skeletonbuilder import rulesfile | |
357 | class SimpleCallback: | |
358 | def __init__( self, tag ): | |
359 | self.tag = tag | |
360 | def __call__( self, event ): | |
361 | print self.tag, event.GetString() | |
362 | class DemoFrame( wxFrame ): | |
363 | def __init__(self, parent): | |
364 | wxFrame.__init__(self, parent, 2400, "File entry with browse", size=(500,260) ) | |
365 | EVT_CLOSE(self, self.OnCloseWindow) | |
366 | panel = wxPanel (self,-1) | |
367 | innerbox = wxBoxSizer(wxVERTICAL) | |
368 | control = FileBrowseButton( | |
369 | panel, | |
370 | initialValue = "z:\\temp", | |
371 | ) | |
372 | innerbox.Add( control, 0, wxEXPAND ) | |
373 | middlecontrol = FileBrowseButtonWithHistory( | |
374 | panel, | |
375 | labelText = "With History", | |
376 | initialValue = "d:\\temp", | |
377 | history = ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"], | |
378 | changeCallback= SimpleCallback( "With History" ), | |
379 | ) | |
380 | innerbox.Add( middlecontrol, 0, wxEXPAND ) | |
381 | middlecontrol = FileBrowseButtonWithHistory( | |
382 | panel, | |
383 | labelText = "History callback", | |
384 | initialValue = "d:\\temp", | |
385 | history = self.historyCallBack, | |
386 | changeCallback= SimpleCallback( "History callback" ), | |
387 | ) | |
388 | innerbox.Add( middlecontrol, 0, wxEXPAND ) | |
389 | self.bottomcontrol = control = FileBrowseButton( | |
390 | panel, | |
391 | labelText = "With Callback", | |
392 | style = wxSUNKEN_BORDER|wxCLIP_CHILDREN , | |
393 | changeCallback= SimpleCallback( "With Callback" ), | |
394 | ) | |
395 | innerbox.Add( control, 0, wxEXPAND) | |
396 | self.bottommostcontrol = control = DirBrowseButton( | |
397 | panel, | |
398 | labelText = "Simple dir browse button", | |
399 | style = wxSUNKEN_BORDER|wxCLIP_CHILDREN) | |
400 | innerbox.Add( control, 0, wxEXPAND) | |
401 | ID = wxNewId() | |
402 | innerbox.Add( wxButton( panel, ID,"Change Label", ), 1, wxEXPAND) | |
403 | EVT_BUTTON( self, ID, self.OnChangeLabel ) | |
404 | ID = wxNewId() | |
405 | innerbox.Add( wxButton( panel, ID,"Change Value", ), 1, wxEXPAND) | |
406 | EVT_BUTTON( self, ID, self.OnChangeValue ) | |
407 | panel.SetAutoLayout(True) | |
408 | panel.SetSizer( innerbox ) | |
409 | self.history={"c:\\temp":1, "c:\\tmp":1, "r:\\temp":1,"z:\\temp":1} | |
410 | ||
411 | def historyCallBack(self): | |
412 | keys=self.history.keys() | |
413 | keys.sort() | |
414 | return keys | |
415 | ||
416 | def OnFileNameChangedHistory (self, event): | |
417 | self.history[event.GetString ()]=1 | |
418 | ||
419 | def OnCloseMe(self, event): | |
420 | self.Close(True) | |
421 | def OnChangeLabel( self, event ): | |
422 | self.bottomcontrol.SetLabel( "Label Updated" ) | |
423 | def OnChangeValue( self, event ): | |
424 | self.bottomcontrol.SetValue( "r:\\somewhere\\over\\the\\rainbow.htm" ) | |
425 | ||
426 | def OnCloseWindow(self, event): | |
427 | self.Destroy() | |
428 | ||
429 | class DemoApp(wxApp): | |
430 | def OnInit(self): | |
431 | wxImage_AddHandler(wxJPEGHandler()) | |
432 | wxImage_AddHandler(wxPNGHandler()) | |
433 | wxImage_AddHandler(wxGIFHandler()) | |
434 | frame = DemoFrame(NULL) | |
435 | #frame = RulesPanel(NULL ) | |
436 | frame.Show(True) | |
437 | self.SetTopWindow(frame) | |
438 | return True | |
439 | ||
440 | def test( ): | |
441 | app = DemoApp(0) | |
442 | app.MainLoop() | |
443 | print 'Creating dialog' | |
444 | test( ) | |
445 | ||
1fded56b | 446 | |
1fded56b | 447 |