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 type( size
) == types
.TupleType
:
113 size
= apply( wxSize
, size
)
114 if size
.width
!= -1 or size
.height
!= -1:
117 def SetBackgroundColour(self
,color
):
118 wxPanel
.SetBackgroundColour(self
,color
)
119 self
.label
.SetBackgroundColour(color
)
121 def createLabel( self
):
122 """Create the label/caption"""
123 label
= wxStaticText(self
, -1, self
.labelText
, style
=wxALIGN_RIGHT
)
124 font
= label
.GetFont()
125 w
, h
, d
, e
= self
.GetFullTextExtent(self
.labelText
, font
)
126 label
.SetSize(wxSize(w
+5, h
))
129 def createTextControl( self
):
130 """Create the text control"""
132 textControl
= wxTextCtrl(self
, ID
)
133 textControl
.SetToolTipString( self
.toolTip
)
134 if self
.changeCallback
:
135 EVT_TEXT(textControl
, ID
, self
.OnChanged
)
136 EVT_COMBOBOX(textControl
, ID
, self
.OnChanged
)
139 def OnChanged(self
, evt
):
140 if self
.callCallback
and self
.changeCallback
:
141 self
.changeCallback(evt
)
143 def createBrowseButton( self
):
144 """Create the browse-button control"""
146 button
=wxButton(self
, ID
, self
.buttonText
)
147 button
.SetToolTipString( self
.toolTip
)
148 EVT_BUTTON(button
, ID
, self
.OnBrowse
)
152 def OnBrowse (self
, event
= None):
153 """ Going to browse for file... """
154 current
= self
.GetValue()
155 directory
= os
.path
.split(current
)
156 if os
.path
.isdir( current
):
159 elif directory
and os
.path
.isdir( directory
[0] ):
160 current
= directory
[1]
161 directory
= directory
[0]
163 directory
= self
.startDirectory
164 dlg
= wxFileDialog(self
, self
.dialogTitle
, directory
, current
, self
.fileMask
, self
.fileMode
)
166 if dlg
.ShowModal() == wxID_OK
:
167 self
.SetValue(dlg
.GetPath())
172 """ Convenient access to text control value """
173 return self
.textControl
.GetValue()
175 def SetValue (self
, value
, callBack
=1):
176 """ Convenient setting of text control value """
177 save
= self
.callCallback
178 self
.callCallback
= callBack
179 self
.textControl
.SetValue(value
)
180 self
.callCallback
= save
183 def Enable (self
, value
):
184 """ Convenient enabling/disabling of entire control """
185 self
.label
.Enable (value
)
186 self
.textControl
.Enable (value
)
187 return self
.browseButton
.Enable (value
)
189 def GetLabel( self
):
190 """ Retrieve the label's current text """
191 return self
.label
.GetLabel()
193 def SetLabel( self
, value
):
194 """ Set the label's current text """
195 rvalue
= self
.label
.SetLabel( value
)
202 class FileBrowseButtonWithHistory( FileBrowseButton
):
203 """ with following additions:
204 __init__(..., history=None)
206 history -- optional list of paths for initial history drop-down
207 (must be passed by name, not a positional argument)
208 If history is callable it will must return a list used
209 for the history drop-down
210 changeCallback -- as for FileBrowseButton, but with a work-around
211 for win32 systems which don't appear to create EVT_COMBOBOX
212 events properly. There is a (slight) chance that this work-around
213 will cause some systems to create two events for each Combobox
214 selection. If you discover this condition, please report it!
215 As for a FileBrowseButton.__init__ otherwise.
217 Return reference to the control which implements interfaces
218 required for manipulating the history list. See GetHistoryControl
219 documentation for description of what that interface is.
221 Return current history list
222 SetHistory( value=(), selectionIndex = None )
223 Set current history list, if selectionIndex is not None, select that index
225 def __init__( self
, *arguments
, **namedarguments
):
226 self
.history
= namedarguments
.get( "history" )
228 del namedarguments
["history"]
230 self
.historyCallBack
=None
231 if callable(self
.history
):
232 self
.historyCallBack
=self
.history
234 apply( FileBrowseButton
.__init
__, ( self
,)+arguments
, namedarguments
)
237 def createTextControl( self
):
238 """Create the text control"""
240 textControl
= wxComboBox(self
, ID
, style
= wxCB_DROPDOWN
)
241 textControl
.SetToolTipString( self
.toolTip
)
242 EVT_SET_FOCUS(textControl
, self
.OnSetFocus
)
243 if self
.changeCallback
:
244 EVT_TEXT(textControl
, ID
, self
.changeCallback
)
245 EVT_COMBOBOX(textControl
, ID
, self
.changeCallback
)
249 self
.SetHistory( history
, control
=textControl
)
253 def GetHistoryControl( self
):
254 """Return a pointer to the control which provides (at least)
255 the following methods for manipulating the history list.:
256 Append( item ) -- add item
257 Clear() -- clear all items
258 Delete( index ) -- 0-based index to delete from list
259 SetSelection( index ) -- 0-based index to select in list
260 Semantics of the methods follow those for the wxComboBox control
262 return self
.textControl
265 def SetHistory( self
, value
=(), selectionIndex
= None, control
=None ):
266 """Set the current history list"""
268 control
= self
.GetHistoryControl()
269 if self
.history
== value
:
272 # Clear history values not the selected one.
273 tempValue
=control
.GetValue()
274 # clear previous values
276 control
.SetValue(tempValue
)
277 # walk through, appending new values
279 control
.Append( path
)
280 if selectionIndex
is not None:
281 control
.SetSelection( selectionIndex
)
284 def GetHistory( self
):
285 """Return the current history list"""
286 if self
.historyCallBack
!= None:
287 return self
.historyCallBack()
289 return list( self
.history
)
292 def OnSetFocus(self
, event
):
293 """When the history scroll is selected, update the history"""
294 if self
.historyCallBack
!= None:
295 self
.SetHistory( self
.historyCallBack(), control
=self
.textControl
)
299 if wxPlatform
== "__WXMSW__":
300 def SetValue (self
, value
, callBack
=1):
301 """ Convenient setting of text control value, works
302 around limitation of wxComboBox """
303 save
= self
.callCallback
304 self
.callCallback
= callBack
305 self
.textControl
.SetValue(value
)
306 self
.callCallback
= save
308 # Hack to call an event handler
310 def __init__(self
, string
):
315 # The callback wasn't being called when SetValue was used ??
316 # So added this explicit call to it
317 self
.changeCallback(LocalEvent(value
))
320 class DirBrowseButton(FileBrowseButton
):
321 def __init__(self
, parent
, id = -1,
322 pos
= wxDefaultPosition
, size
= wxDefaultSize
,
323 style
= wxTAB_TRAVERSAL
,
324 labelText
= 'Select a directory:',
325 buttonText
= 'Browse',
326 toolTip
= 'Type directory name or browse to select',
328 startDirectory
= '.',
329 changeCallback
= None,
330 dialogClass
= wxDirDialog
):
331 FileBrowseButton
.__init
__(self
, parent
, id, pos
, size
, style
,
332 labelText
, buttonText
, toolTip
,
333 dialogTitle
, startDirectory
,
334 changeCallback
= changeCallback
)
336 self
._dirDialog
= dialogClass(self
,
337 message
= dialogTitle
,
338 defaultPath
= startDirectory
)
340 def OnBrowse(self
, ev
= None):
341 dialog
= self
._dirDialog
342 if dialog
.ShowModal() == wxID_OK
:
343 self
.SetValue(dialog
.GetPath())
346 if self
.__dict
__.has_key('_dirDialog'):
347 self
._dirDialog
.Destroy()
350 #----------------------------------------------------------------------
353 if __name__
== "__main__":
354 #from skeletonbuilder import rulesfile
355 class SimpleCallback
:
356 def __init__( self
, tag
):
358 def __call__( self
, event
):
359 print self
.tag
, event
.GetString()
360 class DemoFrame( wxFrame
):
361 def __init__(self
, parent
):
362 wxFrame
.__init
__(self
, parent
, 2400, "File entry with browse", size
=(500,260) )
363 EVT_CLOSE(self
, self
.OnCloseWindow
)
364 panel
= wxPanel (self
,-1)
365 innerbox
= wxBoxSizer(wxVERTICAL
)
366 control
= FileBrowseButton(
368 initialValue
= "z:\\temp",
370 innerbox
.Add( control
, 0, wxEXPAND
)
371 middlecontrol
= FileBrowseButtonWithHistory(
373 labelText
= "With History",
374 initialValue
= "d:\\temp",
375 history
= ["c:\\temp", "c:\\tmp", "r:\\temp","z:\\temp"],
376 changeCallback
= SimpleCallback( "With History" ),
378 innerbox
.Add( middlecontrol
, 0, wxEXPAND
)
379 middlecontrol
= FileBrowseButtonWithHistory(
381 labelText
= "History callback",
382 initialValue
= "d:\\temp",
383 history
= self
.historyCallBack
,
384 changeCallback
= SimpleCallback( "History callback" ),
386 innerbox
.Add( middlecontrol
, 0, wxEXPAND
)
387 self
.bottomcontrol
= control
= FileBrowseButton(
389 labelText
= "With Callback",
390 style
= wxSUNKEN_BORDER|wxCLIP_CHILDREN
,
391 changeCallback
= SimpleCallback( "With Callback" ),
393 innerbox
.Add( control
, 0, wxEXPAND
)
394 self
.bottommostcontrol
= control
= DirBrowseButton(
396 labelText
= "Simple dir browse button",
397 style
= wxSUNKEN_BORDER|wxCLIP_CHILDREN
)
398 innerbox
.Add( control
, 0, wxEXPAND
)
400 innerbox
.Add( wxButton( panel
, ID
,"Change Label", ), 1, wxEXPAND
)
401 EVT_BUTTON( self
, ID
, self
.OnChangeLabel
)
403 innerbox
.Add( wxButton( panel
, ID
,"Change Value", ), 1, wxEXPAND
)
404 EVT_BUTTON( self
, ID
, self
.OnChangeValue
)
405 panel
.SetAutoLayout(true
)
406 panel
.SetSizer( innerbox
)
407 self
.history
={"c:\\temp":1, "c:\\tmp":1, "r:\\temp":1,"z:\\temp":1}
409 def historyCallBack(self
):
410 keys
=self
.history
.keys()
414 def OnFileNameChangedHistory (self
, event
):
415 self
.history
[event
.GetString ()]=1
417 def OnCloseMe(self
, event
):
419 def OnChangeLabel( self
, event
):
420 self
.bottomcontrol
.SetLabel( "Label Updated" )
421 def OnChangeValue( self
, event
):
422 self
.bottomcontrol
.SetValue( "r:\\somewhere\\over\\the\\rainbow.htm" )
424 def OnCloseWindow(self
, event
):
427 class DemoApp(wxApp
):
429 wxImage_AddHandler(wxJPEGHandler())
430 wxImage_AddHandler(wxPNGHandler())
431 wxImage_AddHandler(wxGIFHandler())
432 frame
= DemoFrame(NULL
)
433 #frame = RulesPanel(NULL )
435 self
.SetTopWindow(frame
)
441 print 'Creating dialog'