Hello Python community,

I have a basic question about the wx.DirDialog method/event handler system and how it works. I had a problem today, but solved it. Basically what I'm trying to do is have a frame, then use event handler wx.DirDialog to open up another dialogue where I can choose the filepath, and then I would like this filepath to populate into the text control box. I have solved the problem, but I don't understand the logic behind it, even though it works. :icon_neutral: :icon_lol:

Basically my problem was similar to this previous post:
http://www.daniweb.com/forums/thread97220.html#
Also listed here: http://mail.python.org/pipermail/tutor/2007-November/058662.html

So basically we're using the wx.DirDialog method on event call. YOu can see the basic functionality of this feature by looking at pictures;
"wxDirDialog1.jpg" and "wxDirDialog3.jpg"

This is the main snippet of the code (there's more, but this is all we need for illustration purposes).
This is what I wrote in the beginning and when ever I opened the 'get directory' dialogue from the event handler via the wx.DirDialog method I would be able to select the new file path but the full path directory would never show up in the text control box:

def  __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,'Get Quotes Tool', size=(400,300))
        self.SetIcon(wx.Icon('C:\Basic_Icons\globe_32.png',wx.BITMAP_TYPE_PNG))
panel=wx.Panel(self)
status=self.CreateStatusBar()

basicLabel=wx.StaticText(panel,-1,"Folder:",(52,65))
[B]FilePathTextBox[/B]=wx.TextCtrl(panel,-1,"",size=(200,-1),pos=(100,60))
self.button = wx.Button(panel,-1,"Browse",pos=(305,60))
self.Bind(wx.EVT_BUTTON, self.OnClick, self.button)

def OnClick(self,event): 
         dialog = wx.DirDialog(None, "Choose a directory:",
               style=wx.DD_DEFAULT_STYLE | wx.DD_CHANGE_DIR)
          if dialog.ShowModal() == wx.ID_OK:
             self.SetStatusText('You selected: %s\n' %dialog.GetPath())      
             [B]dirname=dialog.GetPath()
             FilePathTextBox.write(dirname)[/B]
        dialog.Destroy

I would usually get the following error with the above code:
FilePathTextBox.SetValue(dirname)
NameError: global name 'FilePathTextBox' is not defined
See the image below: "globalnamenotdefined.jpg"


Then after banging my head on the problem for a couple of hours, and finding some help on the web, I tried the following code:

def  __init__(self,parent,id):
        wx.Frame.__init__(self,parent,id,'Get Quotes Tool', size=(400,300))
        self.SetIcon(wx.Icon('C:\Basic_Icons\globe_32.png',wx.BITMAP_TYPE_PNG))
panel=wx.Panel(self)
status=self.CreateStatusBar()

basicLabel=wx.StaticText(panel,-1,"Folder:",(52,65))
[B]self.FilePathTextBox[/B]=wx.TextCtrl(panel,-1,"",size=(200,-1),pos=(100,60))
self.button = wx.Button(panel,-1,"Browse",pos=(305,60))
self.Bind(wx.EVT_BUTTON, self.OnClick, self.button)

def OnClick(self,event): 
         dialog = wx.DirDialog(None, "Choose a directory:",
               style=wx.DD_DEFAULT_STYLE | wx.DD_CHANGE_DIR)
          if dialog.ShowModal() == wx.ID_OK:
             self.SetStatusText('You selected: %s\n' %dialog.GetPath())      
             [B]self.dirname=dialog.GetPath()
             self.FilePathTextBox.write(self.dirname)[/B]
        dialog.Destroy

You can see that it now works if you look at the picture "wxDirDialog2.jpg"


I made three adjustments to my original code:
1. FilePathTextBox=wx.TextCtrl(panel,-1,"",size=(200,-1),pos=(100,60)) ---> I changed to ---> self.FilePathTextBox=wx.TextCtrl(panel,-1,"",size=(200,-1),pos=(100,60))

On the event handler OnClick() I did the following:

2. dirname=dialog.GetPath() ---> changed to ---> self.dirname=dialog.GetPath()
self.FilePathTextBox.write(dirname)

3. FilePathTextBox.write(dirname) ----> changed to ----> self.FilePathTextBox.write(dirname)


As you can see the main thing I did was changed those 3 lines by putting ".self" in front of them.
Does anyone know why doing this solved my problem and why I didn't get the "NameError: global name 'FilePathTextBox' is not defined" problem anymore??

