comp 585 noteset #9 strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf ·...

31
COMP 585 Noteset #9 Strings and other basic datatypes in C# Outline C# Basics String Formatting WinForms Quick Tour of Namespaces, Classes and Structs, Properties Events and Delegates Internal vs. External Event Handling Mouse and Keyboard Events Layout Dock and Anchor Properties Layout-Aware Controls Tour of Common Controls Scrolling Do-It-Yourself Layout

Upload: duongcong

Post on 15-Mar-2018

217 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

COMP 585 Noteset #9 Strings and other basic datatypes in C#

Outline

C# Basics

String Formatting

WinForms

Quick Tour of Namespaces, Classes and Structs, Properties

Events and Delegates

Internal vs. External Event Handling

Mouse and Keyboard Events

Layout

Dock and Anchor Properties

Layout-Aware Controls

Tour of Common Controls

Scrolling

Do-It-Yourself Layout

Page 2: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

2

Primitive Types

In Java, primitive types are defined separately from the class libraries or packages. True, there are wrapper classes for

each primitive, but int and Integer are different types. int class Integer { }

double class Double { } … …

In C#, each primitive type is really just an “alias” for a struct that defines that type.

int: alias for struct Int32 { …}

For example: int x = 5; // or Int32 x = 5; Console.WriteLine(x);

int y = int.Parse("345"); // or Int32.Parse("345"); Console.WriteLine(y);

Strings

A String in C# is a collection of Char objects. Each Char object typically represents a single 16-bit Unicode character

code. In some cases, a Unicode character might require 2 Char objects to represent it. In lowercase, the datatype “string”

is just an alias for “String.” There is no difference between them.

String Properties Char[] Chars

int Length

C# classes support an indexer property that allows a composite object like a string to be indexed directly as if it were an

array. Here’s a simple Console I/O example:

string s = "abcde";

String t = "pqrst"; Console.WriteLine(s); Console.WriteLine(t);

Console.Write("Enter a String: ");

String u = Console.ReadLine(); Console.WriteLine("You entered " + u); Console.WriteLine("First character is " + u[0]);

C# Parse Methods

Use the Parse() method for the appropriate datatype to convert a String to a corresponding numeric value: String s = "123";

int x = int.Parse(s); // same as Int32.Parse(s);

C# String.Format Method

The String class provides the String.Format() static method that performs composite formatting. This kind of

formatting is similar to the printf() method provided by the C language. For example in C, you can write the following: int x = 546;

double y = 33.25; printf("x=%d, y=%f\n", x, y);

In this example, the first argument to printf() is called the format string. The other arguments are variables. The values

of the variables are inserted into the format string at the positions indicated by the format specifiers

%d d for decimal (base 10) integer

%f for floating point

Page 3: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

3

In C#, use String.Format to perform an equivalent operation. The method takes a variable number of arguments, where

the first argument is a format string, and the remaining arguments are variables whose values are to be substituted into

the format string. The positions for the substitutions are indicated by format items embedded into the format string.

The number of format items embedded into the format string should match the number of arguments that follow the

format string.

Example int x = 3, y = 4, z = 9; string s = String.Format(“x = {0}, y = {1}, z = {2}”, x, y, z);

System.Console.WriteLine(s);

Output is x = 3, y = 4, z = 9

In this example, the expressions “{1}” “{2}” “{3}” etc. are called format items and are embedded into the format string

where desired. After the format string is terminated, the additional arguments to String.Format() follow in a standard

comma separated list. The index of the format item refers to the value of these additional arguments, where argument 0

is the first argument after the format string itself.

Other methods such as Console.WriteLine() also accept composite format expressions: int x = 3, y = 4, z = 9; Console.WriteLine(“x = {0}, y = {1}, z = {2}”, x, y, z);

Standard Numeric Format Strings

To gain more detailed control over detailed formatting of each format item, the item can contain several numeric format

specifiers.

c: currency

d: decimal (base 10) integer

e: scientific notation real number

f: fixed point real number

g: general real number

n: number

r: round-trip [number � string � number yields same value]

x: hexadecimal (base 16) integer

Specifiers are added after the position indicator and a colon separator: {0:f}

{1:g} {2:x}

The format specifier can also define alignment and precision. The meaning of this value varies from format to format.

{0:f3} display 3 digits to the right of the decimal, padding with 0s on the right if necessary

{1:d10} display the integer in ten digits, padding with 0s on the left if necessary

Alignment is specified by a comma plus field width. {2,10:d5} // the “,10” means field width of 10

Examples: double x = 12345.678912345;

double y = 12345.67; string s1 = String.Format("{0:f3} {0:f4} {0:f5}",x); string s2 = String.Format("{0:f3} {0:f4} {0:f5}",y);

System.Console.WriteLine(s1); System.Console.WriteLine(s2);

