190 likes | 326 Vues
Explore the fundamentals of event-driven programming using Tkinter in Python. This guide covers the creation of command buttons, event handling, and responding to user interactions. Learn how to layout windows, respond to keyboard and mouse events, and add functionality to buttons through methods that change states. By the end, you'll be able to create interactive applications that respond to user actions, illustrated through a "Hello World!" example and a simple calculator prototype. Perfect for beginners eager to develop GUI applications.
E N D
Computer Science 112 Fundamentals of Programming II Command Buttons and Responding to Events
Event-Driven Programming • Layout and pop up a window • Wait for events • When an event occurs, respond • Goto step 2
Types of Events Keyboard entry Mouse move Mouse press Mouse release Mouse drag • Button click • Menu item selection • Check box selection • List box selection
Command Buttons • The method addButton adds a widget of type tkinter.Button to the window and returns it • Text, row, and column are required args • Button attributes • text (the button’s label) • image (for “hot spots”) • state (“normal” or “disabled”) • command (a method to run when the button is clicked)
Methods as Attributes? • Python methods and functions are first-class data objects • They can be passed as arguments to other methods and functions, and returned as the values of other methods and functions • The default command method for a button is a method of no arguments that does nothing
classHelloWorld(EasyFrame): """Illustrates buttons and user events.""" def__init__(self): """Sets up the window and the widgets.""" EasyFrame.__init__(self) self.label = self.addLabel(text = "Hello world!", row = 0, column = 0, columnspan = 2, sticky = "NSEW")
classHelloWorld(EasyFrame): """Illustrates buttons and user events.""" def__init__(self): """Sets up the window and the widgets.""" EasyFrame.__init__(self) self.label = self.addLabel(text = "Hello world!", row = 0, column = 0, columnspan = 2, sticky = "NSEW") # Add command buttons self.clearBtn = self.addButton(text = "Clear", row = 1, column = 0) self.restoreBtn = self.addButton(text = "Restore", row = 1, column = 1, state = "disabled") We can now view the layout, but the buttons can’t respond
classHelloWorld(EasyFrame): """Illustrates buttons and user events.""" def__init__(self): """Sets up the window and the widgets.""" EasyFrame.__init__(self) self.label = self.addLabel(text = "Hello world!", row = 0, column = 0, columnspan = 2, sticky = "NSEW") # Add command buttons self.clearBtn = self.addButton(text = "Clear", row = 1, column = 0, command = self.clear) self.restoreBtn = self.addButton(text = "Restore", row = 1, column = 1, command = self.restore, state = "disabled") The method’s names are here used just like variable references
classHelloWorld(EasyFrame): """Illustrates buttons and user events.""" def__init__(self): """Sets up the window and the widgets.""" EasyFrame.__init__(self) self.label = self.addLabel(text = "Hello world!", row = 0, column = 0, columnspan = 2, sticky = "NSEW") # Add command buttons self.clearBtn = self.addButton(text = "Clear", row = 1, column = 0, command = self.clear) self.restoreBtn = self.addButton(text = "Restore", row = 1, column = 1, command = self.restore, state = "disabled") # Methods to handle user events defclear(self): """Resets the label to the empty string and inverts the button states.""" self.label["text"] = "" self.clearBtn["state"] = "disabled" self.restoreBtn["state"] = "normal"
def__init__(self): """Sets up the window and the widgets.""" EasyFrame.__init__(self) self.label = self.addLabel(text = "Hello world!", row = 0, column = 0, columnspan = 2, sticky = "NSEW") # Add command buttons self.clearBtn = self.addButton(text = "Clear", row = 1, column = 0, command = self.clear) self.restoreBtn = self.addButton(text = "Restore", row = 1, column = 1, command = self.restore, state = "disabled") # Methods to handle user events defclear(self): """Resets the label to the empty string and inverts the button states.""" self.label["text"] = "" self.clearBtn["state"] = "disabled" self.restoreBtn["state"] = "normal" defrestore(self): """Resets the label to 'Hello world!' and inverts the state of the buttons.""" self.label["text"] = "Hello world!" self.clearBtn["state"] = "normal" self.restoreBtn["state"] = "disabled"
Command Buttons and Event Handling • Usually, each button has its own dedicated event handling method • Kind of like an automatic if statement • The GUI also automatically runs an event-driven loop, behind the scenes
A Calculator Prototype Can enter a number, but no other functions yet
class CalculatorDemo(EasyFrame): """Illustrates command buttons and user events.""" def__init__(self): """Sets up the window, label, and buttons.""" EasyFrame.__init__(self, "Calculator") self.digits = self.addLabel("0", row = 0, column = 0, columnspan = 3, sticky = "NSEW") digit = 9 for row inrange(1, 4): for column inrange(0, 3): button = self.addButton(str(digit), row, column) digit -= 1 # Instantiates and pops up the window. if __name__ == "__main__": CalculatorDemo().mainloop() Always lay out and pop up the window to refine the look of the UI, before you write the event handlers
Many Event Handlers, or One? • Usually, each button has its own dedicated event handling method • But, in this case, the method just adds the button’s text to the label’s text • If we can find a way to access that text, we can use one event handling method for all the buttons
Solution • Define a method that expects the button’s text as an argument • Run that method when the button’s command attribute is set • The method defines a nested function of no arguments, which adds the button’s text to the label’s text • The method returns the function, which becomes the event handler for that button
def__init__(self): """Sets up the window, label, and buttons.""" EasyFrame.__init__(self, "Calculator") self.digits = self.addLabel("0", row = 0, column = 0, columnspan = 3, sticky = "NSEW") digit = 9 for row inrange(1, 4): for column inrange(0, 3): button = self.addButton(str(digit), row, column) button["command"] = self.makeCommand(str(digit)) digit -= 1 self.makeCommand is a method that defines and returns a function of no arguments
def__init__(self): """Sets up the window, label, and buttons.""" EasyFrame.__init__(self, "Calculator") self.digits = self.addLabel("0", row = 0, column = 0, columnspan = 3, sticky = "NSEW") digit = 9 for row inrange(1, 4): for column inrange(0, 3): button = self.addButton(str(digit), row, column) button["command"] = self.makeCommand(str(digit)) digit -= 1 # Event handling method builder for digit buttons defmakeCommand(self, buttonText): """Define and return the event handler for a button.""" defaddDigit(): ifself.digits["text"] == "0": self.digits["text"] = "" self.digits["text"] += buttonText returnaddDigit The function addDigit has access to the button’s text
For Friday • Input and output with data fields • Responding to error conditions