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
):
27 """ A control to allow the user to type in a filename
28 or browse with the standard file dialog to select file
31 parent, id, pos, size -- passed directly to wxPanel initialisation
32 style = wxTAB_TRAVERSAL -- passed directly to wxPanel initialisation
33 labelText -- Text for label to left of text field
34 buttonText -- Text for button which launches the file dialog
36 dialogTitle -- Title used in file dialog
37 startDirectory -- Default directory for file dialog startup
38 fileMask -- File mask (glob pattern, such as *.*) to use in file dialog
39 fileMode -- wxOPEN or wxSAVE, indicates type of file dialog to use
40 changeCallback -- callback receives all > > changes in value of control
42 GetValue() -- retrieve current value of text control
43 SetValue(string) -- set current value of text control
44 label -- pointer to internal label widget
45 textControl -- pointer to internal text control
46 browseButton -- pointer to button
48 def __init__ (self
, parent
, id= -1,
49 pos
= wx
.DefaultPosition
, size
= wx
.DefaultSize
,
50 style
= wx
.TAB_TRAVERSAL
,
51 labelText
= "File Entry:",
53 toolTip
= "Type filename or click browse to choose file",
54 # following are the values for a file dialog box
55 dialogTitle
= "Choose a file",
60 # callback for when value changes (optional)
61 changeCallback
= lambda x
:x
64 self
.labelText
= labelText
65 self
.buttonText
= buttonText
66 self
.toolTip
= toolTip
67 self
.dialogTitle
= dialogTitle
68 self
.startDirectory
= startDirectory
69 self
.initialValue
= initialValue
70 self
.fileMask
= fileMask
71 self
.fileMode
= fileMode
72 self
.changeCallback
= changeCallback
73 self
.callCallback
= True
76 # get background to match it
78 self
._bc
= parent
.GetBackgroundColour()
83 self
.createDialog(parent
, id, pos
, size
, style
)
84 # Setting a value causes the changeCallback to be called.
85 # In this case that would be before the return of the
86 # constructor. Not good. So a default value on
87 # SetValue is used to disable the callback
88 self
.SetValue( initialValue
, 0)
91 def createDialog( self
, parent
, id, pos
, size
, style
):
92 """Setup the graphic representation of the dialog"""
93 wx
.Panel
.__init
__ (self
, parent
, id, pos
, size
, style
)
94 # try to set the background colour
96 self
.SetBackgroundColour(self
._bc
)
99 box
= wx
.BoxSizer(wx
.HORIZONTAL
)
101 self
.label
= self
.createLabel( )
102 box
.Add( self
.label
, 0, wx
.CENTER
)
104 self
.textControl
= self
.createTextControl()
105 box
.Add( self
.textControl
, 1, wx
.LEFT|wx
.CENTER
, 5)
107 self
.browseButton
= self
.createBrowseButton()
108 box
.Add( self
.browseButton
, 0, wx
.LEFT|wx
.CENTER
, 5)
110 # add a border around the whole thing and resize the panel to fit
111 outsidebox
= wx
.BoxSizer(wx
.VERTICAL
)
112 outsidebox
.Add(box
, 1, wx
.EXPAND|wx
.ALL
, 3)
115 self
.SetAutoLayout(True)
116 self
.SetSizer( outsidebox
)
118 if type( size
) == types
.TupleType
:
119 size
= apply( wx
.Size
, size
)
120 self
.SetDimensions(-1, -1, size
.width
, size
.height
, wx
.SIZE_USE_EXISTING
)
122 # if size.width != -1 or size.height != -1:
125 def SetBackgroundColour(self
,color
):
126 wx
.Panel
.SetBackgroundColour(self
,color
)
127 self
.label
.SetBackgroundColour(color
)
129 def createLabel( self
):
130 """Create the label/caption"""
131 label
= wx
.StaticText(self
, -1, self
.labelText
, style
=wx
.ALIGN_RIGHT
)
132 font
= label
.GetFont()
133 w
, h
, d
, e
= self
.GetFullTextExtent(self
.labelText
, font
)
134 label
.SetSize((w
+5, h
))
137 def createTextControl( self
):
138 """Create the text control"""
139 textControl
= wx
.TextCtrl(self
, -1)
140 textControl
.SetToolTipString( self
.toolTip
)
141 if self
.changeCallback
:
142 textControl
.Bind(wx
.EVT_TEXT
, self
.OnChanged
)
143 textControl
.Bind(wx
.EVT_COMBOBOX
, self
.OnChanged
)
146 def OnChanged(self
, evt
):
147 if self
.callCallback
and self
.changeCallback
:
148 self
.changeCallback(evt
)
150 def createBrowseButton( self
):
151 """Create the browse-button control"""
152 button
=wx
.Button(self
, -1, self
.buttonText
)
153 button
.SetToolTipString( self
.toolTip
)
154 button
.Bind(wx
.EVT_BUTTON
, self
.OnBrowse
)
158 def OnBrowse (self
, event
= None):
159 """ Going to browse for file... """
160 current
= self
.GetValue()
161 directory
= os
.path
.split(current
)
162 if os
.path
.isdir( current
):
165 elif directory
and os
.path
.isdir( directory
[0] ):
166 current
= directory
[1]
167 directory
= directory
[0]
169 directory
= self
.startDirectory
170 dlg
= wx
.FileDialog(self
, self
.dialogTitle
, directory
, current
,
171 self
.fileMask
, self
.fileMode
)
173 if dlg
.ShowModal() == wx
.ID_OK
:
174 self
.SetValue(dlg
.GetPath())
179 """ Convenient access to text control value """
180 return self
.textControl
.GetValue()
182 def SetValue (self
, value
, callBack
=1):
183 """ Convenient setting of text control value """
184 save
= self
.callCallback
185 self
.callCallback
= callBack
186 self
.textControl
.SetValue(value
)
187 self
.callCallback
= save
190 def Enable (self
, value
):
191 """ Convenient enabling/disabling of entire control """
192 self
.label
.Enable (value
)
193 self
.textControl
.Enable (value
)
194 return self
.browseButton
.Enable (value
)
196 def GetLabel( self
):
197 """ Retrieve the label's current text """
198 return self
.label
.GetLabel()
200 def SetLabel( self
, value
):
201 """ Set the label's current text """
202 rvalue
= self
.label
.SetLabel( value
)
209 class FileBrowseButtonWithHistory( FileBrowseButton
):
210 """ with following additions:
211 __init__(..., history=None)
213 history -- optional list of paths for initial history drop-down
214 (must be passed by name, not a positional argument)
215 If history is callable it will must return a list used
216 for the history drop-down
217 changeCallback -- as for FileBrowseButton, but with a work-around
218 for win32 systems which don't appear to create wx.EVT_COMBOBOX
219 events properly. There is a (slight) chance that this work-around
220 will cause some systems to create two events for each Combobox
221 selection. If you discover this condition, please report it!
222 As for a FileBrowseButton.__init__ otherwise.
224 Return reference to the control which implements interfaces
225 required for manipulating the history list. See GetHistoryControl
226 documentation for description of what that interface is.
228 Return current history list
229 SetHistory( value=(), selectionIndex = None )
230 Set current history list, if selectionIndex is not None, select that index
232 def __init__( self
, *arguments
, **namedarguments
):
233 self
.history
= namedarguments
.get( "history" )
235 del namedarguments
["history"]
237 self
.historyCallBack
=None
238 if callable(self
.history
):
239 self
.historyCallBack
=self
.history
241 apply( FileBrowseButton
.__init
__, ( self
,)+arguments
, namedarguments
)
244 def createTextControl( self
):
245 """Create the text control"""
246 textControl
= wx
.ComboBox(self
, -1, style
= wx
.CB_DROPDOWN
)
247 textControl
.SetToolTipString( self
.toolTip
)
248 textControl
.Bind(wx
.EVT_SET_FOCUS
, self
.OnSetFocus
)
249 if self
.changeCallback
:
250 textControl
.Bind(wx
.EVT_TEXT
, self
.changeCallback
)
251 textControl
.Bind(wx
.EVT_COMBOBOX
, self
.changeCallback
)
255 self
.SetHistory( history
, control
=textControl
)
259 def GetHistoryControl( self
):
260 """Return a pointer to the control which provides (at least)
261 the following methods for manipulating the history list.:
262 Append( item ) -- add item
263 Clear() -- clear all items
264 Delete( index ) -- 0-based index to delete from list
265 SetSelection( index ) -- 0-based index to select in list
266 Semantics of the methods follow those for the wxComboBox control
268 return self
.textControl
271 def SetHistory( self
, value
=(), selectionIndex
= None, control
=None ):
272 """Set the current history list"""
274 control
= self
.GetHistoryControl()
275 if self
.history
== value
:
278 # Clear history values not the selected one.
279 tempValue
=control
.GetValue()
280 # clear previous values
282 control
.SetValue(tempValue
)
283 # walk through, appending new values
285 control
.Append( path
)
286 if selectionIndex
is not None:
287 control
.SetSelection( selectionIndex
)
290 def GetHistory( self
):
291 """Return the current history list"""
292 if self
.historyCallBack
!= None:
293 return self
.historyCallBack()
295 return list( self
.history
)
298 def OnSetFocus(self
, event
):
299 """When the history scroll is selected, update the history"""
300 if self
.historyCallBack
!= None:
301 self
.SetHistory( self
.historyCallBack(), control
=self
.textControl
)
305 if wx
.Platform
== "__WXMSW__":
306 def SetValue (self
, value
, callBack
=1):
307 """ Convenient setting of text control value, works
308 around limitation of wx.ComboBox """
309 save
= self
.callCallback
310 self
.callCallback
= callBack
311 self
.textControl
.SetValue(value
)
312 self
.callCallback
= save
314 # Hack to call an event handler
316 def __init__(self
, string
):
321 # The callback wasn't being called when SetValue was used ??
322 # So added this explicit call to it
323 self
.changeCallback(LocalEvent(value
))
326 class DirBrowseButton(FileBrowseButton
):
327 def __init__(self
, parent
, id = -1,
328 pos
= wx
.DefaultPosition
, size
= wx
.DefaultSize
,
329 style
= wx
.TAB_TRAVERSAL
,
330 labelText
= 'Select a directory:',
331 buttonText
= 'Browse',
332 toolTip
= 'Type directory name or browse to select',
334 startDirectory
= '.',
335 changeCallback
= None,
336 dialogClass
= wx
.DirDialog
):
337 FileBrowseButton
.__init
__(self
, parent
, id, pos
, size
, style
,
338 labelText
, buttonText
, toolTip
,
339 dialogTitle
, startDirectory
,
340 changeCallback
= changeCallback
)
342 self
._dirDialog
= dialogClass(self
,
343 message
= dialogTitle
,
344 defaultPath
= startDirectory
)
346 def OnBrowse(self
, ev
= None):
347 dialog
= self
._dirDialog
348 if dialog
.ShowModal() == wx
.ID_OK
:
349 self
.SetValue(dialog
.GetPath())
352 if self
.__dict
__.has_key('_dirDialog'):
353 self
._dirDialog
.Destroy()
356 #----------------------------------------------------------------------
359 if __name__
== "__main__":
360 #from skeletonbuilder import rulesfile
361 class SimpleCallback
:
362 def __init__( self
, tag
):
364 def __call__( self
, event
):
365 print self
.tag
, event
.GetString()
366 class DemoFrame( wx
.Frame
):
367 def __init__(self
, parent
):
368 wx
.Frame
.__init
__(self
, parent
, -1, "File entry with browse", size
=(500,260))
369 self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
)
370 panel
= wx
.Panel (self
,-1)
371 innerbox
= wx
.BoxSizer(wx
.VERTICAL
)
372 control
= FileBrowseButton(
374 initialValue
= "z:\\temp",
376 innerbox
.Add( control
, 0, wx
.EXPAND
)
377 middlecontrol
= FileBrowseButtonWithHistory(
379 labelText
= "With History",
380 initialValue
= "d:\\temp",
381 history
= ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"],
382 changeCallback
= SimpleCallback( "With History" ),
384 innerbox
.Add( middlecontrol
, 0, wx
.EXPAND
)
385 middlecontrol
= FileBrowseButtonWithHistory(
387 labelText
= "History callback",
388 initialValue
= "d:\\temp",
389 history
= self
.historyCallBack
,
390 changeCallback
= SimpleCallback( "History callback" ),
392 innerbox
.Add( middlecontrol
, 0, wx
.EXPAND
)
393 self
.bottomcontrol
= control
= FileBrowseButton(
395 labelText
= "With Callback",
396 style
= wx
.SUNKEN_BORDER|wx
.CLIP_CHILDREN
,
397 changeCallback
= SimpleCallback( "With Callback" ),
399 innerbox
.Add( control
, 0, wx
.EXPAND
)
400 self
.bottommostcontrol
= control
= DirBrowseButton(
402 labelText
= "Simple dir browse button",
403 style
= wx
.SUNKEN_BORDER|wx
.CLIP_CHILDREN
)
404 innerbox
.Add( control
, 0, wx
.EXPAND
)
406 innerbox
.Add( wx
.Button( panel
, ID
,"Change Label", ), 1, wx
.EXPAND
)
407 self
.Bind(wx
.EVT_BUTTON
, self
.OnChangeLabel
, id=ID
)
409 innerbox
.Add( wx
.Button( panel
, ID
,"Change Value", ), 1, wx
.EXPAND
)
410 self
.Bind(wx
.EVT_BUTTON
, self
.OnChangeValue
, id=ID
)
411 panel
.SetAutoLayout(True)
412 panel
.SetSizer( innerbox
)
413 self
.history
={"c:\\temp":1, "c:\\tmp":1, "r:\\temp":1,"z:\\temp":1}
415 def historyCallBack(self
):
416 keys
=self
.history
.keys()
420 def OnFileNameChangedHistory (self
, event
):
421 self
.history
[event
.GetString ()]=1
423 def OnCloseMe(self
, event
):
425 def OnChangeLabel( self
, event
):
426 self
.bottomcontrol
.SetLabel( "Label Updated" )
427 def OnChangeValue( self
, event
):
428 self
.bottomcontrol
.SetValue( "r:\\somewhere\\over\\the\\rainbow.htm" )
430 def OnCloseWindow(self
, event
):
433 class DemoApp(wx
.App
):
435 wx
.InitAllImageHandlers()
436 frame
= DemoFrame(None)
438 self
.SetTopWindow(frame
)
444 print 'Creating dialog'