Output 12345.679 12345.6789 12345.67891

12345.670 12345.6700 12345.67000

Page 4: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

4

Other Methods

Use the Split() method to break a string apart based on the position of some character (like Java’s StringTokenizer class

in package java.util).

string delimstring = " ,"; // separators

char[] delims = delimstring.ToCharArray(); // convert to char[] string q = "this is a string,with delimiters"; // string to split

string[] tokens = q.Split(delims); // split it for (int i=0; i<tokens.Length; i++) { // print out tokens

Console.WriteLine(tokens[i]); }

Standard DateTime Format Strings

Format specifiers are also available for dates and times. For example, print out the current date and time using the

default format (struct DateTime is defined in namespace System):

DateTime t = DateTime.Now;

Console.WriteLine(t);

Use the format specifiers to customize:

d: short date pattern

D: long date pattern f: full date, short time

F: full date, long time g: general date, short time G: general date, long time

M or m: month day pattern s: sortable date/time pattern

t: short time pattern T: long time pattern u: universal sortable date/time pattern

U: same as full date/time assuming UTC y or Y: year month pattern

Page 5: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

5

Example Program

DateTime t = DateTime.Now; Console.WriteLine("d {0:d}",t); Console.WriteLine("D {0:D}",t);

Console.WriteLine("f {0:f}",t); Console.WriteLine("F {0:F}",t);

Console.WriteLine("g {0:g}",t); Console.WriteLine("G {0:G}",t); Console.WriteLine("M {0:M}",t);

Console.WriteLine("s {0:s}",t); Console.WriteLine("t {0:t}",t);

Console.WriteLine("T {0:T}",t); Console.WriteLine("u {0:u}",t); Console.WriteLine("U {0:U}",t);

Console.WriteLine("Y {0:Y}",t);

Output d 11/9/2006 D Thursday, November 09, 2006

f Thursday, November 09, 2006 12:26 PM F Thursday, November 09, 2006 12:26:39 PM

g 11/9/2006 12:26 PM G 11/9/2006 12:26:39 PM M November 09

s 2006-11-09T12:26:39 t 12:26 PM

T 12:26:39 PM u 2006-11-09 12:26:39Z U Thursday, November 09, 2006 8:26:39 PM

Y November, 2006

Page 6: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

6

Namespaces for WinForms Apps

Use the System, System.Windows.Forms, and System.Drawing namespaces.

System

• This namespace is analogous to the java.lang package for Java programs.

• Contains basic classes and structs used in almost any program

• Classes:

o Console

o EventArgs

o Math

o String/string

• Structs:

o Boolean/bool

o Char/char

o DateTime

o Double/double

o Int32/int

System.Windows.Forms

• This namespace defines the containers and controls used to create a WinForm GUI

o Form

� The standard top-level container for a WinForm GUI

• Control

o Base class for most GUI controls

• Common Widgets:

o Button

o ComboBox

o DateTimePicker

o Label

o ListBox

o NumericUpDown

o RadioButton

o RichTextBox

o TextBox

o TreeNode

o TreeView

• Menus

o MainMenu

o Menu

o MenuItem

• Dialogs/Alerts

o FontDialog

o MessageBox

o OpenFileDialog

o PrintDialog

o SaveFileDialog

• Containers

o FlowLayoutPanel

o Panel

o SplitContainer

o TableLayoutPanel

Page 7: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

7

System. Drawing

Classes:

Brush/Brushes

Font

Graphics

Icon/Image

Pen/Pens

Structs:

Color

Point

Rectangle

Size

System.Collections

ArrayList

Hashtable

Queue

Stack

System.IO

BinaryReader

BinaryWriter

Directory

File

FileStream

Path

TextReader

TextWriter

System.Threading

Thread

Properties

C# uses its style to manage object properties. Properties are generally capitalized, and public properties appear to be

read and written by direct access and direct assignment. In reality, properties are governed by set and get code blocks

which are similar to set and get methods in Java objects.

Common Form Properties

Anchor, AutoScroll, Autosize, BackColor, Bottom, Bounds, ClientSize, Controls, Dock, Enabled, Focused,

Font, ForeColor, Height, Left, Location, Menu, Parent, PreferredSize, Right, Size, TabIndex, TabStop, Top,

Width

Common Control Properties

Anchor, AutoSize, BackColor, Bottom, Bounds, ClientSize, Controls, Dock, Enabled, Focused, Font, ForeColor,

Height, Left, Location, Margin, MaximumSize, MinimumSize, Padding, Parent, PreferredSize, Right, Size,

TabIndex, TabStop, Visible, Width

Each property has a data type, don’t confuse the property name with its type, you’ll need to know both to make an

assignment. For example, the type of the Location property is Point. So to set a control’s location, you would need to

assign a value of type Point to the property:

