Write-Up: Create a new wiki page, give it a useful title (e.g. Stephanie's CS251 Project 1), and describe the functionality of your GUI. Include at least one screen shot and clearly identify any extensions that you did. As a rule-of-thumb, your write-up should be approximately 2 pages when printed. It is important to be both thorough and concise!
This project has allowed me to familiarize myself with TKinter and become accustomed to the syntax of Python. Below is a summary of some of the features:
Part 3: creating a dialog window to manage distribution settings
DistributionDialog is derived from the Dialog class which initializes dialog window with only the buttonbox set of widgets executing the classic "ok" and "cancel" methods. I only overwrote the body and apply methods while adding my own helper method handleGssD.
Extension1: enlarging objects in the canvas
Most of the code for this extension can be found in the handleMouseButton2 and handleMouseButton2Motion methods. It is important to save the initial location and size information of the objects in the initial click so that the objects can grow with respect to their original sizes and they can grow based off the total movement of the mouse rather than the speed of the mouse.
The if-else statement allows us to check if the 2-D array of coordinates for all the objects needs to be expanded to accommodate new objects or if the information needs to be overwritten. We could just append the information onto the 2-D array and it would work for the first expansion, but if we wanted to adjust the size again, the initial coordinates being called from Motion would be that of the original sizes from before the first size-adjustment because the updated data would not be found in the corresponding indices of the object array.
Once the initial click and coordinate location has been saved into field variables, we can write the motion method to adjust the size of the objects and update their new coordinates.
Each oval increases in size by 2 pixels (one on each side) for every tenth of the screen up/down the mouse travels from the initial click. First I calculated the pixel difference between the initial click and the current mouse location (the difference along x is not used) and stored it in diff. Then I calculated the pixels of a tenth of the screen (being sure to round to the nearest pixel) as tenperscr. Finally, the number of pixels to add to each coordinate is stored in addpix. The for loop simply takes the original coordinates and adds or subtracts as appropriate by the value stored in addpix to each coordinate.
Extension 2: widget to control how many points to add when plotting random points
I used the Entry widget for obtaining user input for the number of objects to add to the canvas. The default is set at 10 when the window is initially generated. I started with code under the buildControls method just below the set color button.
I created a label for the Entry box, and then I created the Entry box with a starting value of 10. Then under the randomDataPoints method I created in Lab1 I retrieved the value from the field widget self.txtwid to set the points variable.
Extension 3: controlling the shape of the data objects
There are two aspects to this extension: setting the shape of subsequent objects placed by the randomDataPoints method and a button which sets all objects on the canvas to the selected shape. The shape used is determined by a ListBox in the right-side control frame with the default shape selected as an oval. The only shapes currently available are the "oval" (circle) and the "rectangle" (square) because I have not decided yet how to use the polygon method. If I add a triangle ora any other shape, I must consider how I would scale it when I use the handleMouseButton2Motion in extension 1. "Oval" and "rectangle" both use four coordinates so it is easy to call either create_oval or create_rectangle without having to change the code in the other extensions.
In my code, I create a simple ListBox in the right side control frame with the oval and rectangle options ("polygon" is set to plot ovals just the same as the "oval" selection). I also add a button labeled with "Shape All Objects" which calls the handleButton3 method. Then I added a couple lines to the randomDataPoints method which calls the index of the selected string from the list (0=oval, 1=rectangle, 2=polygon) and stores it in the shp variable. Based on the value of the shp variable, the pt object to be appended to the canvas is created as either an oval or a rectangle. Whenever randomDataPoints is called, it will check the shp the controls have selected to determine what kind of object it will add to the canvas.
In order to change the shape of all the current objects on the canvas, we have created a button with the handleButton3 command assigned to it. The code for this method is below:
Because I was running into trouble with the methods that create shapes not directly replacing their objects in the list at their index, I decided to use a loop based on indices instead of a loop that went through each object in a list. To determine the shape, I simply saved the shape-type variable into shp and built new objects based on its value. Because the loop I used is based off indices, I deleted objects from the front of the list (notice all the 0 indices used when calling an object from self.object) and I appended new objects to the end of self.object. All shapes are set to either an oval (the polygon, shp=2, is set to be created as an oval), or a rectangle (shp=1).
Extension 4: mouse-over reports position of data point underneath it
The code for this extension is a little more scattered. The Frame in which the coordinates are reported was labeled statusarea and created with the other frames and controls. The Frame only has the field Label botlbl. Under the setBindings method, I bind <Motion> to the handleMouse Motion, which updates the label in the statusarea frame as the mouse moves.
First it saves the current x and y coordinates of the mouse and goes through every object to see if it is hovering over an object. If it is, the point the object is centered on (avg. each of the x-coord and y-coord values) is saved into thisX and thisY(note that the Y coord was subtracted from the height to get the position). If not, the thisX and this remain as -1. By using an if-else statement, we can set the label to its default string or update it to show the coordinates of the points.
By taking the average instead of directly printing the mouse position, we give a more accurate position coordinate for the object. This takes a little more code but it is also more precise.
Extension 5: shift-cmd-mouse-button1 will delete point(s) underneath it
Any object or objects under the mouse when it is clicked while holding the shift and command buttons will be removed from the canvas. This is actually a very simple extension where <Shift-Command-Button-2> is bound to the handle method below:
The code simply loops through all the objects on the canvas and if the mouse is found within its coordinates, it is deleted from the canvas and the objects list. Note that if there is more than one object under the mouse, both will be removed from the canvas.
Extension 6: distribution dialog box begins with current x and y distributions as the initial selections
This was also a relatively simple extension. I simply passed the distribution information, a field tuple called dist, into the constructor of DistributionDialog under the name curDistr. Once these two variables are linked, I added a couple lines in the body method to set the initial selection to the indices found in curDistr (a 0 indicates "uniform" distribution and a 1 indicates "gaussian" distribution).
Here's the site with the most JavaDoc-like set-up: