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
72 self
.createDialog(parent
, id, pos
, size
, style
)
73 # Setting a value causes the changeCallback to be called.
74 # In this case that would be before the return of the
75 # constructor. Not good. So a default value on
76 # SetValue is used to disable the callback
77 self
.SetValue( initialValue
, 0)
80 def createDialog( self
, parent
, id, pos
, size
, style
):
81 """Setup the graphic representation of the dialog"""
82 wx
.Panel
.__init
__ (self
, parent
, id, pos
, size
, style
)
83 self
.SetMinSize(size
) # play nice with sizers
85 box
= wx
.BoxSizer(wx
.HORIZONTAL
)
87 self
.label
= self
.createLabel( )
88 box
.Add( self
.label
, 0, wx
.CENTER
)
90 self
.textControl
= self
.createTextControl()
91 box
.Add( self
.textControl
, 1, wx
.LEFT|wx
.CENTER
, 5)
93 self
.browseButton
= self
.createBrowseButton()
94 box
.Add( self
.browseButton
, 0, wx
.LEFT|wx
.CENTER
, 5)
96 # add a border around the whole thing and resize the panel to fit
97 outsidebox
= wx
.BoxSizer(wx
.VERTICAL
)
98 outsidebox
.Add(box
, 1, wx
.EXPAND|wx
.ALL
, 3)
101 self
.SetAutoLayout(True)
102 self
.SetSizer( outsidebox
)
104 if type( size
) == types
.TupleType
:
105 size
= apply( wx
.Size
, size
)
106 self
.SetDimensions(-1, -1, size
.width
, size
.height
, wx
.SIZE_USE_EXISTING
)
108 # if size.width != -1 or size.height != -1:
111 def SetBackgroundColour(self
,color
):
112 wx
.Panel
.SetBackgroundColour(self
,color
)
113 self
.label
.SetBackgroundColour(color
)
115 def createLabel( self
):
116 """Create the label/caption"""
117 label
= wx
.StaticText(self
, -1, self
.labelText
, style
=wx
.ALIGN_RIGHT
)
118 font
= label
.GetFont()
119 w
, h
, d
, e
= self
.GetFullTextExtent(self
.labelText
, font
)
120 label
.SetSize((w
+5, h
))
123 def createTextControl( self
):
124 """Create the text control"""
125 textControl
= wx
.TextCtrl(self
, -1)
126 textControl
.SetToolTipString( self
.toolTip
)
127 if self
.changeCallback
:
128 textControl
.Bind(wx
.EVT_TEXT
, self
.OnChanged
)
129 textControl
.Bind(wx
.EVT_COMBOBOX
, self
.OnChanged
)
132 def OnChanged(self
, evt
):
133 if self
.callCallback
and self
.changeCallback
:
134 self
.changeCallback(evt
)
136 def createBrowseButton( self
):
137 """Create the browse-button control"""
138 button
=wx
.Button(self
, -1, self
.buttonText
)
139 button
.SetToolTipString( self
.toolTip
)
140 button
.Bind(wx
.EVT_BUTTON
, self
.OnBrowse
)
144 def OnBrowse (self
, event
= None):
145 """ Going to browse for file... """
146 current
= self
.GetValue()
147 directory
= os
.path
.split(current
)
148 if os
.path
.isdir( current
):
151 elif directory
and os
.path
.isdir( directory
[0] ):
152 current
= directory
[1]
153 directory
= directory
[0]
155 directory
= self
.startDirectory
156 dlg
= wx
.FileDialog(self
, self
.dialogTitle
, directory
, current
,
157 self
.fileMask
, self
.fileMode
)
159 if dlg
.ShowModal() == wx
.ID_OK
:
160 self
.SetValue(dlg
.GetPath())
166 retrieve current value of text control
168 return self
.textControl
.GetValue()
170 def SetValue (self
, value
, callBack
=1):
171 """set current value of text control"""
172 save
= self
.callCallback
173 self
.callCallback
= callBack
174 self
.textControl
.SetValue(value
)
175 self
.callCallback
= save
178 def Enable (self
, value
):
179 """ Convenient enabling/disabling of entire control """
180 self
.label
.Enable (value
)
181 self
.textControl
.Enable (value
)
182 return self
.browseButton
.Enable (value
)
184 def GetLabel( self
):
185 """ Retrieve the label's current text """
186 return self
.label
.GetLabel()
188 def SetLabel( self
, value
):
189 """ Set the label's current text """
190 rvalue
= self
.label
.SetLabel( value
)
197 class FileBrowseButtonWithHistory( FileBrowseButton
):
199 with following additions:
200 __init__(..., history=None)
202 history -- optional list of paths for initial history drop-down
203 (must be passed by name, not a positional argument)
204 If history is callable it will must return a list used
205 for the history drop-down
207 changeCallback -- as for FileBrowseButton, but with a work-around
208 for win32 systems which don't appear to create wx.EVT_COMBOBOX
209 events properly. There is a (slight) chance that this work-around
210 will cause some systems to create two events for each Combobox
211 selection. If you discover this condition, please report it!
213 As for a FileBrowseButton.__init__ otherwise.
216 Return reference to the control which implements interfaces
217 required for manipulating the history list. See GetHistoryControl
218 documentation for description of what that interface is.
221 Return current history list
223 SetHistory( value=(), selectionIndex = None )
224 Set current history list, if selectionIndex is not None, select that index
227 def __init__( self
, *arguments
, **namedarguments
):
228 self
.history
= namedarguments
.get( "history" )
230 del namedarguments
["history"]
232 self
.historyCallBack
=None
233 if callable(self
.history
):
234 self
.historyCallBack
=self
.history
236 apply( FileBrowseButton
.__init
__, ( self
,)+arguments
, namedarguments
)
239 def createTextControl( self
):
240 """Create the text control"""
241 textControl
= wx
.ComboBox(self
, -1, style
= wx
.CB_DROPDOWN
)
242 textControl
.SetToolTipString( self
.toolTip
)
243 textControl
.Bind(wx
.EVT_SET_FOCUS
, self
.OnSetFocus
)
244 if self
.changeCallback
:
245 textControl
.Bind(wx
.EVT_TEXT
, self
.changeCallback
)
246 textControl
.Bind(wx
.EVT_COMBOBOX
, self
.changeCallback
)
250 self
.SetHistory( history
, control
=textControl
)
254 def GetHistoryControl( self
):
256 Return a pointer to the control which provides (at least)
257 the following methods for manipulating the history list:
259 Append( item ) -- add item
260 Clear() -- clear all items
261 Delete( index ) -- 0-based index to delete from list
262 SetSelection( index ) -- 0-based index to select in list
264 Semantics of the methods follow those for the wxComboBox control
266 return self
.textControl
269 def SetHistory( self
, value
=(), selectionIndex
= None, control
=None ):
270 """Set the current history list"""
272 control
= self
.GetHistoryControl()
273 if self
.history
== value
:
276 # Clear history values not the selected one.
277 tempValue
=control
.GetValue()
278 # clear previous values
280 control
.SetValue(tempValue
)
281 # walk through, appending new values
283 control
.Append( path
)
284 if selectionIndex
is not None:
285 control
.SetSelection( selectionIndex
)
288 def GetHistory( self
):
289 """Return the current history list"""
290 if self
.historyCallBack
!= None:
291 return self
.historyCallBack()
293 return list( self
.history
)
296 def OnSetFocus(self
, event
):
297 """When the history scroll is selected, update the history"""
298 if self
.historyCallBack
!= None:
299 self
.SetHistory( self
.historyCallBack(), control
=self
.textControl
)
303 if wx
.Platform
== "__WXMSW__":
304 def SetValue (self
, value
, callBack
=1):
305 """ Convenient setting of text control value, works
306 around limitation of wx.ComboBox """
307 save
= self
.callCallback
308 self
.callCallback
= callBack
309 self
.textControl
.SetValue(value
)
310 self
.callCallback
= save
312 # Hack to call an event handler
314 def __init__(self
, string
):
319 # The callback wasn't being called when SetValue was used ??
320 # So added this explicit call to it
321 self
.changeCallback(LocalEvent(value
))
324 class DirBrowseButton(FileBrowseButton
):
325 def __init__(self
, parent
, id = -1,
326 pos
= wx
.DefaultPosition
, size
= wx
.DefaultSize
,
327 style
= wx
.TAB_TRAVERSAL
,
328 labelText
= 'Select a directory:',
329 buttonText
= 'Browse',
330 toolTip
= 'Type directory name or browse to select',
332 startDirectory
= '.',
333 changeCallback
= None,
334 dialogClass
= wx
.DirDialog
,
335 newDirectory
= False):
336 FileBrowseButton
.__init
__(self
, parent
, id, pos
, size
, style
,
337 labelText
, buttonText
, toolTip
,
338 dialogTitle
, startDirectory
,
339 changeCallback
= changeCallback
)
340 self
.dialogClass
= dialogClass
341 self
.newDirectory
= newDirectory
344 def OnBrowse(self
, ev
= None):
347 if self
.newDirectory
:
348 style|
=wx
.DD_NEW_DIR_BUTTON
350 dialog
= self
.dialogClass(self
,
351 message
= self
.dialogTitle
,
352 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'