Button b = new Button(); b.Location = new Point(25,35);

Page 8: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

8

Events and Delegates in Windows Forms

Each event in WinForms is paired with a corresponding delegate. The delegate for the event defines the signature for

functions that can act as a delegate for that event. There are not a large number of unique delegate types, and all delegate

types follow a fairly simple pattern:

Event Delegate Delegate Signature Click EventHandler public void f(Object x, EventArgs args);

Paint PaintEventHandler public void f(Object x, PaintEventArgs args);

MouseEnter

MouseHover

MouseLeave

MouseDown

MouseUp

MouseClick

MouseDoubleClick

MouseWheel

MouseMove

EventHandler

MouseEventHandler

public void f(Object x, EventArgs args);

public void f(Object x, MouseEventArgs args);

KeyDown

KeyUp

KeyPress

KeyEventHandler

KeyPressEventHandler

Public void f(Object x, KeyEventArgs args);

public void f(Object x, KeyPressEventArgs args);

To summarize, in order for the programmer to write a delegate that responds to an event, the required method signature

for that delegate must be known. Note the pattern for all delegate types:

• All methods have return type = void

• All methods have two input parameters

o The first parameter is a reference of type Object.

o The second parameter is a reference of type EventArgs or some derived class. This is actually the only

element of the delegate that changes. And it changes in a uniform way from delegate to delegate.

Note: events and handlers are organized similarly in WPF, but the exact names of the delegates and event arguments are

similar but not identical to their corresponding elements in Windows Forms.

Page 9: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

9

Internal vs External Event Handlers

There are two approaches to responding to events for Windows Forms GUIs:

Example: Click Event for Button Object

External Response: Write a Delegate Method and Attach it as an Event Handler

Delegate for Click Event is void EventHandler(Object object, EventArgs args)

void f(Object obj, EventArgs args) { // � TWO args

... Console.WriteLine(“…”);

}

Button b = new Button();

b.Click += f;

Internal Response: Write a Derived Class and Override the OnClick() Method

Each class has a built in method whose name begins with the prefix “On” for each event that the objects of that class can

respond to.

class Button {

protected void OnClick(EventArgs args) { … } // � ONE arg

}

The programmer can write a derived class and override the definition of the OnClick method to implement an internal

response to the event.

class CustomButton : Button {

… protected override void OnClick(EventArgs args) {

base.OnClick(args); ...

} }

The programmer can also combine them (do both). If doing both, it is important that the OnClick() override call the

inherited version base.OnClick(). It is the base method that is responsible for invoking the externally attached delegates.

Page 10: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

10

Mouse And Keyboard Events

Providing keyboard alternatives for most mouse operations is an essential part of good GUI design. Programming with

accessibility in mind is already encouraged by many organizations and is gradually becoming required policy.

The Four Basic Mouse Events

• MouseDown

• MouseUp

• MouseMove

• MouseWheel

• Only one control receives mouse events, and that control must be visible and enabled.

• Any control that is derived from class Form receives mouse events only when the mouse is positioned over the

control’s client area (exception during mouse capture).

MouseEventArgs Properties

• int X

• int Y

• MouseButtons Button

• int Clicks

• int Delta

Example: Check to see if the Right Mouse Button was Pressed

protected override void OnMouseDown(MouseEventArgs args) { if (args.Button & MouseButtons.Right != 0) … }

Entering, Leaving, Hovering The last 3 mouse-related events are

• MouseEnter

• MouseLeave

• MouseHover

Entering and leaving are similar to the equivalent Java events. The MouseHover event is generated when the mouse first

stops moving after entering. There can be at most one hover event between an enter and exit event.

Page 11: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

11

Example: Scribble App

Implement a C#/WinForms app that is equivalent to the Java Swing scribble exercise discussed earlier. One issue to

resolve is the lack of a MouseDrag Event in C#/WinForms. You can simulate a drag operation by implementing your

own state machine and keeping track of the state of the mouse across several events.

To implement the scribble app, you will need to collect a set of points generated across the GUI during a mouse drag.

Then in response to a paint event, you will draw a series of line segments to connect the points to render the scribble onto

the GUI.

OnMouseDown:

Start tracking

Remember location of mouse event in “ptLast”

OnMouseMove:

If not tracking return

Remember location of mouse event in “ptNew”

Draw line from ptLast to ptNew

ptLast = ptNew

OnMouseUp

Stop tracking

Limitations

Doesn’t remember the drawing between OnPaint events

Screen refresh will erase the drawing

ScribbleWithSave

Need to save an array of points, and redraw them during OnPaint. Note that .NET provides a convenient Graphics

method named DrawLines():

public void DrawLines(Pen pen, Point[] pts);

But each MouseDown-MouseMove-MouseUp sequence generates a different array.

Fix: use two ArrayList collections

