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 #----------------------------------------------------------------------
15 from wxPython
.wx
import *
18 #----------------------------------------------------------------------
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
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
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
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
42 def __init__ (self
, parent
, id= -1,
43 pos
= wxDefaultPosition
, size
= wxDefaultSize
,
44 style
= wxTAB_TRAVERSAL
,
45 labelText
= "File Entry:",
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",
54 # callback for when value changes (optional)
55 changeCallback
= lambda x
:x
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
70 # get background to match it
72 self
._bc
= parent
.GetBackgroundColour()
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)
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
90 self
.SetBackgroundColour(self
._bc
)
93 box
= wxBoxSizer(wxHORIZONTAL
)
95 self
.label
= self
.createLabel( )
96 box
.Add( self
.label
, 0, wxCENTER
)
98 self
.textControl
= self
.createTextControl()
99 box
.Add( self
.textControl
, 1, wxLEFT|wxCENTER
, 5)
101 self
.browseButton
= self
.createBrowseButton()
102 box
.Add( self
.browseButton
, 0, wxLEFT|wxCENTER
, 5)
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)
109 self
.SetAutoLayout(True)
110 self
.SetSizer( outsidebox
)
112 if type( size
) == types
.TupleType
:
113 size
= apply( wxSize
, size
)
114 self
.SetDimensions(-1, -1, size
.width
, size
.height
, wxSIZE_USE_EXISTING
)
116 # if size.width != -1 or size.height != -1:
119 def SetBackgroundColour(self
,color
):
120 wxPanel
.SetBackgroundColour(self
,color
)
121 self
.label
.SetBackgroundColour(color
)
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
))
131 def createTextControl( self
):
132 """Create the text control"""
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
)
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"""
148 button
=wxButton(self
, ID
, self
.buttonText
)
149 button
.SetToolTipString( self
.toolTip
)
150 EVT_BUTTON(button
, ID
, self
.OnBrowse
)
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
):
161 elif directory
and os
.path
.isdir( directory
[0] ):
162 current
= directory
[1]
163 directory
= directory
[0]
165 directory
= self
.startDirectory
166 dlg
= wxFileDialog(self
, self
.dialogTitle
, directory
, current
, self
.fileMask
, self
.fileMode
)
168 if dlg
.ShowModal() == wxID_OK
:
169 self
.SetValue(dlg
.GetPath())
174 """ Convenient access to text control value """
175 return self
.textControl
.GetValue()
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
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
)
191 def GetLabel( self
):
192 """ Retrieve the label's current text """
193 return self
.label
.GetLabel()
195 def SetLabel( self
, value
):
196 """ Set the label's current text """
197 rvalue
= self
.label
.SetLabel( value
)
204 class FileBrowseButtonWithHistory( FileBrowseButton
):
205 """ with following additions:
206 __init__(..., history=None)
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.
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.
223 Return current history list
224 SetHistory( value=(), selectionIndex = None )
225 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"""
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
)
251 self
.SetHistory( history
, control
=textControl
)
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
264 return self
.textControl
267 def SetHistory( self
, value
=(), selectionIndex
= None, control
=None ):
268 """Set the current history list"""
270 control
= self
.GetHistoryControl()
271 if self
.history
== value
:
274 # Clear history values not the selected one.
275 tempValue
=control
.GetValue()
276 # clear previous values
278 control
.SetValue(tempValue
)
279 # walk through, appending new values
281 control
.Append( path
)
282 if selectionIndex
is not None:
283 control
.SetSelection( selectionIndex
)
286 def GetHistory( self
):
287 """Return the current history list"""
288 if self
.historyCallBack
!= None:
289 return self
.historyCallBack()
291 return list( self
.history
)
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
)
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
310 # Hack to call an event handler
312 def __init__(self
, string
):
317 # The callback wasn't being called when SetValue was used ??
318 # So added this explicit call to it
319 self
.changeCallback(LocalEvent(value
))
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',
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
)
338 self
._dirDialog
= dialogClass(self
,
339 message
= dialogTitle
,
340 defaultPath
= startDirectory
)
342 def OnBrowse(self
, ev
= None):
343 dialog
= self
._dirDialog
344 if dialog
.ShowModal() == wxID_OK
:
345 self
.SetValue(dialog
.GetPath())
348 if self
.__dict
__.has_key('_dirDialog'):
349 self
._dirDialog
.Destroy()
352 #----------------------------------------------------------------------
355 if __name__
== "__main__":
356 #from skeletonbuilder import rulesfile
357 class SimpleCallback
:
358 def __init__( self
, 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(
370 initialValue
= "z:\\temp",
372 innerbox
.Add( control
, 0, wxEXPAND
)
373 middlecontrol
= FileBrowseButtonWithHistory(
375 labelText
= "With History",
376 initialValue
= "d:\\temp",
377 history
= ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"],
378 changeCallback
= SimpleCallback( "With History" ),
380 innerbox
.Add( middlecontrol
, 0, wxEXPAND
)
381 middlecontrol
= FileBrowseButtonWithHistory(
383 labelText
= "History callback",
384 initialValue
= "d:\\temp",
385 history
= self
.historyCallBack
,
386 changeCallback
= SimpleCallback( "History callback" ),
388 innerbox
.Add( middlecontrol
, 0, wxEXPAND
)
389 self
.bottomcontrol
= control
= FileBrowseButton(
391 labelText
= "With Callback",
392 style
= wxSUNKEN_BORDER|wxCLIP_CHILDREN
,
393 changeCallback
= SimpleCallback( "With Callback" ),
395 innerbox
.Add( control
, 0, wxEXPAND
)
396 self
.bottommostcontrol
= control
= DirBrowseButton(
398 labelText
= "Simple dir browse button",
399 style
= wxSUNKEN_BORDER|wxCLIP_CHILDREN
)
400 innerbox
.Add( control
, 0, wxEXPAND
)
402 innerbox
.Add( wxButton( panel
, ID
,"Change Label", ), 1, wxEXPAND
)
403 EVT_BUTTON( self
, ID
, self
.OnChangeLabel
)
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}
411 def historyCallBack(self
):
412 keys
=self
.history
.keys()
416 def OnFileNameChangedHistory (self
, event
):
417 self
.history
[event
.GetString ()]=1
419 def OnCloseMe(self
, event
):
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" )
426 def OnCloseWindow(self
, event
):
429 class DemoApp(wxApp
):
431 wxImage_AddHandler(wxJPEGHandler())
432 wxImage_AddHandler(wxPNGHandler())
433 wxImage_AddHandler(wxGIFHandler())
434 frame
= DemoFrame(NULL
)
435 #frame = RulesPanel(NULL )
437 self
.SetTopWindow(frame
)
443 print 'Creating dialog'