Determinación Genérica del Equilibrio de Nash en Juegos de Formación de Redes
4.2.4. Finitud Genérica de las Distribuciones de Probabilidad
Buttons, of course, are standard elements of virtually every GUI these days. Modern buttons are very so- phisticated, usually having a 3-dimensional look and feel. Our simple graphics package does not have the machinery to produce buttons that appear to depress as they are clicked. The best we can do is find out where
Figure 10.3: Snapshot of dice roller in action.
the mouse was clicked after the click has already completed. Nevertheless, we can make a useful, if less pretty, button class.
Our buttons will be rectangular regions in a graphics window where user clicks can influence the behavior of the running application. We will need to create buttons and determine when they have been clicked. In addition, it is also nice to be able to activate and deactivate individual buttons. That way, our applications can signal which options are available to the user at any given moment. Typically, an inactive button is grayed-out to show that it is not available.
Summarizing this description, our buttons will support the following methods:
constructor Create a button in a window. We will have to specify the window in which the button will be
displayed, the location/size of the button, and the label that will be on the button.
activate Set the state of the button to active. deactivate Set the state of the button to inactive.
clicked Indicate if the button was clicked. If the button is active, this method will determine if the point
clicked is inside the button region. The point will have to be sent as a parameter to the method.
getLabel Returns the label string of the button. This is provided so that we can identify a particular button.
In order to support these operations, our buttons will need a number of instance variables. For example, the button itself will be drawn as a rectangle with some text centered in it. Invoking theactivateand
deactivatemethods will change the appearance of the button. Saving theRectangleandTextobjects
as instance variables will allow us to change the width of the outline and the color of the label. We might start by implementing the various methods to see what other instance variables might be needed. Once we have identified the relevant variables, we can write a constructor that initializes these values.
Let’s start with theactivatemethod. We can signal that the button is active by making the outline thicker and making the label text black. Here is the code (remember theselfparameter refers to the button object):
def activate(self):
"Sets this button to ’active’." self.label.setFill(’black’) self.rect.setWidth(2)
As I mentioned above, in order for this code to work, our constructor will have to initializeself.label
as an approprateTextobject andself.rectas aRectangleobject. In addition, theself.active
instance variable stores a Boolean value (1 for true, 0 for false) to remember whether or not the button is currently active.
Ourdeactivatemethod will do the inverse ofactivate. It looks like this:
def deactivate(self):
"Sets this button to ’inactive’." self.label.setFill(’darkgrey’) self.rect.setWidth(1)
self.active = 0
Of course, the main point of a button is being able to determine if it has been clicked. Let’s try to write
theclickedmethod. As you know, thegraphicspackage provides agetMousemethod that returns
the point where the mouse was clicked. If an application needs to get a button click, it will first have to call
getMouseand then see which active button (if any) the point is inside of. We could imagine the button processing code looking something like the following:
pt = win.getMouse() if button1.clicked(pt): # Do button1 stuff elif button2.clicked(pt): # Do button2 stuff elif button2.clicked(pt) # Do button3 stuff ...
The main job of theclickedmethod is to determine whether a given point is inside the rectangular button. The point is inside the rectangle if its x and y coordinates lie between the extreme x and y values of the rectangle. This would be easiest to figure out if we just assume that the button object has instance variables that record the min and max values of x and y.
Assuming the existence of instance variablesxmin,xmax, ymin, andymax, we can implement the
clickedmethod with a single Boolean expression.
def clicked(self, p):
"RETURNS true if button is active and p is inside" return self.active and \
self.xmin <= p.getX() <= self.xmax and \ self.ymin <= p.getY() <= self.ymax
Here we have a single large Boolean expression composed by anding together three simpler expressions; all three must be true for the function to return a true value. Recall that the backslash at the end of a line is used to extend a statement over multiple lines.
The first of the three subexpressions simply retrieves the value of the instance variableself.active. This ensures that only active buttons will report that they have been clicked. Ifself.activeis false, then
clickedwill return false. The second two subexpressions are compound conditions to check that the x and
y values of the point fall between the edges of the button rectangle. (Remember,x <= y <= zmeans the same as the mathematical expression x y z (section 7.5.1)).
Now that we have the basic operations of the button ironed out, we just need a constructor to get all the instance variables properly initialized. It’s not hard, but it is a bit tedious. Here is the complete class with a suitable constructor.
# button.py
from graphics import * class Button:
"""A button is a labeled rectangle in a window. It is activated or deactivated with the activate() and deactivate() methods. The clicked(p) method
returns true if the button is active and p is inside it.""" def __init__(self, win, center, width, height, label):
""" Creates a rectangular button, eg:
qb = Button(myWin, Point(30,25), 20, 10, ’Quit’) """ w,h = width/2.0, height/2.0
x,y = center.getX(), center.getY() self.xmax, self.xmin = x+w, x-w self.ymax, self.ymin = y+h, y-h p1 = Point(self.xmin, self.ymin) p2 = Point(self.xmax, self.ymax) self.rect = Rectangle(p1,p2) self.rect.setFill(’lightgray’) self.rect.draw(win)
self.label = Text(center, label) self.label.draw(win)
self.deactivate() def clicked(self, p):
"RETURNS true if button active and p is inside" return self.active and \
self.xmin <= p.getX() <= self.xmax and \ self.ymin <= p.getY() <= self.ymax
def getLabel(self):
"RETURNS the label string of this button." return self.label.getText()
def activate(self):
"Sets this button to ’active’." self.label.setFill(’black’) self.rect.setWidth(2)
self.active = 1 def deactivate(self):
"Sets this button to ’inactive’." self.label.setFill(’darkgrey’) self.rect.setWidth(1)
self.active = 0
You should study the constructor in this class to make sure you understand all of the instance variables and how they are initialized. A button is positioned by providing a center point, width and height. Other instance variables are calculated from these parameters.