• For each drawing sequence accumulate an ArrayList of points

• During the current sequence, connect the current series of points as before, since it won’t get saved until the

MouseUp event.

• At the end of the sequence, convert the ArrayList to an array and add it to an ArrayList of arrays.

• During OnPaint, redraw each array of points in turn.

Page 12: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

12

Keyboard

Keyboard input is directed to the active control on the active form. The ActiveForm static property of class Form

always tracks which form this is. This is related to the concept of keyboard focus.

Form Methods

void Activate()

Form Events

Activated

Deactivate

Keys and Characters

Two views of a keyboard

• Collection of keys

• Character code generator

Key Groups

• Toggle Keys (capslock, numlock, scrolllock, insert)

• Shift Keys (shift, ctrl, alt)

• Noncharacter Keys (function keys, arrow keys, pause, delete)

• Character Keys (characters, numbers, punctuation, spacebar, tab, backspace, esc, enter)

Events

• KeyDown (KeyEventHandler, KeyEventArgs)

• KeyUp (KeyEventHandler, KeyEventArgs)

• KeyPress (KeyPressEventHandler, KeyPressEventArgs)

KeyEventArgs Properties

• Keys KeyCode

• Keys Modifiers

• Keys KeyData

• bool Shift

• bool Control

• bool Alt

• bool Handled

• int KeyValue

KeyPressEventArgs Properties

• char KeyChar

• bool Handled

Most programs that need to monitor key events will only monitor the KeyDown event, and only for cursor-movement

keys, insert, and delete. It’s also common to combine cursor-movement keys with modifier keys like “Shift”.

Page 13: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

13

What Mouse/Keyboard Events Does a Button Receive? What Events Does a Form Receive?

To respond to a button click, provide a handler with the right signature and register it with the Click event. The “Click”

event is similar to the Java “ActionEvent”.

If a single button is placed on a Form, when that form becomes the active form, the button receives the focus, and

therefore (almost) all the keyboard input. The form receives no keyboard input in this case.

There are a few keystrokes that are handled in a special way. Neither the button nor the form receives them:

• KeyDown event for Enter, Tab, Arrow Keys

• KeyPress event for Enter, Tab

These keystrokes are used for GUI navigation, and so are not available to the form or its controls.

A Control can receive keyboard and mouse input only if it is both visible and enabled.

Alignment and Appearance

Set the TextAlignment control property to one of these values:

ContentAlignment Enumeration:

TopLeft, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter,

BottomRight

Set the FlatStyle control property to one of these values:

FlatStyle Enumeration

Flat, Popup, Standard, System

Page 14: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

14

Layout in Windows Forms

Windows Forms is gradually providing more support for the concept of dynamic layout, but in general the support is not

a good as in Java. The original style in Windows-based GUIs using VB was absolute positioning of controls on a fixed-

size form.

Problems

• Platform and device independence issues such as monitor resolution, default font, etc.

• Old style was for the form to impose a size on its controls.

• New style is for the form to accommodate the size desired by its controls.

Property AutoSize

• Tells a control to pick its size in a reasonable way.

• false by default, generally should set it to true

• Property AutoSizeMode options: GrowAndShrink, GrowOnly

Anchor and Dock Properties

These are properties of individual controls that provide some simple layout behavior. But they are not a substitute for a

real layout manager. Properties must be manipulated for individual control, global coordination between controls is

minimal.

Dock Property

The possible values of this property are defined by the DockStyle Enumeration: None, Top, Bottom, Left, Right, Fill.

These are absolute values and cannot be combined. For example, DockStyle.Top causes a control to be held against the

top of the container, and stretched to fill the width of the container.

Guidelines

• Default value of Dock property is None

• If one control sets Dock to a non-default value, other controls should too

• Only one control should use the Dock value Fill.

Docking

Docking is different from Anchoring. Docking causes a control to be pressed flush against the indicated edge, then

stretched to fill the edge.

DockStyle Enumeration

None 0

Top 1

Bottom 2

Left 3

Right 4

Fill 5

These are not bit values that can be bitwise-ORed together. The control defines a “Dock” property to hold these values.

Docking causes a control to be pressed flush against the indicated side, and expanded (resized) along one dimension to

occupy the entire edge of the container.

Anchor Property

Possible values given by the AnchorStyles Enumeration: None, Top, Bottom, Left, Right. These are bit vector values so

they can be combined with bitwise OR. The Anchor property causes a control to remain a fixed distance from the

indicated container edge or edges, as the size of the container changes.

Dock and Anchor settings could be duplicated by appropriate logic explicitly added to the OnResize() method of the

parent form for the controls. A carefully constructed handler for OnResize() could play the role of a simple layout

manager (true in Java Swing as well).

Page 15: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

15

Guidelines

• Default value of Anchor property is Top | Left (not None).

