I am trying to write a program that graphically presents three doors and ask the user to choose the “special” door (randomly selected by the program). If the user correctly chooses the special door, it’s a win. If either of the other two non-special doors is selected, it’s a loss.

I am getting the below error, and I don’t understand why.

Traceback (most recent call last):
 File "C:/Python27/ThreeButtonMonte_scratch.py", line 81, in <module>
    main()
 File "C:/Python27/ThreeButtonMonte_scratch.py", line 68, in main
    if door == 1 and b1.clicked(pt):
AttributeError: 'NoneType' object has no attribute 'clicked'

Program:

# button.py
from graphics import *
from random import randrange

class Button:

    """A button is a labeled rectangle in a window. It is activate or deactivated with the activated() and deactivated() 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 rectangle button, eg: qb = Button(myWin, centerPoint, width, height, '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 is 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 onf this button"
        return self.label.getText()


    def activate(self):
        "Sets this button to 'active'."
        self.label.setFill('black')
        self.rect.setWidth(2)
        self.active = True

    def deactivate(self):
        "Sets ths button to 'inactive'."
        self.label.setFill('darkgrey')
        self.rect.setWidth(1)
        self.active = False

def main():

    #create application graphics window
    win = GraphWin("Three Button Monte")
    win.setCoords(0, 0, 20, 10)
    win.setBackground("green2")

    #Draw the interface
    Text(Point(10, 7), "Choose a door").draw(win)
    b1 = Button(win, Point(3, 5), 5, 2, "Door 1").activate()
    b2 = Button(win, Point(10, 5), 5, 2, "Door 2").activate()
    b3 = Button(win, Point(17, 5), 5, 2, "Door 3").activate()
    qbutton = Button(win, Point(10, 1.5), 4, 1, "quit")


    pt = win.getMouse()

    #choose a random door
    door = randrange(1, 4)

    if door == 1 and b1.clicked(pt):
        Text(Point(10, 3), "You Win!")
    elif door == 2 and b2.clicked(pt):
        Text(Point(10, 3), "You Win!") 
    elif door == 3 and b3.clicked(pt):
        Text(Point(10, 3), "You Win!")
    else:
        Text(Point(10, 3), "You Lose.")

    qbutton.activate()    
    win.getMouse()
    win.close()

main()

Edited 3 Years Ago by pyTony: fixed formatting

if door == 1 and b1.clicked(pt):
AttributeError: 'NoneType' object has no attribute 'clicked'

I am not that familiar with the GUI named "graphics", but obviously b1==None which means it has no method clicked, or any other method. Examples of creating buttons exist here on Daniweb as well as on the web. Compare what the example is doing to what you have.

the .activate need to be on their own line
e.g
b1.activate
b2.activate
this makes the program work. good program for chapter 10 exercise 3

In other words:
b1 = Button(win, Point(3, 5), 5, 2, "Door 1")
b1.activate()
b2 = Button(win, Point(10, 5), 5, 2, "Door 2")
b2.activate()
b3 = Button(win, Point(17, 5), 5, 2, "Door 3")
b3.activate()

This article has been dead for over six months. Start a new discussion instead.