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
8 # Author: Mike Fletcher
11 # Copyright: (c) 2000 by Total Control Software
12 # Licence: wxWindows license
13 #----------------------------------------------------------------------
14 # 12/02/2003 - Jeff Grimmett (grimmtooth@softhome.net)
16 # o 2.5 Compatability changes
24 #----------------------------------------------------------------------
26 class FileBrowseButton(wx
.Panel
):
28 A control to allow the user to type in a filename or browse with
29 the standard file dialog to select file
31 def __init__ (self
, parent
, id= -1,
32 pos
= wx
.DefaultPosition
,
33 size
= wx
.DefaultSize
,
34 style
= wx
.TAB_TRAVERSAL
,
35 labelText
= "File Entry:",
37 toolTip
= "Type filename or click browse to choose file",
38 # following are the values for a file dialog box
39 dialogTitle
= "Choose a file",
44 # callback for when value changes (optional)
45 changeCallback
= lambda x
:x
48 :param labelText: Text for label to left of text field
49 :param buttonText: Text for button which launches the file dialog
50 :param toolTip: Help text
51 :param dialogTitle: Title used in file dialog
52 :param startDirectory: Default directory for file dialog startup
53 :param fileMask: File mask (glob pattern, such as *.*) to use in file dialog
54 :param fileMode: wx.OPEN or wx.SAVE, indicates type of file dialog to use
55 :param changeCallback: callback receives all changes in value of control
59 self
.labelText
= labelText
60 self
.buttonText
= buttonText
61 self
.toolTip
= toolTip
62 self
.dialogTitle
= dialogTitle
63 self
.startDirectory
= startDirectory
64 self
.initialValue
= initialValue
65 self
.fileMask
= fileMask
66 self
.fileMode
= fileMode
67 self
.changeCallback
= changeCallback
68 self
.callCallback
= True
71 # get background to match it
73 self
._bc
= parent
.GetBackgroundColour()
78 self
.createDialog(parent
, id, pos
, size
, style
)
79 # Setting a value causes the changeCallback to be called.
80 # In this case that would be before the return of the
81 # constructor. Not good. So a default value on
82 # SetValue is used to disable the callback
83 self
.SetValue( initialValue
, 0)
86 def createDialog( self
, parent
, id, pos
, size
, style
):
87 """Setup the graphic representation of the dialog"""
88 wx
.Panel
.__init
__ (self
, parent
, id, pos
, size
, style
)
89 # try to set the background colour
91 self
.SetBackgroundColour(self
._bc
)
94 box
= wx
.BoxSizer(wx
.HORIZONTAL
)
96 self
.label
= self
.createLabel( )
97 box
.Add( self
.label
, 0, wx
.CENTER
)
99 self
.textControl
= self
.createTextControl()
100 box
.Add( self
.textControl
, 1, wx
.LEFT|wx
.CENTER
, 5)
102 self
.browseButton
= self
.createBrowseButton()
103 box
.Add( self
.browseButton
, 0, wx
.LEFT|wx
.CENTER
, 5)
105 # add a border around the whole thing and resize the panel to fit
106 outsidebox
= wx
.BoxSizer(wx
.VERTICAL
)
107 outsidebox
.Add(box
, 1, wx
.EXPAND|wx
.ALL
, 3)
110 self
.SetAutoLayout(True)
111 self
.SetSizer( outsidebox
)
113 if type( size
) == types
.TupleType
:
114 size
= apply( wx
.Size
, size
)
115 self
.SetDimensions(-1, -1, size
.width
, size
.height
, wx
.SIZE_USE_EXISTING
)
117 # if size.width != -1 or size.height != -1:
120 def SetBackgroundColour(self
,color
):
121 wx
.Panel
.SetBackgroundColour(self
,color
)
122 self
.label
.SetBackgroundColour(color
)
124 def createLabel( self
):
125 """Create the label/caption"""
126 label
= wx
.StaticText(self
, -1, self
.labelText
, style
=wx
.ALIGN_RIGHT
)
127 font
= label
.GetFont()
128 w
, h
, d
, e
= self
.GetFullTextExtent(self
.labelText
, font
)
129 label
.SetSize((w
+5, h
))
132 def createTextControl( self
):
133 """Create the text control"""
134 textControl
= wx
.TextCtrl(self
, -1)
135 textControl
.SetToolTipString( self
.toolTip
)
136 if self
.changeCallback
:
137 textControl
.Bind(wx
.EVT_TEXT
, self
.OnChanged
)
138 textControl
.Bind(wx
.EVT_COMBOBOX
, self
.OnChanged
)
141 def OnChanged(self
, evt
):
142 if self
.callCallback
and self
.changeCallback
:
143 self
.changeCallback(evt
)
145 def createBrowseButton( self
):
146 """Create the browse-button control"""
147 button
=wx
.Button(self
, -1, self
.buttonText
)
148 button
.SetToolTipString( self
.toolTip
)
149 button
.Bind(wx
.EVT_BUTTON
, self
.OnBrowse
)
153 def OnBrowse (self
, event
= None):
154 """ Going to browse for file... """
155 current
= self
.GetValue()
156 directory
= os
.path
.split(current
)
157 if os
.path
.isdir( current
):
160 elif directory
and os
.path
.isdir( directory
[0] ):
161 current
= directory
[1]
162 directory
= directory
[0]
164 directory
= self
.startDirectory
165 dlg
= wx
.FileDialog(self
, self
.dialogTitle
, directory
, current
,
166 self
.fileMask
, self
.fileMode
)
168 if dlg
.ShowModal() == wx
.ID_OK
:
169 self
.SetValue(dlg
.GetPath())
175 retrieve current value of text control
177 return self
.textControl
.GetValue()
179 def SetValue (self
, value
, callBack
=1):
180 """set current value of text control"""
181 save
= self
.callCallback
182 self
.callCallback
= callBack
183 self
.textControl
.SetValue(value
)
184 self
.callCallback
= save
187 def Enable (self
, value
):
188 """ Convenient enabling/disabling of entire control """
189 self
.label
.Enable (value
)
190 self
.textControl
.Enable (value
)
191 return self
.browseButton
.Enable (value
)
193 def GetLabel( self
):
194 """ Retrieve the label's current text """
195 return self
.label
.GetLabel()
197 def SetLabel( self
, value
):
198 """ Set the label's current text """
199 rvalue
= self
.label
.SetLabel( value
)
206 class FileBrowseButtonWithHistory( FileBrowseButton
):
208 with following additions:
209 __init__(..., history=None)
211 history -- optional list of paths for initial history drop-down
212 (must be passed by name, not a positional argument)
213 If history is callable it will must return a list used
214 for the history drop-down
216 changeCallback -- as for FileBrowseButton, but with a work-around
217 for win32 systems which don't appear to create wx.EVT_COMBOBOX
218 events properly. There is a (slight) chance that this work-around
219 will cause some systems to create two events for each Combobox
220 selection. If you discover this condition, please report it!
222 As for a FileBrowseButton.__init__ otherwise.
225 Return reference to the control which implements interfaces
226 required for manipulating the history list. See GetHistoryControl
227 documentation for description of what that interface is.
230 Return current history list
232 SetHistory( value=(), selectionIndex = None )
233 Set current history list, if selectionIndex is not None, select that index
236 def __init__( self
, *arguments
, **namedarguments
):
237 self
.history
= namedarguments
.get( "history" )
239 del namedarguments
["history"]
241 self
.historyCallBack
=None
242 if callable(self
.history
):
243 self
.historyCallBack
=self
.history
245 apply( FileBrowseButton
.__init
__, ( self
,)+arguments
, namedarguments
)
248 def createTextControl( self
):
249 """Create the text control"""
250 textControl
= wx
.ComboBox(self
, -1, style
= wx
.CB_DROPDOWN
)
251 textControl
.SetToolTipString( self
.toolTip
)
252 textControl
.Bind(wx
.EVT_SET_FOCUS
, self
.OnSetFocus
)
253 if self
.changeCallback
:
254 textControl
.Bind(wx
.EVT_TEXT
, self
.changeCallback
)
255 textControl
.Bind(wx
.EVT_COMBOBOX
, self
.changeCallback
)
259 self
.SetHistory( history
, control
=textControl
)
263 def GetHistoryControl( self
):
265 Return a pointer to the control which provides (at least)
266 the following methods for manipulating the history list:
268 Append( item ) -- add item
269 Clear() -- clear all items
270 Delete( index ) -- 0-based index to delete from list
271 SetSelection( index ) -- 0-based index to select in list
273 Semantics of the methods follow those for the wxComboBox control
275 return self
.textControl
278 def SetHistory( self
, value
=(), selectionIndex
= None, control
=None ):
279 """Set the current history list"""
281 control
= self
.GetHistoryControl()
282 if self
.history
== value
:
285 # Clear history values not the selected one.
286 tempValue
=control
.GetValue()
287 # clear previous values
289 control
.SetValue(tempValue
)
290 # walk through, appending new values
292 control
.Append( path
)
293 if selectionIndex
is not None:
294 control
.SetSelection( selectionIndex
)
297 def GetHistory( self
):
298 """Return the current history list"""
299 if self
.historyCallBack
!= None:
300 return self
.historyCallBack()
302 return list( self
.history
)
305 def OnSetFocus(self
, event
):
306 """When the history scroll is selected, update the history"""
307 if self
.historyCallBack
!= None:
308 self
.SetHistory( self
.historyCallBack(), control
=self
.textControl
)
312 if wx
.Platform
== "__WXMSW__":
313 def SetValue (self
, value
, callBack
=1):
314 """ Convenient setting of text control value, works
315 around limitation of wx.ComboBox """
316 save
= self
.callCallback
317 self
.callCallback
= callBack
318 self
.textControl
.SetValue(value
)
319 self
.callCallback
= save
321 # Hack to call an event handler
323 def __init__(self
, string
):
328 # The callback wasn't being called when SetValue was used ??
329 # So added this explicit call to it
330 self
.changeCallback(LocalEvent(value
))
333 class DirBrowseButton(FileBrowseButton
):
334 def __init__(self
, parent
, id = -1,
335 pos
= wx
.DefaultPosition
, size
= wx
.DefaultSize
,
336 style
= wx
.TAB_TRAVERSAL
,
337 labelText
= 'Select a directory:',
338 buttonText
= 'Browse',
339 toolTip
= 'Type directory name or browse to select',
341 startDirectory
= '.',
342 changeCallback
= None,
343 dialogClass
= wx
.DirDialog
):
344 FileBrowseButton
.__init
__(self
, parent
, id, pos
, size
, style
,
345 labelText
, buttonText
, toolTip
,
346 dialogTitle
, startDirectory
,
347 changeCallback
= changeCallback
)
348 self
.dialogClass
= dialogClass
351 def OnBrowse(self
, ev
= None):
352 dialog
= self
.dialogClass(self
,
353 message
= self
.dialogTitle
,
354 defaultPath
= self
.startDirectory
)
355 if dialog
.ShowModal() == wx
.ID_OK
:
356 self
.SetValue(dialog
.GetPath())
361 #----------------------------------------------------------------------
364 if __name__
== "__main__":
365 #from skeletonbuilder import rulesfile
366 class SimpleCallback
:
367 def __init__( self
, tag
):
369 def __call__( self
, event
):
370 print self
.tag
, event
.GetString()
371 class DemoFrame( wx
.Frame
):
372 def __init__(self
, parent
):
373 wx
.Frame
.__init
__(self
, parent
, -1, "File entry with browse", size
=(500,260))
374 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
375 panel
= wx
.Panel (self
,-1)
376 innerbox
= wx
.BoxSizer(wx
.VERTICAL
)
377 control
= FileBrowseButton(
379 initialValue
= "z:\\temp",
381 innerbox
.Add( control
, 0, wx
.EXPAND
)
382 middlecontrol
= FileBrowseButtonWithHistory(
384 labelText
= "With History",
385 initialValue
= "d:\\temp",
386 history
= ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"],
387 changeCallback
= SimpleCallback( "With History" ),
389 innerbox
.Add( middlecontrol
, 0, wx
.EXPAND
)
390 middlecontrol
= FileBrowseButtonWithHistory(
392 labelText
= "History callback",
393 initialValue
= "d:\\temp",
394 history
= self
.historyCallBack
,
395 changeCallback
= SimpleCallback( "History callback" ),
397 innerbox
.Add( middlecontrol
, 0, wx
.EXPAND
)
398 self
.bottomcontrol
= control
= FileBrowseButton(
400 labelText
= "With Callback",
401 style
= wx
.SUNKEN_BORDER|wx
.CLIP_CHILDREN
,
402 changeCallback
= SimpleCallback( "With Callback" ),
404 innerbox
.Add( control
, 0, wx
.EXPAND
)
405 self
.bottommostcontrol
= control
= DirBrowseButton(
407 labelText
= "Simple dir browse button",
408 style
= wx
.SUNKEN_BORDER|wx
.CLIP_CHILDREN
)
409 innerbox
.Add( control
, 0, wx
.EXPAND
)
411 innerbox
.Add( wx
.Button( panel
, ID
,"Change Label", ), 1, wx
.EXPAND
)
412 self
.Bind(wx
.EVT_BUTTON
, self
.OnChangeLabel
, id=ID
)
414 innerbox
.Add( wx
.Button( panel
, ID
,"Change Value", ), 1, wx
.EXPAND
)
415 self
.Bind(wx
.EVT_BUTTON
, self
.OnChangeValue
, id=ID
)
416 panel
.SetAutoLayout(True)
417 panel
.SetSizer( innerbox
)
418 self
.history
={"c:\\temp":1, "c:\\tmp":1, "r:\\temp":1,"z:\\temp":1}
420 def historyCallBack(self
):
421 keys
=self
.history
.keys()
425 def OnFileNameChangedHistory (self
, event
):
426 self
.history
[event
.GetString ()]=1
428 def OnCloseMe(self
, event
):
430 def OnChangeLabel( self
, event
):
431 self
.bottomcontrol
.SetLabel( "Label Updated" )
432 def OnChangeValue( self
, event
):
433 self
.bottomcontrol
.SetValue( "r:\\somewhere\\over\\the\\rainbow.htm" )
435 def OnCloseWindow(self
, event
):
438 class DemoApp(wx
.App
):
440 wx
.InitAllImageHandlers()
441 frame
= DemoFrame(None)
443 self
.SetTopWindow(frame
)
449 print 'Creating dialog'