• Dock and Anchor don’t mix well on the same form.

• Exception is when using Dock to position a tool bar to one edge, then position other controls in the remaining space

with Anchor.

• Better to introduce a Panel with Dock value Fill, and attach Anchored controls to the panel.

• Some layout alignment problems can be solved with nested panels that dock sequentially across or down the

container.

Note that there is an implicit relationship between the Anchor property and the Resize event. A Resize event will impact

the Location and Size properties of any control that does not have the default value of the Anchor property. This

happens automatically, the programmer does not have to explicitly program the OnResize() handler to do this.

More specifically:

• Anchor property for Control c includes two opposite sides (Top + Bottom, or Left + Right): then Resize changes

Size property for Control c

• Anchor property for Control c specifies one side: then Resize changes the Location property for Control c

• Anchor property for Control c specifies AnchorStyles.None: then Resize changes the Location property to keep

Control c in the same relative location within the form.

Page 16: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

16

Example: Dock Style Buttons

This example illustrates the effect of different Dock values for a group of buttons. using System; using System.Drawing;

using System.Windows.Forms;

using System.Threading; using System.Collections; using System.Collections.Generic;

public class Layout1 : Form {

Button[] btns;

public Layout1() : base() { btns = new Button[5];

for (int i=0; i<btns.Length; i++) { btns[i] = new Button(); btns[i].Text = "Btn " + i;

btns[i].Parent = this; }

btns[0].Dock = DockStyle.Top; btns[1].Dock = DockStyle.Right; btns[2].Dock = DockStyle.Bottom;

btns[3].Dock = DockStyle.Left; btns[4].Dock = DockStyle.Fill;

} public static void Main(string[] args) {

Layout1 form = new Layout1(); Application.Run(form);

} }

Page 17: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

17

Example: Anchor Style Buttons

This example illustrates the effect of different Anchor values for a group of buttons.

using System;

using System.Drawing; using System.Windows.Forms;

using System.Threading; using System.Collections;

using System.Collections.Generic;

public class Layout2 : Form { Button[] btns;

public Layout2() : base() {

btns = new Button[5]; for (int i=0; i<btns.Length; i++) { btns[i] = new Button();

btns[i].Text = "Btn " + i; btns[i].Parent = this;

} btns[0].Anchor = AnchorStyles.Top; btns[1].Anchor = AnchorStyles.Right;

btns[2].Anchor = AnchorStyles.Bottom; btns[3].Anchor = AnchorStyles.Left;

btns[4].Anchor = AnchorStyles.None; }

public static void Main(string[] args) { Layout2 form = new Layout2();

Application.Run(form); }

}

Page 18: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

18

Panels and Containers: Panel, FlowLayoutPanel, TableLayoutPanel

A Panel is a container object for visual grouping of controls. A FlowLayoutPanel is a container object that simulates

HTML flow layout (like Java FlowLayout). Flow can be either horizontal or vertical. Also, a specific control can be

tagged as a row or column break. This control will then start a new row or column.

Example

Here’s an example using FlowLayoutPanel, with randomly sized buttons and several choices of Anchor property. This

example also demonstrates two other useful techniques.

• The AutoScroll property of class Form

• The Application.EnableVisualStyles() method call.

using System; using System.Drawing;

using System.Windows.Forms;

