1

I'm on break from school but I want to keep coding over the summer so I am going back to old programs I have made and trying to improve them. atonofsmiles is a very simple Python program to make faces on the screen that I completed in my intro to programming class. Even though it is one of my first programs I ever wrote it is my most successful in that my kids love to use it. In the earlier version, I would have to go into the code to change the color of the faces so I am making a new version with a color picker. It is working kind of. . . In the original version getFace() is in a while loop to continually listen for a mouse click. But I would like the while loop to also listen for my new getColor() which returns a color. However when I place both functions in the same while loop, I can only make one face at a time. Then I have to click the color picker again to make another face.

      while True:
    color = getColor()
    while True:
        getFace(color)
        window.getMouse    

main()

My first instinct was to place the getFace() in a nested while loop inside the first while loop like so . . .

def main():

    while True:
        color = getColor()
        while True:
            getFace(color)
            window.getMouse

main()

However, this creates a situation where I can make multiple faces but I can only choose the color once.

I know this is not a difficult question and the answer I probably obvious to some but I can't see it.

Complete code below:

#several faces
#a program to draw several faces

from graphics import *
from math import *

win1=GraphWin("Color Picker", 1000, 200)

pink=Circle(Point(100,100), 50)
pink.draw(win1)
pink.setFill("pink")

red=Circle(Point(300,100), 50)
red.draw(win1)
red.setFill("red")

blue=Circle(Point(500,100), 50)
blue.draw(win1)
blue.setFill("blue")

green=Circle(Point(700,100), 50)
green.draw(win1)
green.setFill("green")

window=GraphWin("FACE MACHINE", 1000,800)
Text(Point(200,10), 'Click to make faces.').draw(window)
Text(Point(200,25), 'One for the center of the face,').draw(window)
Text(Point(200,40), 'and the second click will determine the size of the         
face.').draw(window)
Text(Point(200,55), 'Make a ton of faces').draw(window)


def drawFace(cx,cy, size, win, color):

rear=Circle(Point(cx-size,cy), .25*size)
rear.draw(window)
rear.setFill(color)

lear=Circle(Point(cx+size,cy), .25*size)
lear.draw(window)
lear.setFill(color)


head=Circle(Point(cx,cy), size)
head.draw(window)
head.setFill(color)



rightI=Circle(Point(cx+(.5*size), cy-(.5*size)), .1*size)
rightI.draw(window)
rightI.setFill('white')

rightiris=Circle(Point(cx+(.5*size), cy-(.5*size)), .05*size)
rightiris.draw(window)
rightiris.setFill('blue')

rightPupil=Circle(Point(cx+(.5*size), cy-(.5*size)), .025*size)
rightPupil.draw(window)
rightPupil.setFill('black')

leftI=Circle(Point(cx-(.5*size), cy-(.5*size)), .1*size)
leftI.draw(window)
leftI.setFill('white')
leftiris=Circle(Point(cx-(.5*size), cy-(.5*size)), .05*size)
leftiris.draw(window)
leftiris.setFill('blue')

leftPupil=Circle(Point(cx-(.5*size), cy-(.5*size)), .025*size)
leftPupil.draw(window)
leftPupil.setFill('black')



#smile=Line(Point(cx-(.5*size), cy+(.5*size)), Point(cx+(.5*size), cy+ 
(.5*size)))
#smile.draw(window)

bottomlip=Circle(Point(cx, cy+(.2*size)), .7*size)
bottomlip.draw(window)
bottomlip.setFill('black')

toplip=Circle(Point(cx, cy+(.15*size)), .7*size)
toplip.draw(window)
toplip.setFill(color)
toplip.setOutline(color)

rightP=Point(cx+(.02*size), cy+(.15*size))
rightP.draw(window)

leftP=Point(cx-(.02*size), cy+(.15*size))
leftP.draw(window)

def getFace(color):

pA= window.getMouse()
x1=pA.getX()
y1=pA.getY()
pB= window.getMouse()
x2=pB.getX()
y2=pB.getY()
z=sqrt((x1-x2)**2+(y1-y2)**2)
drawFace(x1,y1, z, window, color)

def getColor():
choice = win1.getMouse()
x = choice.getX()
y = choice.getY()

color = "grey"

if x > 75 and x < 125 and y > 75 and y < 125:
    color = "pink"
    print("pink")
    return color 

if x > 275 and x < 325 and y > 75 and y < 125:
    color = "red"
    print("red")
    return color 

if x > 475 and x < 525 and y > 75 and y < 125:
    color = "blue"
    print("blue")
    return color

if x > 675 and x < 725 and y > 75 and y < 125:
    color = "green"
    print("green")
    return color 

else:
    color = "grey"
    print("grey")
    return color 




def main():

while True:
    color = getColor()
    while True:
        getFace(color)
        window.getMouse

main()
Joe Bot
  • 11
  • 1
  • 3
    Your inner `while` loop never terminates as it's always `True`. You either have to change the condition, or break it, otherwise once it enters it - it never goes back. – dmitryro Jun 22 '18 at 02:17
  • Thanks. I see that I am miss using the while loop by trying to nest them. Ultimately, I want the program to be "listening" for a mouse click in both windows at the same time. – Joe Bot Jul 03 '18 at 02:44

1 Answers1

0

To do this you probably need to use event binding (when an event happens, call this function). Your current code lets you set the color once and then loops forever looking to drawFace.

I'm assuming you are using this wrapper class for Tkinter. It aims to simplify the use of Tkinter but may complicate things if you try to get too advanced because it changes some of the functionality of Tkinter.

However, there is a function built into that graphics library/wrapper class that can callback another function on a click event. You can do win1.setMouseHandler(func) where you send in a function to call when the mouse is clicked in that window. Do the same for the other window.

You'll need to pass in the color argument which should be doable using one of the methods mentioned here: How to pass an argument to event handler in tkinter?

Here are the two relevant methods in the GraphWin class in that graphics package:

def setMouseHandler(self, func):
    self._mouseCallback = func

def _onClick(self, e):
    self.mouseX = e.x
    self.mouseY = e.y
    if self._mouseCallback:
        self._mouseCallback(Point(e.x, e.y))

You can see that the callback sends the mouse's current position to whatever function you pass in and as I mentioned before, you'd call the function on a window object: win1.setMouseHandler(func)

Zev
  • 3,423
  • 1
  • 20
  • 41
  • Thank you. Yes, that is the very same graphics.py file I am using. The reason was using getMouse() was to access the x and y coordinates of the mouse clicks of the mouse click to determine which color was being clicked. As I hard coded these "buttons" I wondered if there was a better way. Not quite remembering the Button() function I have used in other python programs. I am guessing that would work better than the primitive buttons I have created. Would the win1.setMouseHandler(func) allow me to determine if where in the window the mouse was clicked or if a particular button was clicked? – Joe Bot Jul 03 '18 at 02:34
  • Yes, you would do a separate setMouseHandler for each window and I edited my answer to show the relevant functions and that the input to the callback is the location of the mouse. – Zev Jul 03 '18 at 02:44