Difference between revisions of "CSC111 Lab 12 2014"

From dftwiki3
Jump to: navigation, search
(Adding a Call-Back Function)
(A Beginning CSV)
 
(40 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
--[[User:Thiebaut|D. Thiebaut]] ([[User talk:Thiebaut|talk]]) 18:47, 21 April 2014 (EDT)
 
--[[User:Thiebaut|D. Thiebaut]] ([[User talk:Thiebaut|talk]]) 18:47, 21 April 2014 (EDT)
 
----
 
----
 
+
<br />
 +
__TOC__
 +
<br />
 +
<bluebox>
 +
This lab is in two parts.  The first part is a regular lab, with step-by-step instructions for building an event-driven program.  The second part is a free-form lab that will start with a discussion, and a selection of several problems to be implemented for the lab.  The main task for this part is to be able to display a partial map of the Smith campus to scale.
 +
</bluebox>
 +
<br />
 +
<center>
 +
<font size="+3">The current graphics library for this lab is graphics111.py</font>
 +
</center>
 +
<br />
 +
<br />
 
=Building a car using the Graphics111 library=
 
=Building a car using the Graphics111 library=
 +
<br />
 
* Get a copy of the [[CSC111_graphics111.py_2014| graphics111.py]] library
 
* Get a copy of the [[CSC111_graphics111.py_2014| graphics111.py]] library
 
* Save it in your main directory (where you keep you python programs) and save it as '''graphics111.py'''
 
* Save it in your main directory (where you keep you python programs) and save it as '''graphics111.py'''
Line 28: Line 40:
 
     canvas = win.canvas()
 
     canvas = win.canvas()
  
     p1 = Car( 100, 100, 50, 20, (250, 250, 0) )
+
     car = Car( 100, 100, 50, 20, (250, 250, 0) )
     p1.draw( canvas )
+
     car.draw( canvas )
  
 
     win.wait()
 
     win.wait()
Line 40: Line 52:
  
 
<br />
 
<br />
 +
 
=Adding A Menu=
 
=Adding A Menu=
 
<br />
 
<br />
Line 60: Line 73:
 
         self._w2.draw( canvas )
 
         self._w2.draw( canvas )
 
          
 
          
 +
 
def main():
 
def main():
 
     win = GraphicsWindow(MAXWIDTH, MAXHEIGHT)
 
     win = GraphicsWindow(MAXWIDTH, MAXHEIGHT)
Line 67: Line 81:
 
     menu.draw( canvas )
 
     menu.draw( canvas )
 
      
 
      
     p1 = Car( 100, 100, 50, 20, (250, 250, 0) )
+
     car = Car( 100, 100, 50, 20, (250, 250, 0) )
     p1.draw( canvas )
+
     car.draw( canvas )
  
 
     win.wait()
 
     win.wait()
Line 77: Line 91:
 
</source>
 
</source>
 
<br />
 
<br />
=A Bit of Hacking=
+
=A Bit of Hacking (optional)=
 
<br />
 
<br />
 
* Figure out where the '''menu''' is located in the '''graphics111.py''' program, and change its color to red.  All the symbols should show up in red when your modification is over.
 
* Figure out where the '''menu''' is located in the '''graphics111.py''' program, and change its color to red.  All the symbols should show up in red when your modification is over.
 
<br />
 
<br />
 +
 
=Adding a Call-Back Function=
 
=Adding a Call-Back Function=
 
<br />
 
<br />
Line 116: Line 131:
 
     menu.draw( canvas )
 
     menu.draw( canvas )
 
      
 
      
     p1 = Car( 100, 100, 50, 20, (250, 250, 0) )
+
     car = Car( 100, 100, 50, 20, (250, 250, 0) )
     p1.draw( canvas )
+
     car.draw( canvas )
  
 
     win.wait()
 
     win.wait()
Line 144: Line 159:
 
Using the '''menu''' is now fairly easy.  All we have to do is call its main method called  '''buttonClicked( x, y )''' which returns the name of the symbol clicked if the user pressed one, or '''None''' if the mouse was not clicked on the menu.
 
Using the '''menu''' is now fairly easy.  All we have to do is call its main method called  '''buttonClicked( x, y )''' which returns the name of the symbol clicked if the user pressed one, or '''None''' if the mouse was not clicked on the menu.
 
<br />
 
<br />
::<source lang="python" highlight="2,16">
+
::<source lang="python" highlight="2-16">
 
def mouseEvent( win, canvas, x, y ):
 
def mouseEvent( win, canvas, x, y ):
 
     global menu  
 
     global menu  
Line 163: Line 178:
  
 
</source>
 
</source>
 +
<br />
 +
* Run your program.
 +
* Click on the menu symbols and observe the printouts in the console.  You should be able to detects clicks on the different symbols in the menu.
 +
<br />
 +
 +
=  Menu-Driven Action=
 +
<br />
 +
 +
* Add a new method to your car that will ''move'' its body and its wheels by some distance ''dx'' in the horizontal direction, and ''dy'' in the vertical direction when called:
 +
<br />
 +
::<source lang="python" highlight="14-17">
 +
class Car:
 +
    def __init__(self, x, y, w, h, color ):
 +
        self._body = Rectangle( x, y, w, h, color )
 +
        self._w1  = Wheel( x+w//4, y+h, w//4 )
 +
        self._w2  = Wheel( x+3*w//4, y+h, w//4 )
 +
       
 +
    def draw( self, canvas ):
 +
        self._body.draw( canvas )
 +
        self._w1.draw( canvas )
 +
        self._w2.draw( canvas )
 +
 +
    # move the car dx pixels to the right if dx is positive, dx pixels to the left if dx is negative.
 +
    # move the car dy pixels down if dy is positive, dy pixels up if dy is negative.
 +
    def move( self, canvas, dx, dy ):
 +
        self._body.move( canvas, dx, dy )
 +
        self._w1.move( canvas, dx, dy )
 +
        self._w2.move( canvas, dx, dy )
 +
</source>
 +
<br />
 +
* Make the call-back function '''move''' the car when the user clicks on the right-arrow in the menu.
 +
<br />
 +
::<source lang="python" highlight="3,11">
 +
def mouseEvent( win, canvas, x, y ):
 +
    global menu
 +
    global car
 +
    button = menu.buttonClicked( x, y )
 +
 +
    if button == "LeftArrow":
 +
        print( "left-arrow clicked!" )
 +
        return
 +
    if button == "RightArrow":
 +
        print( "right-arrow clicked!" )
 +
        car.move( canvas, 10, 0 )
 +
        return
 +
    if button == "Minus":
 +
        print( "minus clicked!" )
 +
        return
 +
    if button == "Plus":
 +
        print( "plus clicked!" )
 +
        return   
 +
 +
</source>
 +
<br />
 +
* make the '''car''' ''global'' in the main() function, the same way you made the '''menu''' ''global''.  This way the callback function '''mouseEvent()''' will be able to access the '''car''' object created in the '''main()''' function.
 +
 +
* Now run your program, and verify that the right arrow symbol can be used to move the car.
 +
<br />
 +
<br />
 +
{| style="width:100%; background:silver"
 +
|-
 +
|
 +
 +
==Challenge 2:  Car moving Left and Right==
 +
|}
 +
[[Image:QuestionMark9.jpg|right|120px]]
 +
<br />
 +
* Make the car move left when the left-arrow is clicked, and right when the right arrow is clicked.
 +
<br />
 +
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
 +
=Mapping The Smith College Campus=
 +
<br />
 +
<br />
 +
{|
 +
|
 +
<center> [[File:SmithMapSmall.gif|400px]]</center>
 +
|
 +
For this section we will depart from the regular lab organization and start a group discussion to address the problem of creating a program that would display a map (or section of a map) of the campus and would allow one to select different years and see the campus as it stood that year.  We'll have to address several questions:
 +
<br />
 +
* What should be the process of creating a map?
 +
<br />
 +
* How to save the map information so that the program can easily get it, and allow new buildings to be added in the future with the least effort.
 +
<br />
 +
* How can new buildings be added?  Could we create a separate program or incorporate in the current program an option for the user to input a new building in the map?
 +
<br />
 +
* How should the map be  displayed:  what scale?  what oritentation?  What features will be available to the user? 
 +
** Zooming? 
 +
** Moving the map?
 +
** Anything else?
 +
<br />
 +
* What will the user interaction feel like?
 +
<br />
 +
* Anything else?
 +
|}
 +
<br />
 +
After you have an idea of some of the possibility, pick some part of the options discussed above that you'd like to implement.
 +
 +
<br />
 +
==Some Hints About Drawing Polygons==
 +
[[Image:CSC111BluePolygon.png|right|200px]]<br />
 +
If you are using the '''graphics111.py''' library, then drawing a polygon once you have a list of all its coordinates in a 1-dimensional list can be done as follows:
 +
<br />
 +
:<source lang="python">
 +
  # list of x, y coordinates: 10 numbers ==> 5 points
 +
  L = [100, 100, 200, 100, 300, 150, 200, 200, 100, 200 ]
 +
 +
  # create a polygon object and draw it with color (205, 105, 205 )
 +
  p = Polygon( L,  (205, 105, 205) )
 +
  p.draw( canvas )
 +
</source>
 +
 +
<br />
 +
<br />
 +
 +
<br />
 +
<br />
 +
 +
=Submission=
 +
<br />
 +
The program for the first part should be called '''lab12a.py'''.  The program to create a csv file for the map should be called '''lab12b.py'''.  The program that reads the csv file and draws its contents should be called '''lab12c.py'''.
 +
 +
The URL for the submission: [http://cs.smith.edu/~thiebaut/111b/submitL12.php http://cs.smith.edu/~thiebaut/111b/submitL12.php]
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
 +
<br />
 +
 +
=A Beginning CSV=
 +
<br />
 +
 +
<source lang="text">
 +
Ford Hall, 358, 493, 371, 490, 383, 485, 387, 492, 391, 491, 401, 517, 410, 518, 413, 528, 407, 532, 421, 579, 420, 584, 422, 593, 415, 595, 415, 602, 406, 604, 403, 600, 400, 597, 394, 600, 391, 596, 388, 596, 366, 529
 +
Mendenhall Hall, 338, 497, 343, 512, 336, 512, 340, 522, 347, 520, 353, 543, 349, 546, 351, 556, 356, 556, 361, 572, 359, 583, 350, 581, 347, 576, 341, 577, 345, 594, 322, 601, 318, 595, 295, 599, 292, 598, 286, 597, 286, 601, 271, 606, 268, 600, 265, 585, 284, 581, 301, 574, 293, 532, 290, 529, 280, 529, 277, 515, 292, 511, 317, 503, 317, 498, 322, 496
 +
</source>
 +
<br />
 +
<font color="magenta">Be sure to set your drawing window at least 800 pixels high to see these buildings!</font>
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<!--
 +
=Solution Program for Part 1=
 +
<br />
 +
<source lang="python">
 +
from graphics111 import *
 +
 +
MAXWIDTH  = 600
 +
MAXHEIGHT = 400
 +
 +
class Car:
 +
    def __init__(self, x, y, w, h, color ):
 +
        self._body = Rectangle( x, y, w, h, color )
 +
        self._w1  = Wheel( x+w//4, y+h, w//4 )
 +
        self._w2  = Wheel( x+3*w//4, y+h, w//4 )
 +
       
 +
    def draw( self, canvas ):
 +
        self._body.draw( canvas )
 +
        self._w1.draw( canvas )
 +
        self._w2.draw( canvas )
 +
 +
    def move( self, canvas, dx, dy ):
 +
        self._body.move( canvas, dx, dy )
 +
        self._w1.move( canvas, dx, dy )
 +
        self._w2.move( canvas, dx, dy )
 +
       
 +
def mouseEvent( win, canvas, x, y ):
 +
    global menu, car
 +
    button = menu.buttonClicked( x, y )
 +
 +
    if button == None:
 +
        # create a circle centered on mouse coordinates
 +
        # give it a color that depends on the location (for fun)
 +
        c1 = Circle( x, y, 20, (x%256, y%256, (x+y)%256 ) )
 +
        c1.draw( canvas )
 +
        return
 +
   
 +
    if button == "LeftArrow":
 +
        #print( "left-arrow clicked!" )
 +
        car.move( canvas, -10, 0 )
 +
        return
 +
   
 +
    if button == "RightArrow":
 +
        #print( "right-arrow clicked!" )
 +
        car.move( canvas, 10, 0 )
 +
        return
 +
   
 +
    if button == "Minus":
 +
        print( "minus clicked!" )
 +
        return
 +
   
 +
    if button == "Plus":
 +
        print( "plus clicked!" )
 +
        return   
 +
 +
def main():
 +
    global menu, car
 +
 +
    win = GraphicsWindow(MAXWIDTH, MAXHEIGHT)
 +
    canvas = win.canvas()
 +
    canvas.setCallbackFunction( mouseEvent )   
 +
 +
    menu = Menu()
 +
    menu.draw( canvas )
 +
   
 +
    car = Car( 100, 100, 50, 20, (250, 250, 0) )
 +
    car.draw( canvas )
 +
 +
    win.wait()
 +
    win.close()
 +
 +
main()
 +
 +
</source>
 +
-->
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
[[Category:CSC111]][[Category:Python]][[Category:Labs]]

Latest revision as of 14:29, 24 April 2014

--D. Thiebaut (talk) 18:47, 21 April 2014 (EDT)




This lab is in two parts. The first part is a regular lab, with step-by-step instructions for building an event-driven program. The second part is a free-form lab that will start with a discussion, and a selection of several problems to be implemented for the lab. The main task for this part is to be able to display a partial map of the Smith campus to scale.


The current graphics library for this lab is graphics111.py



Building a car using the Graphics111 library


  • Get a copy of the graphics111.py library
  • Save it in your main directory (where you keep you python programs) and save it as graphics111.py
  • Create a car using the new classes now available in the graphics111 library. Call it lab12.py.


from graphics111 import *

MAXWIDTH  = 600
MAXHEIGHT = 400

class Car:
    def __init__(self, x, y, w, h, color ):
        self._body = Rectangle( x, y, w, h, color )
        self._w1   = Wheel( x+w//4, y+h, w//4 )
        self._w2   = Wheel( x+3*w//4, y+h, w//4 )
        
    def draw( self, canvas ):
        self._body.draw( canvas )
        self._w1.draw( canvas )
        self._w2.draw( canvas )
        
def main():    
    win = GraphicsWindow(MAXWIDTH, MAXHEIGHT)
    canvas = win.canvas()

    car = Car( 100, 100, 50, 20, (250, 250, 0) )
    car.draw( canvas )

    win.wait()
    win.close()

main()


  • Notice how short the program is now that the classes for the wheels and rectangles are in the graphics111 library!


Adding A Menu


  • Add a menu at the top left of the window. Don't try to activate it, it won't respond yet...


from graphics111 import *

MAXWIDTH  = 600
MAXHEIGHT = 400
class Car:
    def __init__(self, x, y, w, h, color ):
        self._body = Rectangle( x, y, w, h, color )
        self._w1   = Wheel( x+w//4, y+h, w//4 )
        self._w2   = Wheel( x+3*w//4, y+h, w//4 )
        
    def draw( self, canvas ):
        self._body.draw( canvas )
        self._w1.draw( canvas )
        self._w2.draw( canvas )
        

def main():
    win = GraphicsWindow(MAXWIDTH, MAXHEIGHT)
    canvas = win.canvas()

    menu = Menu()
    menu.draw( canvas )
    
    car = Car( 100, 100, 50, 20, (250, 250, 0) )
    car.draw( canvas )

    win.wait()
    win.close()

main()


A Bit of Hacking (optional)


  • Figure out where the menu is located in the graphics111.py program, and change its color to red. All the symbols should show up in red when your modification is over.


Adding a Call-Back Function


  • Modify your program and add a call-back function as shown below.
  • Run it and click the mouse on the window, several times. Make sure you check the output in the console.


from graphics111 import *

MAXWIDTH  = 600
MAXHEIGHT = 400

class Car:
    def __init__(self, x, y, w, h, color ):
        self._body = Rectangle( x, y, w, h, color )
        self._w1   = Wheel( x+w//4, y+h, w//4 )
        self._w2   = Wheel( x+3*w//4, y+h, w//4 )
        
    def draw( self, canvas ):
        self._body.draw( canvas )
        self._w1.draw( canvas )
        self._w2.draw( canvas )

def mouseEvent( win, canvas, x, y ):
    print( "Caught an event. Received x=%d, y=%d" % (x,y) )
    
def main():
    global menu 

    win = GraphicsWindow(MAXWIDTH, MAXHEIGHT)
    canvas = win.canvas()
    canvas.setCallbackFunction( mouseEvent )    

    menu = Menu()
    menu.draw( canvas )
    
    car = Car( 100, 100, 50, 20, (250, 250, 0) )
    car.draw( canvas )

    win.wait()
    win.close()

main()


Challenge 1: Circles on Mouse-Clicks

QuestionMark1.jpg


  • Make your program generate a colored circle where ever the user clicks the mouse.
  • Make the program generate red circles on the left side of the canvas, and green circles on the right side of the canvas.






Activating the Menu


Using the menu is now fairly easy. All we have to do is call its main method called buttonClicked( x, y ) which returns the name of the symbol clicked if the user pressed one, or None if the mouse was not clicked on the menu.

def mouseEvent( win, canvas, x, y ):
    global menu 
    button = menu.buttonClicked( x, y )

    if button == "LeftArrow":
        print( "left-arrow clicked!" )
        return
    if button == "RightArrow":
        print( "right-arrow clicked!" )
        return
    if button == "Minus":
        print( "minus clicked!" )
        return
    if button == "Plus":
        print( "plus clicked!" )
        return


  • Run your program.
  • Click on the menu symbols and observe the printouts in the console. You should be able to detects clicks on the different symbols in the menu.


Menu-Driven Action


  • Add a new method to your car that will move its body and its wheels by some distance dx in the horizontal direction, and dy in the vertical direction when called:


class Car:
    def __init__(self, x, y, w, h, color ):
        self._body = Rectangle( x, y, w, h, color )
        self._w1   = Wheel( x+w//4, y+h, w//4 )
        self._w2   = Wheel( x+3*w//4, y+h, w//4 )
        
    def draw( self, canvas ):
        self._body.draw( canvas )
        self._w1.draw( canvas )
        self._w2.draw( canvas )

    # move the car dx pixels to the right if dx is positive, dx pixels to the left if dx is negative.
    # move the car dy pixels down if dy is positive, dy pixels up if dy is negative.
    def move( self, canvas, dx, dy ):
        self._body.move( canvas, dx, dy )
        self._w1.move( canvas, dx, dy )
        self._w2.move( canvas, dx, dy )


  • Make the call-back function move the car when the user clicks on the right-arrow in the menu.


def mouseEvent( win, canvas, x, y ):
    global menu
    global car
    button = menu.buttonClicked( x, y )

    if button == "LeftArrow":
        print( "left-arrow clicked!" )
        return
    if button == "RightArrow":
        print( "right-arrow clicked!" )
        car.move( canvas, 10, 0 )
        return
    if button == "Minus":
        print( "minus clicked!" )
        return
    if button == "Plus":
        print( "plus clicked!" )
        return


  • make the car global in the main() function, the same way you made the menu global. This way the callback function mouseEvent() will be able to access the car object created in the main() function.
  • Now run your program, and verify that the right arrow symbol can be used to move the car.



Challenge 2: Car moving Left and Right

QuestionMark9.jpg


  • Make the car move left when the left-arrow is clicked, and right when the right arrow is clicked.








Mapping The Smith College Campus



SmithMapSmall.gif

For this section we will depart from the regular lab organization and start a group discussion to address the problem of creating a program that would display a map (or section of a map) of the campus and would allow one to select different years and see the campus as it stood that year. We'll have to address several questions:

  • What should be the process of creating a map?


  • How to save the map information so that the program can easily get it, and allow new buildings to be added in the future with the least effort.


  • How can new buildings be added? Could we create a separate program or incorporate in the current program an option for the user to input a new building in the map?


  • How should the map be displayed: what scale? what oritentation? What features will be available to the user?
    • Zooming?
    • Moving the map?
    • Anything else?


  • What will the user interaction feel like?


  • Anything else?


After you have an idea of some of the possibility, pick some part of the options discussed above that you'd like to implement.


Some Hints About Drawing Polygons

CSC111BluePolygon.png

If you are using the graphics111.py library, then drawing a polygon once you have a list of all its coordinates in a 1-dimensional list can be done as follows:

   # list of x, y coordinates: 10 numbers ==> 5 points
   L = [100, 100, 200, 100, 300, 150, 200, 200, 100, 200 ]

   # create a polygon object and draw it with color (205, 105, 205 )
   p = Polygon( L,   (205, 105, 205) )
   p.draw( canvas )





Submission


The program for the first part should be called lab12a.py. The program to create a csv file for the map should be called lab12b.py. The program that reads the csv file and draws its contents should be called lab12c.py.

The URL for the submission: http://cs.smith.edu/~thiebaut/111b/submitL12.php














































A Beginning CSV


Ford Hall, 358, 493, 371, 490, 383, 485, 387, 492, 391, 491, 401, 517, 410, 518, 413, 528, 407, 532, 421, 579, 420, 584, 422, 593, 415, 595, 415, 602, 406, 604, 403, 600, 400, 597, 394, 600, 391, 596, 388, 596, 366, 529
Mendenhall Hall, 338, 497, 343, 512, 336, 512, 340, 522, 347, 520, 353, 543, 349, 546, 351, 556, 356, 556, 361, 572, 359, 583, 350, 581, 347, 576, 341, 577, 345, 594, 322, 601, 318, 595, 295, 599, 292, 598, 286, 597, 286, 601, 271, 606, 268, 600, 265, 585, 284, 581, 301, 574, 293, 532, 290, 529, 280, 529, 277, 515, 292, 511, 317, 503, 317, 498, 322, 496


Be sure to set your drawing window at least 800 pixels high to see these buildings!