public class Layout3 : Form { public Layout3() : base() {

FlowLayoutPanel p = new FlowLayoutPanel(); p.Parent = this;

p.Dock = DockStyle.Fill; p.AutoScroll = true;

Random r = new Random(); for (int i=0; i<40; i++) {

Button btn = new Button(); int x = r.Next()%100; int y = r.Next()%100;

btn.Size = new Size(30+x,20+y); btn.Parent = p;

btn.Anchor = AnchorStyles.None; // or Top,Bottom btn.Text = String.Format("{0}",i); }

}

public static void Main(String[] args) { Layout3 form = new Layout3(); Application.EnableVisualStyles();

Application.Run(form); }

}

Page 19: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

19

TableLayoutPanel

Similar to GridBagLayout in Java. Allows you to layout components in a grid. By default, the grid has one column, set

the ColumnCount property to a different value for more columns.

Example

In this example, create a TableLayoutPanel and attach it to a Form. Use the Dock property to make the

TableLayoutForm completely fill the client area of the Form

class Demo : Form {

public Demo() { TableLayoutPanel p = new TableLayoutPanel();

this.Controls.Add(p); p.Dock = DockStyle.Fill;

} }

Set up the desired number of rows and columns p.RowCount = 4; p.ColumnCount = 3;

Attach controls in row-major format for (int i=0; i<12; i++) {

Button b = new Button(); b.Text = …;

b.AutoSize = true; p.Controls.Add(b);

}

Or attach individual controls at specific grid positions Button b = new Button(); b.Text = …; b.AutoSize = true;

p.SetRow(b,2); p.SetColumn(b,1);

Individual controls can span multiple rows or columns: p.SetColumnSpan(b,2);

You can set a row or column to have a specific style, which controls how the row or column behaves when the container

is resized. Style can be auto, absolute or percent. for (int i=0; i<6; i++) {

p.RowStyles.Insert(i,new RowStyle()); } p.RowStyles[0].SizeType = SizeType.AutoSize;

p.RowStyles[1].SizeType = SizeType.AutoSize; p.RowStyles[2].SizeType = SizeType.AutoSize;

p.RowStyles[3].SizeType = SizeType.Percent; p.RowStyles[3].Height = 25; p.RowStyles[4].SizeType = SizeType.Absolute;

p.RowStyles[4].Height = 10; p.RowStyles[5].SizeType = SizeType.AutoSize;

Page 20: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

20

Example

using System; using System.Drawing; using System.Windows.Forms;

public class Layout4 : Form {

public Layout4() : base() { TableLayoutPanel p = new TableLayoutPanel();

p.AutoSize = true; p.Parent = this;

p.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single; for (int i=0; i<10; i++) {

Button btn = new Button(); btn.Text = "Button " + i;

btn.AutoSize = true; btn.Parent = p; }

}

public static void Main(string[] args) { Layout4 form = new Layout4();

Application.EnableVisualStyles(); Application.Run(form);

} }

We can change the number of columns, and furthermore allow some buttons to span multiple columns.

… p.ColumnCount = 2;

for (int i=0; i<10; i++) { Button btn = new Button();

if (i==2) { p.SetColumnSpan(btn,2); btn.Dock = DockStyle.Fill;

} btn.Text = "Button " + i;

btn.AutoSize = true; btn.Parent = p; }

Page 21: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

21

Padding and Margin

Padding is a way to create extra space inside a control. For example, if a button is autosized, the boundary of the button

will conform closely to the boundary of the text label that appears on the button. Use padding to force the button to take

up more space.

Button btn = new Button(); btn.Padding = new Padding(20);

btn.AutoSize = true;

Margin is also a property of type Padding, but is used in conjunction with FlowLayoutPanel and TableLayoutPanel.

Page 22: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

22

Simple Layout Effects with Docking Styles

• Create a Form

• Attach one component with Dock set to DockStyle.Left

• Attach a second component with Dock set to DockStyle.Fill.

• This results in a simple “BorderLayout” arrangement

For example, in “PrimevalNotepad.cs”, the component to the left is a TreeView, and the component in the fill position is

a TextBox. A more general example is to use a Panel object in the “fill” position.

Plain Panels

Here’s an excerpt from “SimplePanel.cs” Ch 3 Petzold Text 2. Two controls are placed onto a form: a Panel and a

TreeView. By careful use of DockStyle settings, simple layout manager logic is implemented. More specifically, this

implements a rudimentary “BorderLayout”. One component is a “plain” panel that “fills” most of the region of its

containing form (like BorderLayout.CENTER). Other controls like the TreeView are constrained to “hug” the edge of

the form (like BorderLayout.WEST, etc.).

Panel pnl = new Panel(); pnl.Parent = this;

pnl.Dock = DockStyle.Fill; // BorderLayout.CENTER pnl.AutoScroll = true;

TreeView tree = new TreeView(); tree.Parent = this;

tree.Dock = DockStyle.Left; // BorderLayout.WEST tree.Nodes.Add("tree");

The “plain” or “do-nothing” panel is analogous to class JPanel in Java Swing. Other controls (Button, TextBox, etc.) can

be attached to the Panel.

Page 23: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

23

More Examples with Anchors

Here’s an example from Petzold Text 2 (Ch 3). It creates a form containing several rows of controls. Each row contains

a label and a text box.

//---------------------------------------------

// AnchorFields.cs (c) 2005 by Charles Petzold //--------------------------------------------- using System;

using System.Drawing; using System.Windows.Forms;

class AnchorFields : Form {

[STAThread] public static void Main()

{ Application.EnableVisualStyles(); Application.Run(new AnchorFields());

} public AnchorFields()

{ Text = "Anchor Fields"; int iSpace = Font.Height;

int y = iSpace;

for (int i = 0; i < 4; i++) { Label lbl = new Label();

lbl.Parent = this; lbl.AutoSize = true;

lbl.Text = (new string[] { "Name:", "Address:", "Job:", "Very personal information:" })[i]; lbl.Location = new Point(iSpace, y);

TextBox txtbox = new TextBox();

txtbox.Parent = this; txtbox.Location = new Point(lbl.Right + iSpace, y); txtbox.Size = new Size(ClientSize.Width - iSpace - txtbox.Left,

txtbox.Height); txtbox.Anchor |= AnchorStyles.Right;

y = txtbox.Bottom + iSpace; }

} }

Page 24: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

24

The basic strategy is still absolute positioning, with the position of the label on each row specified in terms of x-y

coordinates. But notice that the text box uses relative positioning (in part). It locates itself according to the right edge of

the previous control on the same row. The right edge of the text box is calculated to mostly fill the row, based on how

wide the form currently is.

More layout-like logic is provided by setting the anchor style of the text box. By including the setting for

AnchorStyles.Right, the text box will now expand to fill the width of the form whenever the user resizes the form.

Since the default anchor style is “top” + “left”, the effect of the setting for each text box is the same as the more explicit

statement:

txtbox.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right;

The effect is somewhat subtle here. The size of the textbox depends on the position of its left edge, so the “Location”

property must be set before the “Size” property. Also, the AnchorStyles setting causes the size of the control to be

recalculated during a “Resize” event. This is not obvious from a quick glance at the code.

Page 25: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

25

Other Controls

Summary of Common Controls

• Label

• Button

• TextBox

CheckBox

Properties

• bool Checked

• bool AutoCheck

The Checked property indicates the current logical value of the check box control. The AutoCheck property causes the

Checked property to automatically toggle in response to a Click event on the control.

Events

If AutoCheck property is true, clicking on a check box generates a Click event. Regardless of the state of the

AutoCheck property, changing the value of the Checked property generates a CheckedChanged event. Imagine

writing a subclass of class CheckBox called MyCheckBox, and think about what the following handler for class

MyCheckBox would do:

protected override void OnCheckedChanged(EventArgs arg) { Checked ^= true;

}

It uses the exclusive-OR operation to toggle the value of the Checked property. But changing this property generates

another CheckedChanged event, so we’re stuck in a loop.

If AutoCheck is set to false, the check box control no longer responds to Click events.

Page 26: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

26

RadioButton

Similar to CheckBox. Uses Checked and AutoCheck properties in a similar way. Unlike Java radio buttons, Windows

Forms buttons automatically provide mutually exclusive behavior in a default way: all radio buttons attached to a form

are automatically mutually exclusive. If you want more fine-tuned control (eg, two groups of radio buttons that are

mutually exclusive only internally to a group), you have to use a GroupBox class.

Example

Four mutually exclusive buttons; they implicitly form a group because they have a common parent (current form = this).

class RadioTest : Form {

RadioButton b1, b2, b3, b4; public RadioTest() {

b1 = new RadioButton();

b1.Location = new Point(50,50); b1.Text = "choice 1"; b1.Parent = this;

b2 = new RadioButton();

b2.Location = new Point(50,b1.Bottom+10); b2.Text = "choice 2"; b2.Parent = this;

b3 = new RadioButton();

b3.Location = new Point(50,b2.Bottom+10); b3.Text = "choice 3"; b3.Parent = this;

b4 = new RadioButton();

b4.Location = new Point(50,b3.Bottom+10); b4.Text = "choice 4"; b4.Parent = this;

} }

Page 27: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

27

Example

Two groups of radio buttons, each group contained in a GroupBox object. The GroupBox has the extra benefit of

visually clarifying the grouping (bounding box, text label, etc.)

class RadioTest : Form {

RadioButton b1, b2, b3, b4; public RadioTest() {

GroupBox box1 = new GroupBox();

box1.Parent = this; box1.Text = "Group 1"; box1.Location = new Point(50,50);

b1 = new RadioButton();

b1.Location = new Point(10,20); b1.Text = "choice 1"; b1.Parent = box1;

b2 = new RadioButton();

b2.Location = new Point(10,b1.Bottom+10); b2.Text = "choice 2"; b2.Parent = box1;

GroupBox box2 = new GroupBox(); box2.Parent = this; box2.Text = "Group 2";

box2.Location = new Point(50, box2.Bottom + 50);

b3 = new RadioButton(); b3.Location = new Point(10,20); b3.Text = "choice 3";

b3.Parent = box2;

b4 = new RadioButton(); b4.Location = new Point(10,b3.Bottom+10); b4.Text = "choice 4";

b4.Parent = box2; }

}

Page 28: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

28

Scrolling and ScrollBars

For some applications, scrolling behavior for a container control like a Form or Panel can be defined by using the

AutoScroll and AutoScrollMinSize properties.

Example

class ScrollTest : Form { public ScrollTest() {

AutoScroll = true; AutoScrollMinSize = new Size(300,400); }

protected override void OnPaint(PaintEventArgs args) {

Graphics g = args.Graphics; g.DrawRectangle(Pens.Black,50,50,100,150); }

public static void Main() {

Application.Run(new ScrollTest()); } }

In this example, scroll bars appear whenever the size of the form is reduced below the specified minimum size. To make

the application more practical, the minimum size should be made to depend on the contents of the form (either a drawing

or a collection of controls).

Scroll bars can be added explicitly if needed. This is discussed in Petzold.

Properties

• int Value

• int Minimum

• int Maximum

• int SmallChange

• int LargeChange

Events

• ValueChanged (EventArgs)

• Scroll (ScrollEventArgs)

See ColorScroll Example in Petzold Ch 12. This uses three ScrollBar controls as if they were JSlider controls to set the

color of a panel. An alternative is the TrackBar control, which is more like the JSlider.

Page 29: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

29

Variations on Absolute Positioning: Simple Layout Logic

Petzold presents several programs that reveal how much work the programmer must do to imitate only a part of the

functionality that is performed effortlessly (for the programmer) by the layout managers for Java containers. For

example, one of Petzold’s techniques is to keep controls approximately in the center of their form. This requires that the

form receive Resize events, then reset the control’s locations. To improve upon this approach, the programmer could

add logic to create complex dependencies on the size of the form that impacts: the buttons’ sizes, relative orientations,

length of text label, choice of label font, etc. At some point, you have implemented a rudimentary layout manager.

More will be said about automatic layouts in Windows Forms later. For now, we’ll stick to absolute positioning and its

variations.

The techniques for simulating simple layout logic, without actually having a real layout manager, involve the following:

Control Properties

• Anchor

• Dock

• AutoSize

• Location

• Size

• ClientSize

Control Events

• OnResize

In effect, implementing the OnResize() method can simulate a simple layout manager. As of 2.0 of the SDK, additional

containers have been introduced to automatically provide some of this functionality.

Example: Simple Flow Layout Simulation

There are two situations when layout logic must be addressed:

• When the form is first constructed

• Whenever the form is resized

Define a method that performs the job of a layout manager. The method must look at the size of the controls and the size

of the form. Then call this method from both the constructor and the OnResize() event handler.

Page 30: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

30

This example creates 10 buttons then lays them out based on the logic of the flow layout manager.

using System; using System.Drawing; using System.Windows.Forms;

public class ResizeForm : Form {

int bcount = 10; Button[] buttons;

// constructor creates buttons, uses separate method to set locations

public ResizeForm() { buttons = new Button[bcount];

for (int i=0; i<bcount; i++) { buttons[i] = new Button();

buttons[i].Parent = this; buttons[i].Text = "Btn " + i; }

DoLayout(); // sets locations of all buttons }

private void DoLayout() {

Size csize = this.ClientSize;

int cx = 10; int cy = 10;

for (int i=0; i<bcount; i++) {

int tempx = cx + buttons[i].Size.Width + 10; // if current row will overflow the form, start a new row

if (tempx > csize.Width) { cx = 10;

cy = cy + buttons[i].Size.Height + 10; } buttons[i].Location = new Point(cx,cy);

cx = cx + buttons[i].Size.Width + 10; }

} // add method to do layout when form is resized

protected override void OnResize(EventArgs args) { Console.WriteLine("form was resized.");

DoLayout(); // reset locations based on new form size Invalidate(); // force form to be repainted }

}

class Driver { public static void Main() {

ResizeForm form = new ResizeForm(); Application.Run(form); }

}

Page 31: COMP 585 Noteset #9 Strings and other basic datatypes in ...cov/comp585f15/notes/noteset09.pdf · In C#, use String.Format to perform an equivalent operation. ... Standard DateTime

31

How To Generalize

This example introduces a useful idea, but the implementation shown is not fully general. How would the logic have to

be modified for an arbitrary collection of components?

Step 1: instead of using a customized array to hold references to buttons, the general version would access all members

of the form’s predefined “Controls” property.

Step 2: instead of assuming that every control is the same size, the general version would have to calculate the width and

height of the current row of controls by checking the Size property of each control as it is added to the current row.

With these adjustments, the approach would now be a good approximation to flow layout from the Java JPanel class.

TabStop and TabIndex

When a form is active, one control has the focus. If the user presses the TAB key, the focus moves to the next control in

sequence. Repeatedly pressing the TAB key eventually causes the focus to move throughout the entire form and wrap

around back to the first control.

This behavior is determined by two control properties:

• bool TabStop

• int TabIndex

In order for a control to receive the focus at all, its TabStop property must be set to “true”. Given the set of all controls

whose tab stop property is true, the tab index property defines the order in which the focus moves from control to control.

The initial value of the index is defined by the order in which the controls were programmatically added to the form, but

the programmer can change them.

In general, tab order is an important property for the programmer to notice. Many “power users” of applications depend

on reasonable tab order behavior in order to perform rapid navigation of the form without lifting their hands off the

keyboard to use the mouse. I’ve listened to conversations between clients and developers where the client is

complaining about unexpected tab order and the developer has to fix it.