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, wxCENTER
)
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 size
.width
!= -1 or size
.height
!= -1:
115 def SetBackgroundColour(self
,color
):
116 wxPanel
.SetBackgroundColour(self
,color
)
117 self
.label
.SetBackgroundColour(color
)
119 def createLabel( self
):
120 """Create the label/caption"""
121 label
= wxStaticText(self
, -1, self
.labelText
, style
=wxALIGN_RIGHT
)
122 font
= label
.GetFont()
123 w
, h
, d
, e
= self
.GetFullTextExtent(self
.labelText
, font
)
124 label
.SetSize(wxSize(w
+5, h
))
127 def createTextControl( self
):
128 """Create the text control"""
130 textControl
= wxTextCtrl(self
, ID
)
131 textControl
.SetToolTipString( self
.toolTip
)
132 if self
.changeCallback
:
133 EVT_TEXT(textControl
, ID
, self
.OnChanged
)
134 EVT_COMBOBOX(textControl
, ID
, self
.OnChanged
)
137 def OnChanged(self
, evt
):
138 if self
.callCallback
and self
.changeCallback
:
139 self
.changeCallback(evt
)
141 def createBrowseButton( self
):
142 """Create the browse-button control"""
144 button
=wxButton(self
, ID
, self
.buttonText
)
145 button
.SetToolTipString( self
.toolTip
)
146 EVT_BUTTON(button
, ID
, self
.OnBrowse
)
150 def OnBrowse (self
, event
= None):
151 """ Going to browse for file... """
152 current
= self
.GetValue()
153 directory
= os
.path
.split(current
)
154 if os
.path
.isdir( current
):
157 elif directory
and os
.path
.isdir( directory
[0] ):
158 current
= directory
[1]
159 directory
= directory
[0]
161 directory
= self
.startDirectory
162 dlg
= wxFileDialog(self
, self
.dialogTitle
, directory
, current
, self
.fileMask
, self
.fileMode
)
164 if dlg
.ShowModal() == wxID_OK
:
165 self
.SetValue(dlg
.GetPath())
170 """ Convenient access to text control value """
171 return self
.textControl
.GetValue()
173 def SetValue (self
, value
, callBack
=1):
174 """ Convenient setting of text control value """
175 save
= self
.callCallback
176 self
.callCallback
= callBack
177 self
.textControl
.SetValue(value
)
178 self
.callCallback
= save
181 def Enable (self
, value
):
182 """ Convenient enabling/disabling of entire control """
183 self
.label
.Enable (value
)
184 self
.textControl
.Enable (value
)
185 return self
.browseButton
.Enable (value
)
187 def GetLabel( self
):
188 """ Retrieve the label's current text """
189 return self
.label
.GetLabel()
191 def SetLabel( self
, value
):
192 """ Set the label's current text """
193 rvalue
= self
.label
.SetLabel( value
)
200 class FileBrowseButtonWithHistory( FileBrowseButton
):
201 """ with following additions:
202 __init__(..., history=None)
204 history -- optional list of paths for initial history drop-down
205 (must be passed by name, not a positional argument)
206 If history is callable it will must return a list used
207 for the history drop-down
208 changeCallback -- as for FileBrowseButton, but with a work-around
209 for win32 systems which don't appear to create EVT_COMBOBOX
210 events properly. There is a (slight) chance that this work-around
211 will cause some systems to create two events for each Combobox
212 selection. If you discover this condition, please report it!
213 As for a FileBrowseButton.__init__ otherwise.
215 Return reference to the control which implements interfaces
216 required for manipulating the history list. See GetHistoryControl
217 documentation for description of what that interface is.
219 Return current history list
220 SetHistory( value=(), selectionIndex = None )
221 Set current history list, if selectionIndex is not None, select that index
223 def __init__( self
, *arguments
, **namedarguments
):
224 self
.history
= namedarguments
.get( "history" )
226 del namedarguments
["history"]
228 self
.historyCallBack
=None
229 if callable(self
.history
):
230 self
.historyCallBack
=self
.history
232 apply( FileBrowseButton
.__init
__, ( self
,)+arguments
, namedarguments
)
235 def createTextControl( self
):
236 """Create the text control"""
238 textControl
= wxComboBox(self
, ID
, style
= wxCB_DROPDOWN
)
239 textControl
.SetToolTipString( self
.toolTip
)
240 EVT_SET_FOCUS(textControl
, self
.OnSetFocus
)
241 if self
.changeCallback
:
242 EVT_TEXT(textControl
, ID
, self
.changeCallback
)
243 EVT_COMBOBOX(textControl
, ID
, self
.changeCallback
)
247 self
.SetHistory( history
, control
=textControl
)
251 def GetHistoryControl( self
):
252 """Return a pointer to the control which provides (at least)
253 the following methods for manipulating the history list.:
254 Append( item ) -- add item
255 Clear() -- clear all items
256 Delete( index ) -- 0-based index to delete from list
257 SetSelection( index ) -- 0-based index to select in list
258 Semantics of the methods follow those for the wxComboBox control
260 return self
.textControl
263 def SetHistory( self
, value
=(), selectionIndex
= None, control
=None ):
264 """Set the current history list"""
266 control
= self
.GetHistoryControl()
267 if self
.history
== value
:
270 # Clear history values not the selected one.
271 tempValue
=control
.GetValue()
272 # clear previous values
274 control
.SetValue(tempValue
)
275 # walk through, appending new values
277 control
.Append( path
)
278 if selectionIndex
is not None:
279 control
.SetSelection( selectionIndex
)
282 def GetHistory( self
):
283 """Return the current history list"""
284 if self
.historyCallBack
!= None:
285 return self
.historyCallBack()
287 return list( self
.history
)
290 def OnSetFocus(self
, event
):
291 """When the history scroll is selected, update the history"""
292 if self
.historyCallBack
!= None:
293 self
.SetHistory( self
.historyCallBack(), control
=self
.textControl
)
297 if wxPlatform
== "__WXMSW__":
298 def SetValue (self
, value
, callBack
=1):
299 """ Convenient setting of text control value, works
300 around limitation of wxComboBox """
301 save
= self
.callCallback
302 self
.callCallback
= callBack
303 self
.textControl
.SetValue(value
)
304 self
.callCallback
= save
306 # Hack to call an event handler
308 def __init__(self
, string
):
313 # The callback wasn't being called when SetValue was used ??
314 # So added this explicit call to it
315 self
.changeCallback(LocalEvent(value
))
318 class DirBrowseButton(FileBrowseButton
):
319 def __init__(self
, parent
, id = -1,
320 pos
= wxDefaultPosition
, size
= wxDefaultSize
,
321 style
= wxTAB_TRAVERSAL
,
322 labelText
= 'Select a directory:',
323 buttonText
= 'Browse',
324 toolTip
= 'Type directory name or browse to select',
326 startDirectory
= '.',
327 changeCallback
= None,
328 dialogClass
= wxDirDialog
):
329 FileBrowseButton
.__init
__(self
, parent
, id, pos
, size
, style
,
330 labelText
, buttonText
, toolTip
,
331 dialogTitle
, startDirectory
,
332 changeCallback
= changeCallback
)
334 self
._dirDialog
= dialogClass(self
,
335 message
= dialogTitle
,
336 defaultPath
= startDirectory
)
338 def OnBrowse(self
, ev
= None):
339 dialog
= self
._dirDialog
340 if dialog
.ShowModal() == wxID_OK
:
341 self
.SetValue(dialog
.GetPath())
344 if self
.__dict
__.has_key('_dirDialog'):
345 self
._dirDialog
.Destroy()
348 #----------------------------------------------------------------------
351 if __name__
== "__main__":
352 #from skeletonbuilder import rulesfile
353 class SimpleCallback
:
354 def __init__( self
, tag
):
356 def __call__( self
, event
):
357 print self
.tag
, event
.GetString()
358 class DemoFrame( wxFrame
):
359 def __init__(self
, parent
):
360 wxFrame
.__init
__(self
, parent
, 2400, "File entry with browse", size
=(500,260) )
361 EVT_CLOSE(self
, self
.OnCloseWindow
)
362 panel
= wxPanel (self
,-1)
363 innerbox
= wxBoxSizer(wxVERTICAL
)
364 control
= FileBrowseButton(
366 initialValue
= "z:\\temp",
368 innerbox
.Add( control
, 0, wxEXPAND
)
369 middlecontrol
= FileBrowseButtonWithHistory(
371 labelText
= "With History",
372 initialValue
= "d:\\temp",
373 history
= ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"],
374 changeCallback
= SimpleCallback( "With History" ),
376 innerbox
.Add( middlecontrol
, 0, wxEXPAND
)
377 middlecontrol
= FileBrowseButtonWithHistory(
379 labelText
= "History callback",
380 initialValue
= "d:\\temp",
381 history
= self
.historyCallBack
,
382 changeCallback
= SimpleCallback( "History callback" ),
384 innerbox
.Add( middlecontrol
, 0, wxEXPAND
)
385 self
.bottomcontrol
= control
= FileBrowseButton(
387 labelText
= "With Callback",
388 style
= wxSUNKEN_BORDER|wxCLIP_CHILDREN
,
389 changeCallback
= SimpleCallback( "With Callback" ),
391 innerbox
.Add( control
, 0, wxEXPAND
)
392 self
.bottommostcontrol
= control
= DirBrowseButton(
394 labelText
= "Simple dir browse button",
395 style
= wxSUNKEN_BORDER|wxCLIP_CHILDREN
)
396 innerbox
.Add( control
, 0, wxEXPAND
)
398 innerbox
.Add( wxButton( panel
, ID
,"Change Label", ), 1, wxEXPAND
)
399 EVT_BUTTON( self
, ID
, self
.OnChangeLabel
)
401 innerbox
.Add( wxButton( panel
, ID
,"Change Value", ), 1, wxEXPAND
)
402 EVT_BUTTON( self
, ID
, self
.OnChangeValue
)
403 panel
.SetAutoLayout(true
)
404 panel
.SetSizer( innerbox
)
405 self
.history
={"c:\\temp":1, "c:\\tmp":1, "r:\\temp":1,"z:\\temp":1}
407 def historyCallBack(self
):
408 keys
=self
.history
.keys()
412 def OnFileNameChangedHistory (self
, event
):
413 self
.history
[event
.GetString ()]=1
415 def OnCloseMe(self
, event
):
417 def OnChangeLabel( self
, event
):
418 self
.bottomcontrol
.SetLabel( "Label Updated" )
419 def OnChangeValue( self
, event
):
420 self
.bottomcontrol
.SetValue( "r:\\somewhere\\over\\the\\rainbow.htm" )
422 def OnCloseWindow(self
, event
):
425 class DemoApp(wxApp
):
427 wxImage_AddHandler(wxJPEGHandler())
428 wxImage_AddHandler(wxPNGHandler())
429 wxImage_AddHandler(wxGIFHandler())
430 frame
= DemoFrame(NULL
)
431 #frame = RulesPanel(NULL )
433 self
.SetTopWindow(frame
)
439 print 'Creating dialog'