It seems as if the ".self" feature references objects within the class or something, and not putting that ".self" in front of the lines means that I'm accessing global variables when it is not impossible b/c they are local functions.
However ... why is it that putting ".self" in front of the lines makes it okay for a local variable to access global instances??

Any help on this from someone knowledgeable about the core language would be great. I would like to understand the core logic behind why putting .self in front of everything works, and what this means and all.

This is wxPython btw.

Thanks in advance.

The 'self' keyword refers to the object (your class).

In your first example, you define a TextCtrl object and assign it to 'FilePathTextBox'. So in the constructor '__init__', 'FilePathTextBox' is a TextCtrl object.
In the OnClick method 'FilePathTextBox' is not recognised as a TextCtrl object, but as a local variable to the OnClick method.

When you add 'self.' to it 'self.FilePathTextBox' is recognised as the TextCtrl object defined in the 'self' object (your class).

I hope this is a bit clear. I understand the concept of OOP, but do not always use the correct vocabulary :s

I googled a bit and found next link:
http://linuxgazette.net/issue56/orr.html

With following paragraph:

Note that __init__ is defined with an extra first argument, self. But we don't specify self when we call the method. All Python methods work like this. self is in fact the instance itself, and Python supplies it behind the scenes. You need self because it's the only way the method can access the instance's attributes and other methods. Inside the method, self.rooms means the instance's attribute rooms, but rooms means the local variable rooms. Local variables, of course, vanish when the method ends. Python's use of self is parallelled in Perl and other OO languages as well.

It pays to study up on Python OOP a little.

Here is an example:

# explore wxPython's entry/wx.TextCtrl and label/wx.StaticText

import wx

class MyFrame(wx.Frame):
    def __init__(self, parent=None):
        wx.Frame.__init__(self, parent, -1, size=(300, 200))
        s = "Enter your name below:"
        label = wx.StaticText(self, -1, s)
        # style=wx.TE_PROCESS_ENTER needed for Linux
        self.text_in = wx.TextCtrl(self, -1, size=(250, 20),
            style=wx.TE_PROCESS_ENTER)
        # respond to enter key when focus is on text_in
        self.text_in.Bind(wx.EVT_TEXT_ENTER, self.onEnter)
        # cursor in text_in
        self.text_in.SetFocus()
        
        # create another text control for output
        self.text_out = wx.TextCtrl(self, -1, size=(250, 20))

        sizer = wx.BoxSizer(wx.VERTICAL)
        flag1 = wx.LEFT|wx.TOP|wx.EXPAND
        flag2 = wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.EXPAND
        flag3 = wx.ALL|wx.EXPAND
        sizer.Add(label, 0, flag=flag1, border=10)
        sizer.Add(self.text_in, 0, flag=flag2, border=10)
        sizer.Add(self.text_out, 0, flag=flag3, border=10)
        self.SetSizerAndFit(sizer)

    def onEnter(self, event):
        """the enter key has been pressed, do something"""
        name = self.text_in.GetValue()
        print(name)  # test
        s = "You entered the name: " + name
        # new text
        self.text_out.ChangeValue(s)
        # appends to existing text
        #self.text_out.AppendText(s)


app = wx.App(0)
# create a MyFrame instance and show the frame
MyFrame().Show()
app.MainLoop()

I googled a bit and found next link:
http://linuxgazette.net/issue56/orr.html

With following paragraph:

Ah okay. Thanks for that. I was looking for a basic explanation of self inside the wxPython In Action book but couldn't find it. Was probably too basic. lol ... ;)

So I guess .self is always required when accessing each specific object within the __init__ constructor. I will keep that in mind next time.

By the way in my previous code I used:

def OnClick(self,event): 
         dialog = wx.DirDialog(None, "Choose a directory:",
               style=wx.DD_DEFAULT_STYLE | wx.DD_CHANGE_DIR)
          if dialog.ShowModal() == wx.ID_OK:
             self.SetStatusText('You selected: %s\n' %dialog.GetPath())      
             self.dirname=dialog.GetPath()
             self.FilePathTextBox.write(self.dirname)
        dialog.Destroy

You can see I used:
"self.FilePathTextBox.write(self.dirname)"

And then later in my second block of code when the solution was found:
"self.FilePathTextBox.SetValue(self.dirname)"

Both of which do the same thing.
I figure the SetValue() feature is more in line with convention so I used that as the solution instead.
Sorry if this has confused anyone.

I prefer SetValue than write why? Because it is generic to all widgets

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.