How to do it...

In the beginning, all hell breaks loose, but we will soon fix this apparent mess.

Note that in Eclipse, the PyDev editor hints at coding problems by highlighting them in red on the right-hand side portion of the code editor.

Maybe we should not code in OOP after all, but this is what we do, and for very good reasons:

We just have to prepend all the variables with the self keyword and also bind the functions to the class by using self, which officially and technically turns the functions into methods.

There is a difference between functions and methods. Python makes this very clear. Methods are bound to a class while functions are not. We can even mix the two within the same Python module.

Let's prefix everything with self to get rid of the red so we can run our code again:

Once we do this for all of the errors highlighted in red, we can run our Python code again. The click_Me function is now bound to the class and has officially become a method.

Unfortunately, starting in a procedural way and then translating it into OOP is not as simple as I stated earlier. The code has become a huge mess. This is a very good reason to start programming in Python using the OOP model of coding.

Python is good at doing things the easy way. The easy code often becomes more complex (because it was easy to begin with). Once we get too complex, refactoring our procedural code into what truly could be OOP code becomes harder with every single line of code.

We are translating our procedural code into object-oriented code. Looking at all the troubles we got ourselves into, translating only 200+ lines of Python code into OOP could suggest that we might as well start coding in OOP from the beginning.

We actually did break some of our previously working functionality. Using Tab 2 and clicking the radio buttons no longer works. We have to refactor more.

The procedural code was easy in the sense that it was simply top to bottom coding. Now that we have placed our code into a class, we have to move all the callback functions into methods. This works, but does take some work to translate our original code:

    ########################################
# Our procedural code looked like this:
########################################
# Button Click Function
def click_me():
action.configure(text='Hello ' + name.get() + ' ' +
number_chosen.get())

# Adding a Textbox Entry widget
name = tk.StringVar()
name_entered = ttk.Entry(mighty, width=12, textvariable=name)
name_entered.grid(column=0, row=1, sticky='W')

# Adding a Button
action = ttk.Button(mighty, text="Click Me!", command=click_me)
action.grid(column=2, row=1)

ttk.Label(mighty, text="Choose a number:").grid(column=1, row=0)
number = tk.StringVar()
number_chosen = ttk.Combobox(mighty, width=12,
textvariable=number, state='readonly')
number_chosen['values'] = (1, 2, 4, 42, 100)
number_chosen.grid(column=1, row=1)
number_chosen.current(0)

********************************************
The new OOP code looks like this:
********************************************
class OOP():
def __init__(self): # Initializer method
# Create instance
self.win = tk.Tk()

# Add a title
self.win.title("Python GUI")
self.create_widgets()

# Button callback
def click_me(self):
self.action.configure(text='Hello ' + self.name.get() + ' '
+self.number_chosen.get())
# ... more callback methods

def create_widgets(self):
# Create Tab Control
tabControl = ttk.Notebook(self.win)
tab1 = ttk.Frame(tabControl) # Create a tab
tabControl.add(tab1, text='Tab 1') # Add the tab
tab2 = ttk.Frame(tabControl) # Create second tab
tabControl.add(tab2, text='Tab 2') # Add second tab
# Pack to make visible
tabControl.pack(expand=1, fill="both")

# Adding a Textbox Entry widget - using self
self.name = tk.StringVar()
name_entered = ttk.Entry(mighty, width=12,
textvariable=self.name)
name_entered.grid(column=0, row=1, sticky='W')

# Adding a Button - using self
self.action = ttk.Button(mighty, text="Click Me!",
command=self.click_me)
self.action.grid(column=2, row=1)
# ...
#======================
# Start GUI
#======================
oop = OOP() # create an instance of the class
# use instance variable to call mainloop via win
oop.win.mainloop()

We moved the callback methods to the top of the module, inside the new OOP class. We moved all the widget-creation code into one rather long method, which we call in the initializer of the class.

Technically, deep underneath the hood of the low-level code, Python does have a constructor, yet Python frees us from any worries about this. It is taken care of for us.

Instead, in addition to a real constructor, Python provides us with an initializer.

We are strongly encouraged to use this initializer. We can use it to pass in parameters to our class, initializing variables we wish to use inside our class instance.

In Python, several classes can exist within the same Python module.

Unlike Java, which has a very rigid naming convention (without which it does not work), Python is much more flexible.

We can create multiple classes within the same Python module. Unlike Java, we do not depend on a file name that has to match each class name.
Python truly rocks!

Once our Python GUI gets large, we will break some classes out into their own modules but, unlike Java, we do not have to. In this book and project, we will keep some classes in the same module while, at the same time, we will break out some other classes into their own modules, importing them into what can be considered as a main() function (this is not C, but we can think C-like because Python is very flexible).

What we have achieved so far is adding the ToolTip class to our Python module and refactoring our procedural Python code into OOP Python code.

Here, in this recipe, we can see that more than one class can live in the same Python module.

Cool stuff, indeed!

Both the ToolTip class and the OOP class reside within the same Python module:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.176.166