190 likes | 315 Views
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
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