Additional Controls, Scope, Random Numbers, and Graphics CS109 In this lecture we will briefly examine a few new controls, introduce the concept of scope, random numbers, and drawing simple graphics. Combo Box The Combo Box control is like a textbox with a pull-down menu of choices. We can access the user s selection with: combobox.text We can add to the items just like with a listbox: combobox.items.add(newitem) (Short demo in class) Group Box Control The group box is used to group related sets of controls for visual effect. To use it, drag the group box onto the form. Then drag any new controls into the group box. The new controls will now be part of the group box. The group box can be used to create different sets of radio buttons (upcoming). (Short demo in class) Check Box Control The checkbox is a small box that can be checked or unchecked by the user. To see if something is checked or not you can inspect the Checked Property: checkbox.checked - True if checked, False if not (Short demo in class) Radio Button Control The radio button operates like an old car radio. When one button is pushed, any other buttons pop out. For all radio buttons that are on a form, only one can be active at a time. If you would like to have multiple subgroups of radio buttons then they should be added to a GroupBox.
To see the value of a radio button, you can inspect the.checked property just as with a checkbox. (Short demo in class) Main Menu Control This control allows you to add a menu to the application. To use it, drag a Main Menu control to your form. Then double-click it in the form area. A menu designer will appear at the top of your form saying Type Here. You can now type the name of the top-level of your menu. Click and type to fill in sub-areas. To attach code to the sub-areas, double-click on the menu item. The VB Code window will appear with an event for you to fill in code. Try adding a menu for F)ile, O)pen, and C)lose. Variable Scope Scope refers to the section of code where a variable is alive. There are two categories of scope for a variable in C# that are generally used: class scope and local scope. Both adhere to the same basic rule: a variable is accessible everywhere within the curly braces where it is declared, including code within nested subroutines. Local Variables A local variable only has scope within the method in which it is created. When a variable is declared within a method, space reserved in memory for that variable exists until the subroutine exits, at which point the variable ceases to exist private void button1_click(object sender, EventArgs e) int num = 3; // Local variable, reset to 3 when run num = num + 5; MessageBox.Show(num.ToString()); // Shows 8 every time Your program is free to have other subroutines that use the variable num and each will refer to a different number. Class Variables Class level variables are visible to every method in the class. These variables are declared within the class but outside all methods within that class. This is useful for variables you would like to use within many methods on the form.
public partial class Form1 : Form string strname; private void button1_click(object sender, EventArgs e) strname = "Milhouse"; private void button2_click(object sender, EventArgs e) Console.WriteLine(strName); This technique is also a way in which subroutines can send data to each other one subroutine can set the class level variable while the other reads it. In this case, strname is set in button1 s click event, and displayed in button2 s click event. If you click button 2 before button 1, then a blank string is output (the default value for strname). In normal usage, variable scoping is as simple as defined above. However, things get trickier when variables have the same name. For example, consider the following scenario: public partial class Form1 : Form string strname = "Hello"; private void button2_click(object sender, EventArgs e) string strname = "There"; Console.WriteLine(strName); In the example above we have two variables named strname. One has class scope, the other has local scope. Which variable is referenced when there is this ambiguity? The rule used in C# is that local variables take precedence over class variables. In the example above, the local variable value of There is output.
If we wanted to access the class or module level variable, use the keyword this in front of the variable name: public partial class Form1 : Form string strname = "Hello"; private void button2_click(object sender, EventArgs e) string strname = "There"; Console.WriteLine(this.strName); It is common convention to always use the this prefix for class level variables. Once again, this example only demonstrates output of a variable, but we could also assign the class or local variable to a different value. C# does not allow us to have multiple local variables with the same name within the same scope. The following is illegal; private void button2_click(object sender, EventArgs e) string strname = "There"; Console.WriteLine(strName); string strname = "Hello"; Console.WriteLine(strName); // Illegal redefinition Random Numbers It is often useful to generate random numbers to produce simulations or games (or homework problems :) One way to generate these numbers in C# is to use the Random object. The random object generates pseudo-random numbers. What is a pseudo-random number? It is a number that is not truly random, but appears random. That is, every number between 0 and 1 has an equal chance (or probability) of being chosen each time random() is called. (In reality, this is not the case, but it is close). Here is a very simple pseudorandom number generator to compute the ith random #: R i = (R i-1 * 7) mod 11 Initially, we set the seed, R 0 = 1. Then our first random number is 7 mod 11 or 7. Our second random number is then (7*7) mod 11 or 5. Our third random number is then (5*7) mod 11 or 3. Our fourth random number is then (3*7) mod 11 or 10...etc.
As you can see, the values we get seem random, but are really not. This is why they are called pseudorandom. We can get slightly more random results by making the initial seed some variable number, for example, derived from the time of day. The particular function shown above would not be a very good pseudorandom number generator because it would repeat numbers rather quickly. Here is an example of using C# s random number generator. 1. At the class level, create a variable of type Random: Random rnd = new Random(); This creates a new Random object. We ll talk more about objects later when we get to object-oriented programming. We need to create the random number only once or we won t get a good pseudorandom number sequence. A good way to do this is to make it a class level variable associated with your form (this it will be created once when the form is displayed). 2. To generate a random integer x, where min x < max, use: x = rnd.next(min, max); 3. To generate a random double d, where 0 d < 1, use: d = rnd.nextdouble(); Here is a short demonstration program: public partial class Form1 : Form Random rnd = new Random(); public Form1() InitializeComponent(); private void button1_click(object sender, EventArgs e) int intnum; double dblnum; intnum = rnd.next(0, 4); Console.WriteLine(intNum); dblnum = rnd.nextdouble(); Console.WriteLine(dblNum);
The program above might print out: 1 0.969432235215526 The second time the button is clicked it might print out: 3 0.032952289578017 Both the integer and double are randomly generated. While the method call allows us to specify the range for integers, what if instead we wanted a random double between 5 and 15? We can just invoke rnd with: intnum = rnd.next(5, 16) This generates a number that is 5 and < 16 (i.e. 5-15 inclusive). Drawing Graphics Generally, you will use the PictureBox control to display graphics. It can display shapes we draw ourselves and also common image formats such as JPG, GIF, BMP, PNG, etc. We already showed how to display a static image (just add a picturebox to the form, click on the image property, Import a local resource, and pick the file that corresponds to the image you want displayed). Drawing Line Graphics To experiment with drawing graphics within a picturebox, add a PictureBox control to the form. In the Visual Studio Code section, go to the events for the PictureBox and select the Paint event: The Paint event is automatically invoked whenever the PictureBox needs to be redrawn. For example, if the form is minimized, dragged, or occluded, then when the form is activated the Paint event will be invoked. By placing the drawing code in the Paint event it will always be updated correctly. If we placed the code somewhere else and the window was obscured, it may not be redrawn correctly when the obscuring item is moved out of the way. We can now put code in the Paint event that will draw whatever we like on top of the PictureBox. The graphics screen is set up as a grid of pixels where the upper left coordinate is 0,0. This is relative to where the PictureBox is on the form. The x coordinate then grows out to the right, and the y coordinate grows down toward the bottom. For example, in the picture below the white pixel is at coordinate (600,400).
(0,0) x y (600, 400) Here is some sample code we can add to the Paint event to draw various shapes on the screen: private void picturebox1_paint(object sender, PaintEventArgs e) // Get the graphics object for the event (i.e. the PictureBox) Graphics g = e.graphics; // Draw a red rect of width 1 at Width=50, Height=80 at coord 10,20 g.drawrectangle(pens.red, 10, 20, 50, 80); // Make a new pen of width 4 Pen thickpurplepen = new Pen(Color.Purple, 4); // Ellipse in purple, width 4, within bounding rectangle at 50,10 g.drawellipse(thickpurplepen, 50, 10, 40, 30); // Draw a line from 10,10 to 50,50 of width 1 g.drawline(pens.mediumseagreen, 10, 10, 50, 50); // To fill in a shape we must use a brush SolidBrush bru = new SolidBrush(Color.GreenYellow); // Fill in the rectangle g.fillrectangle(brushes.greenyellow, 100, 100, 50, 20); // Draw part of a pie g.fillpie(brushes.indianred, 130, 20, 100, 100, 30, 60); // Draw the text "Abstract Art" in font Arial, size 12, in Indigo g.drawstring("abstract Art", new System.Drawing.Font("Arial", 12), Brushes.Indigo, 50, 140); First, we capture the Graphics object from the event arguments. The Graphics object is required to draw graphics on the screen. Remember that everything will be drawn relative to the upperleft corner of the PictureBox. Next, we create a red pen and draw a rectangle using that pen. The rectangle takes the coordinates of the upper left corner then the width and height.
An ellipse is drawn in a similar fashion, by specifying the bounding rectangle that holds the ellipse. This time we create a new pen object. The new pen object can specify the width of the item to draw. Next we draw a single line using the MediumSeaGreen pen. Next we draw a solid rectangle using a Brush object. The Brush in this case is a solid color, but it is possible to create brushes that are hatched, texture, etc. Finally we draw part of a Pie slice using a red brush. Finally we draw text toward the bottom of the screen using DrawString. You can pick whichever font you like that is on the system. The picture created is shown below: There are many other drawing tools available; see the online help for more details. Note that we should always draw the items in the Paint event, or the items won t be refreshed properly if the screen needs to be re-drawn. For example, if the above code was placed in a Button Click event, the items would be drawn when the button is clicked but not when the form needs to be refreshed. Colors There are lots of different pre-defined colors available from the Color object, e.g.: Color.Black Color.DarkGray Color.Gray Color.Blue Color.Green Color.LightGray Color.Cyan Color.Magenta Color.Orange Color.Pink Color.Red Color.White To create our own color, we can specify the color we want in RGB (red, green, blue). To do this, use: Color.FromArgb(Red, Green, Blue)
where Red, Green, and Blue are values in the range 0-255. 0 is the darkest intensity of each color and 255 is the brightest intensity of that color. The colors are mixed somewhat like the colors that make up light, e.g. red + green = yellow. For example: Color.FromArgb(0,255,200); Creates a green-blue color, with stronger green than blue. There is no red since its value is 0. In-Class Exercise: Random rectangles Write a program so that each time a button is pressed, the picturebox on the form displays a rectangle with a random width between (10-400) and a random height between (10-400) in a random color (SolidBrush) in a random position. Use picturebox1.height and picturebox1.width to get the width and height of the picturebox in pixels. Rnd.next(X,Y) gives a random integer between X and Y. To force the picturebox to update itself, inside the button click event add the code: PictureBox1.Invalidate() This invokes the Paint subroutine for PictureBox1 and it will re-draw itself by executing the code in the Paint event.