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: Optional callback called for all changes in value of the 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 self
.SetMinSize(size
) # play nice with sizers
91 # try to set the background colour
93 #Question: is this still needed on other platforms?
94 #It should have transparent background on Mac
95 if wx
.Platform
!= "__WXMAC__":
96 self
.SetBackgroundColour(self
._bc
)
100 box
= wx
.BoxSizer(wx
.HORIZONTAL
)
102 self
.label
= self
.createLabel( )
103 box
.Add( self
.label
, 0, wx
.CENTER
)
105 self
.textControl
= self
.createTextControl()
106 box
.Add( self
.textControl
, 1, wx
.LEFT|wx
.CENTER
, 5)
108 self
.browseButton
= self
.createBrowseButton()
109 box
.Add( self
.browseButton
, 0, wx
.LEFT|wx
.CENTER
, 5)
111 # add a border around the whole thing and resize the panel to fit
112 outsidebox
= wx
.BoxSizer(wx
.VERTICAL
)
113 outsidebox
.Add(box
, 1, wx
.EXPAND|wx
.ALL
, 3)
116 self
.SetAutoLayout(True)
117 self
.SetSizer( outsidebox
)
119 if type( size
) == types
.TupleType
:
120 size
= apply( wx
.Size
, size
)
121 self
.SetDimensions(-1, -1, size
.width
, size
.height
, wx
.SIZE_USE_EXISTING
)
123 # if size.width != -1 or size.height != -1:
126 def SetBackgroundColour(self
,color
):
127 wx
.Panel
.SetBackgroundColour(self
,color
)
128 self
.label
.SetBackgroundColour(color
)
130 def createLabel( self
):
131 """Create the label/caption"""
132 label
= wx
.StaticText(self
, -1, self
.labelText
, style
=wx
.ALIGN_RIGHT
)
133 font
= label
.GetFont()
134 w
, h
, d
, e
= self
.GetFullTextExtent(self
.labelText
, font
)
135 label
.SetSize((w
+5, h
))
138 def createTextControl( self
):
139 """Create the text control"""
140 textControl
= wx
.TextCtrl(self
, -1)
141 textControl
.SetToolTipString( self
.toolTip
)
142 if self
.changeCallback
:
143 textControl
.Bind(wx
.EVT_TEXT
, self
.OnChanged
)
144 textControl
.Bind(wx
.EVT_COMBOBOX
, self
.OnChanged
)
147 def OnChanged(self
, evt
):
148 if self
.callCallback
and self
.changeCallback
:
149 self
.changeCallback(evt
)
151 def createBrowseButton( self
):
152 """Create the browse-button control"""
153 button
=wx
.Button(self
, -1, self
.buttonText
)
154 button
.SetToolTipString( self
.toolTip
)
155 button
.Bind(wx
.EVT_BUTTON
, self
.OnBrowse
)
159 def OnBrowse (self
, event
= None):
160 """ Going to browse for file... """
161 current
= self
.GetValue()
162 directory
= os
.path
.split(current
)
163 if os
.path
.isdir( current
):
166 elif directory
and os
.path
.isdir( directory
[0] ):
167 current
= directory
[1]
168 directory
= directory
[0]
170 directory
= self
.startDirectory
171 dlg
= wx
.FileDialog(self
, self
.dialogTitle
, directory
, current
,
172 self
.fileMask
, self
.fileMode
)
174 if dlg
.ShowModal() == wx
.ID_OK
:
175 self
.SetValue(dlg
.GetPath())
181 retrieve current value of text control
183 return self
.textControl
.GetValue()
185 def SetValue (self
, value
, callBack
=1):
186 """set current value of text control"""
187 save
= self
.callCallback
188 self
.callCallback
= callBack
189 self
.textControl
.SetValue(value
)
190 self
.callCallback
= save
193 def Enable (self
, value
):
194 """ Convenient enabling/disabling of entire control """
195 self
.label
.Enable (value
)
196 self
.textControl
.Enable (value
)
197 return self
.browseButton
.Enable (value
)
199 def GetLabel( self
):
200 """ Retrieve the label's current text """
201 return self
.label
.GetLabel()
203 def SetLabel( self
, value
):
204 """ Set the label's current text """
205 rvalue
= self
.label
.SetLabel( value
)
212 class FileBrowseButtonWithHistory( FileBrowseButton
):
214 with following additions:
215 __init__(..., history=None)
217 history -- optional list of paths for initial history drop-down
218 (must be passed by name, not a positional argument)
219 If history is callable it will must return a list used
220 for the history drop-down
222 changeCallback -- as for FileBrowseButton, but with a work-around
223 for win32 systems which don't appear to create wx.EVT_COMBOBOX
224 events properly. There is a (slight) chance that this work-around
225 will cause some systems to create two events for each Combobox
226 selection. If you discover this condition, please report it!
228 As for a FileBrowseButton.__init__ otherwise.
231 Return reference to the control which implements interfaces
232 required for manipulating the history list. See GetHistoryControl
233 documentation for description of what that interface is.
236 Return current history list
238 SetHistory( value=(), selectionIndex = None )
239 Set current history list, if selectionIndex is not None, select that index
242 def __init__( self
, *arguments
, **namedarguments
):
243 self
.history
= namedarguments
.get( "history" )
245 del namedarguments
["history"]
247 self
.historyCallBack
=None
248 if callable(self
.history
):
249 self
.historyCallBack
=self
.history
251 apply( FileBrowseButton
.__init
__, ( self
,)+arguments
, namedarguments
)
254 def createTextControl( self
):
255 """Create the text control"""
256 textControl
= wx
.ComboBox(self
, -1, style
= wx
.CB_DROPDOWN
)
257 textControl
.SetToolTipString( self
.toolTip
)
258 textControl
.Bind(wx
.EVT_SET_FOCUS
, self
.OnSetFocus
)
259 if self
.changeCallback
:
260 textControl
.Bind(wx
.EVT_TEXT
, self
.changeCallback
)
261 textControl
.Bind(wx
.EVT_COMBOBOX
, self
.changeCallback
)
265 self
.SetHistory( history
, control
=textControl
)
269 def GetHistoryControl( self
):
271 Return a pointer to the control which provides (at least)
272 the following methods for manipulating the history list:
274 Append( item ) -- add item
275 Clear() -- clear all items
276 Delete( index ) -- 0-based index to delete from list
277 SetSelection( index ) -- 0-based index to select in list
279 Semantics of the methods follow those for the wxComboBox control
281 return self
.textControl
284 def SetHistory( self
, value
=(), selectionIndex
= None, control
=None ):
285 """Set the current history list"""
287 control
= self
.GetHistoryControl()
288 if self
.history
== value
:
291 # Clear history values not the selected one.
292 tempValue
=control
.GetValue()
293 # clear previous values
295 control
.SetValue(tempValue
)
296 # walk through, appending new values
298 control
.Append( path
)
299 if selectionIndex
is not None:
300 control
.SetSelection( selectionIndex
)
303 def GetHistory( self
):
304 """Return the current history list"""
305 if self
.historyCallBack
!= None:
306 return self
.historyCallBack()
308 return list( self
.history
)
311 def OnSetFocus(self
, event
):
312 """When the history scroll is selected, update the history"""
313 if self
.historyCallBack
!= None:
314 self
.SetHistory( self
.historyCallBack(), control
=self
.textControl
)
318 if wx
.Platform
== "__WXMSW__":
319 def SetValue (self
, value
, callBack
=1):
320 """ Convenient setting of text control value, works
321 around limitation of wx.ComboBox """
322 save
= self
.callCallback
323 self
.callCallback
= callBack
324 self
.textControl
.SetValue(value
)
325 self
.callCallback
= save
327 # Hack to call an event handler
329 def __init__(self
, string
):
334 # The callback wasn't being called when SetValue was used ??
335 # So added this explicit call to it
336 self
.changeCallback(LocalEvent(value
))
339 class DirBrowseButton(FileBrowseButton
):
340 def __init__(self
, parent
, id = -1,
341 pos
= wx
.DefaultPosition
, size
= wx
.DefaultSize
,
342 style
= wx
.TAB_TRAVERSAL
,
343 labelText
= 'Select a directory:',
344 buttonText
= 'Browse',
345 toolTip
= 'Type directory name or browse to select',
347 startDirectory
= '.',
348 changeCallback
= None,
349 dialogClass
= wx
.DirDialog
,
350 newDirectory
= False):
351 FileBrowseButton
.__init
__(self
, parent
, id, pos
, size
, style
,
352 labelText
, buttonText
, toolTip
,
353 dialogTitle
, startDirectory
,
354 changeCallback
= changeCallback
)
355 self
.dialogClass
= dialogClass
356 self
.newDirectory
= newDirectory
359 def OnBrowse(self
, ev
= None):
362 if self
.newDirectory
:
363 style|
=wx
.DD_NEW_DIR_BUTTON
365 dialog
= self
.dialogClass(self
,
366 message
= self
.dialogTitle
,
367 defaultPath
= self
.startDirectory
,
370 if dialog
.ShowModal() == wx
.ID_OK
:
371 self
.SetValue(dialog
.GetPath())
376 #----------------------------------------------------------------------
379 if __name__
== "__main__":
380 #from skeletonbuilder import rulesfile
381 class SimpleCallback
:
382 def __init__( self
, tag
):
384 def __call__( self
, event
):
385 print self
.tag
, event
.GetString()
386 class DemoFrame( wx
.Frame
):
387 def __init__(self
, parent
):
388 wx
.Frame
.__init
__(self
, parent
, -1, "File entry with browse", size
=(500,260))
389 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
390 panel
= wx
.Panel (self
,-1)
391 innerbox
= wx
.BoxSizer(wx
.VERTICAL
)
392 control
= FileBrowseButton(
394 initialValue
= "z:\\temp",
396 innerbox
.Add( control
, 0, wx
.EXPAND
)
397 middlecontrol
= FileBrowseButtonWithHistory(
399 labelText
= "With History",
400 initialValue
= "d:\\temp",
401 history
= ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"],
402 changeCallback
= SimpleCallback( "With History" ),
404 innerbox
.Add( middlecontrol
, 0, wx
.EXPAND
)
405 middlecontrol
= FileBrowseButtonWithHistory(
407 labelText
= "History callback",
408 initialValue
= "d:\\temp",
409 history
= self
.historyCallBack
,
410 changeCallback
= SimpleCallback( "History callback" ),
412 innerbox
.Add( middlecontrol
, 0, wx
.EXPAND
)
413 self
.bottomcontrol
= control
= FileBrowseButton(
415 labelText
= "With Callback",
416 style
= wx
.SUNKEN_BORDER|wx
.CLIP_CHILDREN
,
417 changeCallback
= SimpleCallback( "With Callback" ),
419 innerbox
.Add( control
, 0, wx
.EXPAND
)
420 self
.bottommostcontrol
= control
= DirBrowseButton(
422 labelText
= "Simple dir browse button",
423 style
= wx
.SUNKEN_BORDER|wx
.CLIP_CHILDREN
)
424 innerbox
.Add( control
, 0, wx
.EXPAND
)
426 innerbox
.Add( wx
.Button( panel
, ID
,"Change Label", ), 1, wx
.EXPAND
)
427 self
.Bind(wx
.EVT_BUTTON
, self
.OnChangeLabel
, id=ID
)
429 innerbox
.Add( wx
.Button( panel
, ID
,"Change Value", ), 1, wx
.EXPAND
)
430 self
.Bind(wx
.EVT_BUTTON
, self
.OnChangeValue
, id=ID
)
431 panel
.SetAutoLayout(True)
432 panel
.SetSizer( innerbox
)
433 self
.history
={"c:\\temp":1, "c:\\tmp":1, "r:\\temp":1,"z:\\temp":1}
435 def historyCallBack(self
):
436 keys
=self
.history
.keys()
440 def OnFileNameChangedHistory (self
, event
):
441 self
.history
[event
.GetString ()]=1
443 def OnCloseMe(self
, event
):
445 def OnChangeLabel( self
, event
):
446 self
.bottomcontrol
.SetLabel( "Label Updated" )
447 def OnChangeValue( self
, event
):
448 self
.bottomcontrol
.SetValue( "r:\\somewhere\\over\\the\\rainbow.htm" )
450 def OnCloseWindow(self
, event
):
453 class DemoApp(wx
.App
):
455 wx
.InitAllImageHandlers()
456 frame
= DemoFrame(None)
458 self
.SetTopWindow(frame
)
464 print 'Creating dialog'