Informatica

Laurent Segers - laurent.segers@vub.be

Tutorial Visual Studio (Windows Forms Applications)

Download scratch: link

Inleiding

Hieronder vinden jullie de oefeningen voor de WPO's informatica 1. De oefeningen zijn onderverdeeld in 4 categorieën: A, E en X. A zijn de algemene basisoefeningen en zijn het minimum dat verwacht wordt. De oefeningen van de E reeks zijn het niveau dat verwacht wordt op het examen. De X-oefeningen (Xtreme) zijn voor de echte durvers. Na elke les worden de opgeloste oefeningen via Pointcarré ingestuurd.

Tijdens de lessen zijn er 2 aangekondigde testen (elk 15%) gepland. Tijdens deze testen ondervragen wij de aangeleerde topics! Alle testen en examens worden hierbij gesloten boek afgenomen. Internet, theorieboek en opgeloste oefgeningen op papier of via een digitaal medium zullen niet toegelaten worden.

Tijdens de oenfeningensessies wordt er van je verwacht dat je actief meewerkt. Is dit niet het geval en verstoor je de groep of kom je te laat binnen, dan kan de assistent je de toegang tot die sessies weigeren.

Oefening baart kunst! Iedereen kan leren programmeren. Programmeren kan je alleen door veel te oefenen!

Testen informatica

Test 1

Opgaven versie A, oplossing A

Opgaven versie B, oplossing B

Test 2

Opgave versie A, Opgave versie B, oplossing A en B in 1 solution

Opgaven Scratch

WPO 1

Oefeningen scratch werkcollege 1

In deze opgave worden de beginselen van het logisch en sequentieel redeneren aangehaald d.m.v. eenvoudige oefeningen in Scratch.

WPO 2

Oefeningen scratch werkcollege 2

In deze opgave worden de beginselen van het logisch en sequentieel redeneren aangehaald d.m.v. eenvoudige oefeningen in Scratch.

Opgaven WPF (C#)

WPO 1

Oefeningen werkcollege 1

In dit werkcollege worden de beginselen van het programmeren in C# aangeleerd. Hierbij wordt het gebruik van variabelen, de grafische interface en enkele bijhorende elementen aangetoond. Hiernaast wordt ook het gebruik van Visual Studio aangetoond. De variabelen die we zullen gebruiken kunnen onderverdeeld worden in 4 grote groepen:

  • de gehele getallen of integers,
  • de kommagetallen: hieronder vallen double en float,
  • de strings (string) en karakters (char): deze worden gebruikt om tekst weer te geven,
  • de booleaanse waarden (true of false).

Het gebruik van elk type variabele wordt hier geïllustreerd.

// declareer eerst de variabelen
// dit gebeurt door de naam van de variabele te laten voorafgaan 
// door het type
double value_double;
float value_float;
int value_int;
char value_char;
string value_string;
bool value_bool;
// zorg ervoor dat de variabelen en waarde bevatten
value_double = 5.0;
// merk de f: deze duidt aan dat het getal als float gezien moet worden
value_float = 5.0f; 
value_int = 5; // geen komma!
value_char = 'a'; // enkele aanhalingstekens
value_string = "dit is een string"; // dubbele aanhalingstekens
// voer enkele bewerkingen uit
value_int = 5+8; // levert 13 op
value_double = 5.6+3.9; // = 9.5
value_string = "test" + "bla" // = "testbla"

Visual Studio (C#) biedt de mogelijkheid aan om waarden van een formulier uit te lezen. Waarden naar een formulier schrijven is eveneens mogelijk. De gebruikelijke controls (textbox, label, enz.) handelen de in- en uitvoer van waarden af als tekenreeksen (string). Om de waarden van een formulier (control) te gebruiken, moet men eerst de conversie van een string het gepaste type uitvoeren.

// inlezen van een control (.Text) naar een variabele (double)
// txtInput.Text is van het type string
value_double = double.Parse(txtInput.Text);
// inlezen van een control (.Text) naar een variabele (float)
value_float = float.Parse(txtInput.Text);
// inlezen van een control (.Text) naar een variabele (int)
value_int = int.Parse(txtInput.Text);
// inlezen van een string gebeurt zonder conversie 
// string naar string heeft geen conversie nodig
value_string = txtInput.Text;

Omgekeerd wordt een waarde steeds eerst naar een string omgezet voordat deze op het scherm weergegeven kan worden. Dit wordt geïllustreerd in onderstaand codefragment.

// wegschrijven van een variabele naar een control (.Text)
// txtOutput.Text is van het type string
txtOutput.Text = value_double.ToString();
// wegschrijven van een variabele naar een control (.Text)
txtOutput.Text = value_float.ToString();
// wegschrijven van een variabele naar een control (.Text)
txtOutput.Text = value_int.ToString();
// wegschrijven van een string 
// string naar string heeft geen conversie nodig
txtOutput.Text = value_string;

Tijdens de lessen worden ook verkorte notatie's gebruikt. Deze werken wel enkel voor enkelvoudige datatypes.

txtOutput.Text  = "" + value_double;
txtOutput.Text  = "" + value_float;
txtOutput.Text  = "" + value_int;

WPO 2

Oefeningen werkcollege 2

Tijdens dit werkcollege worden de principes van het debuggen en de conditionele if-structuren behandeld. Ook worden de eerste stappen van het debuggen tijdens dit WPO behandeld. Debuggen is van essentieel belang om goede software te kunnen schrijven! Zorg ervoor dat je deze technieken dus goed onder de knie hebt!
De conditionele if-structuren - keuzestructuren - vormen een belangrijke mijlpaal tijdens het programmeren. De keuzestructuren laten toe om volgens opgelegde voorwaarden een bepaald stukje code al dan niet uit te voeren. De meest eenvoudige if-structuur is de volgende:

if (condition)
{
	//some code
}

De voorwaarde (condition) kan om het even wat zijn, zolang het resultaat een boolean is. Voorbeelden van dergelijke voorwaarden worden hieronder opgelijst:

  • if (5>3)
  • if (a>3)
  • if ((a>3)&&(a<10)) => en a is groter dan 3, en a is kleiner dan 10
  • if ((a>3)||(a<10)) => of a is groter dan 3, of a is kleiner dan 10

Het blokje code dat uitgevoerd wordt als aan de condities voldaan is, bevindt zich tussen het daaropvolgende openend accolade en het bijbehorende sluitende accolade. Indien er verschillende condities met bijbehorende resultaten vereist zijn, kan men de if-structuur met een else if- en else-blok (zie hieronder) combineren.

if (condition1)
{
	//some code for condition 1
}
else if (condition2)
{
	//some code for condition 2
}
else
{
	//some code for else
}

De uitleg is vrij gelijkaardig als hierboven. Als regel ga je ervan uit dat de condities met hoogste prioriteit of met hoogste eisen als eerste worden behandeld (condition1, dan condition2, enz.). Geneste if-structuren zijn eveneens mogelijk (zoals hieronder weergegeven). De werking ervan is gelijkaardig aan een enkelvoudige if-structuur.

if (condition)
{
	if (subcondition1)
	{
		//some code
	}
}

Ook hier zijn de varianten met else if en else mogelijk. Varianten op de gewone vergelijkende if-structuren bestaan en worden in de opgaves zelf vermeld (checkboxen en radiobuttons).

WPO 3

Oefeningen werkcollege 3

Tijdens dit WPO wordt een eerste vorm van loopstructuren behandeld: de for loop. Loops bestaan uit 2 blokken: de code waarover de loop effect heeft, en de conditie(s) waaronder de loop plaatsvindt. De basis van de for-loop wordt hieronder weergegeven:

for (start;end;increment)
{
	//some code	
}

Over het algmeen wordt er in de for-loop met een integer (index, vandaar i) gewerkt. In dat geval wordt de for-loop:

for (i=0;i<max;i++)
{
	//some code	
}

Voor de start en eind conditie kunnen willekeurige waarden opgegeven worden. De increment (hier i++ of i=i+1) kan ook vrij bepaald worden (bv. i=i-1; i=i+5,...). De loop kan dus ook van hoog naar laag gaan. De grootste bron van fouten bij het opstellen van dergelijke loops is de combinatie van het verkeerd kiezen van de start en eind conditie, tesamen met een verkeerde increment. Het is dus belangrijk om de correctheid van de code na te gaan met de debugger.
Naast enkelvoudige for-loops is het ook mogelijk om for-loops te nesten, een if-structuur binnen een loop te schrijven, of omgekeerd.

WPO 4

Oefeningen werkcollege 4

In WPO 4 wordt het tekenen van allerhande geometrische figuren behandeld. Sommige elementen binnen de toolbox van Visual Studio (zoals een canvas) laten toe om grafische constructies zelf uit te tekenen. De voorbeelden die hieronder aangehaald worden, zijn gebaseerd op de canvas als tekenveld. Het tekenen van objecten verloopt steeds in stappen: het aanmeken van het object met alle eigenschappen en het achteraf toevoegen van dit object aan de canvas.

Hieronder wordt het aanmaken van een aantal object geïllustreerd. Als canvas wordt hier "cvs" gebruikt.

Tekenen van een lijn

// create a line object
Line ln = new Line();
// give the line the red color -> we use stroke for lines and contours
ln.Stroke = new SolidColorBrush(Colors.Red);
// give the line a given width of 5 pixels
ln.StrokeThickness = 5;
// set X and Y coordinates to the line 
ln.X1 = 0;
ln.X2 = cvs.Width;
ln.Y1 = cvs.Height;
ln.Y2 = cvs.Height;

Tekenen van een rechthoek

// create a rectangle object
Rectangle rect = new Rectangle();
// set contour width and color
rect.Stroke = new SolidColorBrush(Colors.GreenYellow);
rect.StrokeThickness = 1;
// position the rectangle against a canvas: 
// here 10,10 pixels from the upper left corner of the canvas
Canvas.SetLeft(rect, 10);
Canvas.SetTop(rect, 10);
// set width and height of our rectangle
rect.Height = 100;
rect.Width = 100;

Tekenen van een cirkel (ellips)

// create an ellips object
Ellipse el = new Ellipse();
// set contour color and width
el.Stroke = new SolidColorBrush(Color.FromArgb(255, 0, 200, 0));
el.StrokeThickness = 5;
// set the ellips width and height, if both are equal we obtain a circle
el.Width = 25;
el.Height = 25;
// position the rectangle against a canvas: 
// here 10,10 pixels from the upper left corner of the canvas
Canvas.SetTop(el, 10);
Canvas.SetLeft(el, 10);

Tekenen van een balk (gevulde rechthoek)

// create a rectangle object
Rectangle rect = new Rectangle();
// set area color
rect.Fill = new SolidColorBrush(Colors.GreenYellow);
// position the rectangle against a canvas: 
// here 10,10 pixels from the upper left corner of the canvas
Canvas.SetLeft(rect, 10);
Canvas.SetTop(rect, 10);
// set width and height of our rectangle
rect.Height = 100;
rect.Width = 100;

Tekenen van een schijf (gevulde ellips)

// create an ellips object
Ellipse el = new Ellipse();
// set area color
el.Fill = new SolidColorBrush(Color.FromArgb(255, 0, 200, 0));
// set the ellips width and height, if both are equal we obtain a circle
el.Width = 25;
el.Height = 25;
// position the rectangle against a canvas: 
// here 10,10 pixels from the upper left corner of the canvas
Canvas.SetTop(el, 10);
Canvas.SetLeft(el, 10);
Nadat deze getekend zijn kunnen die toegevoegd worden aan de canvas. Het toevoegen gebeurt zoals hieronder weergegeven.

Toevoegen van de getekende objecten aan de tekencanvas ("cvs")

// add line to canvas
cvs.Children.Add(ln);
// add ellips to canvas
cvs.Children.Add(el);
// add rectangle to canvas
cvs.Children.Add(rect);

De canvas verwijderen kan met een eenvoudige regel code

cvs.Children.Clear();

Assenstelsel van de canvas

Merk op dat alle objecten (met uitzondering van de lijn) steeds vanuit het linkerhoekpunt van het object getekend worden. Indien het object een hoogte en breedte heeft, dan zal het object vanuit dat punt naar links en naar onder getekend worden. Het assenstelsel van de canvas loopt zoals in de meeste andere programmeeromgevingen van links naar rechts en van boven naar onder toe.

Kleuren

In WPF wordt (toch in de oefeningen) er bijna uitsluitend met een brush gewerkt. In bovenstaande voorbeelden is aangetoond hoe men kleur kan toewijzen aan een object. Het toewijzen van kleuren aan objecten kan op verschillende manieren:
// get a color from 4 gradients 
// Alpha = 255, Red = 0, Green = 255, Blue = 255 -> gives a color between blue and green
// note that the first gradient specefies the transparancy: 
// 0 = fully transparant, 255 = fully opaque
Color clr = Color.FromArgb(255,0,255,255);
// we can also do it without transparancy
clr = Color.FromRgb(0,255,255);
// we can also choose a predefined color from WPF
// note the difference between Color and Colors
clr = Colors.Black;
// assigning the color
rect.Fill = new SolidColorBrush(clr);
el.Fill = new SolidColorBrush(clr);

Het is dus volledig mogelijk om zelf een kleur samen te stellen uit 3 of 4 waarden. Indit geval geeft de eerste waarde de doorzichtigheid (alfa) gevolgd door de rode, groene en blauwe kleurcomponent. Alle componenten zijn hierbij begrensd tussen 0 en 255 (inclusief). Het datatype van de componenten is steeds een byte. Het is dus noodzakelijk om de gewenste typecast te doen indien men vanuit een integer of ander type vertrekt. Het is echter ook mogelijk om vanuit de vooropgestelde kleure van WPF te vertrekken.

WPO 5

Oefeningen werkcollege 5

De while-loop onderscheidt zich van de for-loop in die zin dat er enkel aan een set van voorwaarden moet voldoen worden om een stukje code herhaaldelijk uit te voeren. De algemene vorm van de while-loop ziet er als volgt uit:

while (condition)
{
	//some code	
}

De conditie kan om het even wat zijn, zolang het eindresultaat een boolean is. De (syntax)regels voor de conditie zijn dezelfde als voor een gewone if-structuur. Een bijzondere while-loop is de oneindige loop, en wordt gevormd door:

while (true) //-- true is always true, so loop forever
{
	//some code	
}

Een for-loop kan altijd naar een while-loop omgevormd worden. De for-loop is nl. een gespecialiseerde vorm van de while-loop. Hierbij moet men echter zelf de index (i) van de for-loop in een while-loop bijhouden. Omgekeerd geldt dat een while loop soms ook herschreven kan worden als een for-loop. Dit is echter niet altijd het geval. Een voorbeeld van een omzetting van een for-loop naar een while-loop wordt hieronder weergegeven.

// write 10 number ins a label
for (int i=0;i<10;i++)
{
	lblOutput.Content = lblOutput.Content + " " + i.ToString();
}
// do the same with a while loop now
int i=0;
while(i<10)
{
	lblOutput.Content = lblOutput.Content + " " + i.ToString();
	// we need to do the increment of i ourselves now
	i++;
}

Naast de while loop bestaat er ook de do-while loop. De do-while loop begint eerst met do en eindigt met de while conditie. De code tussen de do en de while zal herhaaldelijk uitgeoverd worden zolang de conditie geldig is. In onderstaand codefragment wordt de do-while gedemonstreerd.

do 
{
	//some code	
}
while(condition==true);

Merk op dat een do-while loop altijd eindigt met een punt-komma. Het grootste verschil met een while-loop is echter het tijdstip wanneer de conditie nagekeken wordt. Bij een do-while wordt de conditie voor het eerst negekeken wanneer de loop minstens éénmaal al uitgevoerd is geweest. Bij een while-loop wordt eerst de conditie nagekeken alvorens de loop 1 keer is uitgevoerd. Het voorbeeldje van hierboven kan in dit geval ook omgevormd worden tot een do-while loop. Deze code zal altijd minstens 1 maal uitgevoerd worden.

int i=0;
do 
{
	lblOutput.Content = lblOutput.Content + " " + i.ToString();	
	i++;
}
while(i<10);

Uiteraard is het mogelijk om, net zoals in een for-loop, een while-loop in een while-loop te nesten. Ook een for-loop in een while-loop, een if-structuur in een while-loop nesten is ook mogelijk. Omgekeerd kan een while-loop op zijn beurt ook genest worden in de andere structuren.

WPO 6

Oefeningen werkcollege 6

Naast de klassieke iteratiemethoden die we tot nu toe hebben gezien kunnen we in C# (WPF) ook gebruik maken van timers. Een timer is een object die op regelmatige tijdsintervallen een voorafbepaalde functie zal oproepen. Hoewel er nergens in de code een loop gedeclareerd hoeft te worden, zal de code die in die bepaalde functie geschreven staat regelmatig uitgevoerd worden. In WPF worden timers aangemaakt via de DispatcherTimer. Het aanmaken en gebruik van de timer wordt hieronder weergegeven. Merk op dat er een speciaal directief bovenaan de code toegevoegd moet worden. Dit wordt eveneens hieronder vermeld.

// put this after the last using... statement above in the code
using System.Windows.Threading;
public partial class MainWindow : Window
{
	// declare our timer as a global variable
	DispatcherTimer timer = new DispatcherTimer();
	public MainWindow()
	{
		InitializeComponent();		
	}
	//-- event handler of a button on the form
	private void btnStart_click(object sender, RoutedEventArgs e)
	{		
		// first clean our label of any content
		lblShow.Content = "";
		// set function to call to our timer
		timer.Tick += timer_Tick;
		// give the interval at which the timer must call our function
		// in this case: 0 days, 0 hours, 0 minutes, 0 seconds and 200 milliseconds
		// frequency is thus 5Hz
		timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
		// start our timer after the cleaning
		timer.Start();		
	}
	//-- the function which will be called by the timer
	//-- code inside this function will be repeated periodically
	//-- (here every 200ms)
	//-- until the timer is stopped:
	//-- timer.Stop();
	private void timer_Tick(object sender, EventArgs e)
	{
		lblShow.Content = lblShow.Content + "X";		
	}
}

Naast de timers zullen we vandaag een nieuwe beslissingsstructuur ontdekken: de switch case. Switch cases zijn naast de if-structuren een manier om het verloop van het programma te bepalen. De switch case structuur is een specialisatie op de if structuur. Bij de switch case is het enkel mogelijk om op gelijkheid te evalueren. Een tweede beperking op de if-structuur wordt gevormd doordat er enkel met voorafbepaalde waarden vergeleken kan worden! Ondanks deze beperkingen wordt de switch case gebruikt om de code meer leesbaar te maken (net zoals de for-loop). M.a.w. het is altijd mogelijk om een switch case om te vormen naar een if-structuur. Omgekeerd kan alleen als aan de beperkingen voldaan wordt. Een voorbeeld van een switch case wordt hieronder weergegeven.

//-- usage of a switch case structure
//-- first decalre necessary variables
int value = 10;
//-- do not forget the brackets!
switch (value)
{
	//-- use "case" + value + ":"
	//-- note that a function can not be used
	//-- to compare against!
	case 0:
		//-- do something when value equals 0
		//-- can be a statement of function
		//-- or else
		//-- end with the break statement
		break;
	case 5:
		//-- do something when value equals 5
		//-- can be a statement of function
		//-- or else
		//-- end with the break statement
		break;
	case 10:
		//-- do something when value equals 10
		//-- can be a statement of function
		//-- or else
		//-- end with the break statement
		break;
	default:
		//-- do something when previous values ar not met
		//-- can be a statement of function
		//-- or else
		//-- end with the break statement
		break;
}

De variabele dat hier gebruikt is, is van het type integer. De programmeur kan hier in principe zelf het (enkelvoudige) type kiezen, maar de integer, string, char en enums worden het vaakst gebruikt. Functies kunnen niet gebruikt worden om mee te vergelijken binnen de switch case (dus case function), enkel een voorafbepaalde waarde!

Als laatste zal een introductie gegeven worden tot de combobox. Een combobox is een dropdown element dat toelaat om een bepaalde selectie te kiezen. Het gebruik van een combobox gebeurt door deze eerst in te vullen. nadien kan men, indien een waarde geselecteerd is, de waarde bepalen via de selected index eigenschap. Het geheel wordt hieronder weergegeven.

// Fill in the combobox with a few values (string only). 
cmbBox.Items.Add("Print in volgorde af");
cmbBox.Items.Add("Print in omgekeerde volgorde af");
cmbBox.Items.Add("Print randomwaarden af");

De juiste waarde uit de combobox opvissen kan als volgt:

// Code that resides in a button 
int index = cmbBox.SelectedIndex;
switch (index)
{
	case -1: // when no value has been selected (no mouse event on the combobox
			MessageBox.Show("Ongeldige keuze");
			break;
	case 0: // first element of the itmes in a combobox
			MessageBox.Show("Print in volgorde af");
			break;
	case 1:
			MessageBox.Show("Print in omgekeerde volgorde af");
			break;
	case 2:
			MessageBox.Show("Print randomwaarden af");
			break;
	default: // out ofrange for the combobox
			MessageBox.Show("Geen geldige waarde gekozen");
			break;
			
} 

De index van het geselecteerde item van de combobox kan ook gebruikt worden elementen uit een array/lijst aan te spreken (zie later).

WPO 7

Oefeningen werkcollege 7

Tijdens dit WPO worden de beginselen van meervoudige variabelen gezien. Collecties vormen hierbij een belangrijke constructie om een reeks bij elkaar horende waarden onder dezelfde naam in te kapselen. Hoewel het lijkt dat het om een gewone variabele gaat, bevat deze variabele een bepaald aantal waarden. Onder de noemer van collecties zullen we tijdens de WPO's 2 structuren zien: de arrays en de lijsten.

  • Arrays: bevatten een vast aantal elementen. Het aantal elementen wordt vastgelegd tijdens het declareren van de array.
  • Lijsten: bevatten een veranderlijk aantal elementen. Een lijst wordt leeg gedeclareerd en het aantal elementen kan veranderen tijdens de uitvoering van het programma.

Arrays kunnen zowel 1D, 2D en hoger dimensionaal zijn. Tijdens dit WPO zullen we ons enkel focussen op 1D arrays. Het gebruik van lijsten en arrays wordt in onderstaande codefragmenten weergegeven. Merk op dat net zoals gewone variabelen, arrays en lijsten van om het even welk datatype aangemaakt kunnen worden. Bij arrays en lijsten geldt dat de elementen aangesproken worden a.d.h.v. een index. Deze index start altijd bij 0 en eindigt bij het aantal elementen -1 (met een loop doorgaan zolang de index kleiner is dan de lengte dus).

// start with declaring an array.
// make an array of 10 floating point values
float[] float_array = new float[10];

// assign values to each element of the array
// the index i goes from 0 to 9, having thus 10 elements
// the value equals here i at position i, but can be anything else!
for (int i=0;i<10;i++)
{
	float_array[i] = i;
}
// read the values and print them in a textbox
for (int i=0;i<float_array.length;i++)
{
	txtoutput.Text = txtoutput.Text + " " + float_array[i];
}
// Start with declaring a list of a given type.
// when declaring and initializing, the type 
// is given between the brackets. Do not forget the 
// round brackets at the end before ';' 
List<float> float_list = new List<float>();

// Add the values into the list
// the index i goes from 0 to 9, having thus 10 elements
for (int i=0;i<10;i++)
{
	float_list.add(i);
}
// read the values and print them in a textbox
// the values can be read as if the list were an array
// go from zero up to the amount of elements in the list -1!
for (int i=0;i<float_list.Count;i++)
{
	txtoutput.Text = txtoutput.Text + " " + float_list[i];
}

WPO 8

Oefeningen werkcollege 8

In dit WPO zullen we de basis leren van gestructureerd programmeren. Tot hier toe werd alle code in de event-handler van een button geplaatst. Echter is deze techniek niet geschikt om grotere programma's te schrijven. In wat volgt zullen we de code opdelen in kleinere fragementen die we in procedures en functies zullen onderbrengen. In WPO 8 zullen we de procedures zien. In WPO 9 volgen de functies.

Procedures zijn methoden die toelaten om veelgebruikte code onder te brengen onder eenzelfde naam (bv. tekenRechthoek). Procedures bestaan uit 4 grote delen:

  • De naam van de procedure: dit is de naam die net de ronde haken voorafgaat.
  • De argumenten van de procedure: dit zijn de waarden die binnen de ronde haken worden gegeven. Deze kunnen bekeken worden als lokale variabelen die reeds ingevuld zijn. Elk argument wordt voorafgegaan door een datatype.
  • Een procedure geeft nooit een waarde terug. Daarom begint een procedure altijd met "void" (letterlijk vertaald: niets).
  • Hiernaast bevat een procedure ook een aantal commando's. Die staan altijd tussen het daaropvolgende paar accoladen. Dit is de code die op verschillende andere plaatsen in de het programma opgeroepen zal worden.

Hieronder wordt een voorbeeld van een procedure weergegeven.

// start a procedure with void
// than after a space follows the name of the procedure
// open the round brackets and write the arguments
private void tekenDriehoek(int x1, int y1, int x2, int y2, int x3, int y3,Color kleur)
{
	Line ln = new Line();
	ln.Stroke = new SolidColorBrush(kleur);
	ln.StrokeThickness = 1;
	ln.X1 = x1; ln.Y1 = y1; ln.X2 = x2; ln.Y2 = y2;
	cvsDraw.Children.Add(ln);

	ln = new Line();
	ln.Stroke = new SolidColorBrush(kleur);
	ln.StrokeThickness = 1;
	ln.X1 = x2; ln.Y1 = y2; ln.X2 = x3; ln.Y2 = y3;
	cvsDraw.Children.Add(ln);
	
	ln = new Line();
	ln.Stroke = new SolidColorBrush(kleur);
	ln.StrokeThickness = 1;
	ln.X1 = x3; ln.Y1 = y3; ln.X2 = x1; ln.Y2 = y1;
	cvsDraw.Children.Add(ln);	            
}

Bovenstaande procedure kan aangeroepen worden zoals afgebeeld in onderstaand codefragment.

// call the procedure as follows (draw 3 triangles)
tekenDriehoek(0,0,100,100,0,100,Colors.Black);
tekenDriehoek(200,200,250,200,100,100,Colors.Red);
tekenDriehoek(500,600,250,250,400,400,Colors.Yellow);

Een procedure laat dus toe om gelijkaardige code te parametriseren en onder te brengen onder 1 naam (naam van de procedure). Procedures worden daarna vanop verschillende plaatsen in het programma opnieuw opgeroepen. Deze techniek laat toe om codeduplicatie te vermijden. Bovendien wordt op die manier gekende en geverifieerde code beschikbaar gemaakt in de rest van een programma terwijl dat fouten t.g.v. codeduplicatie vermeden worden.

WPO 9

Oefeningen werkcollege 9

In dit WPO worden de functies behandeld. Functies lijken enorm hard op procedures en om deze reden is de uitleg ervan grotendeels gelijklopend. Het grote verschil met procedures is dat een functie altijd een return statement heeft. Functies bestaan in tegenstelling tot procedures uit 5 grote delen:

  • De naam van de functies: dit is de naam die net de ronde haken voorafgaat.
  • De argumenten van de functie: dit zijn de waarden die binnen de ronde haken worden gegeven. Deze kunnen bekeken worden als lokale variabelen die reeds ingevuld zijn. Elk argument wordt voorafgegaan door een datatype.
  • Een functie geeft altijd een waarde terug. Daarom begint een procedure altijd met een datatype. Dit kan een integer, float, double, enz. zijn.
  • Hiernaast bevat een functie ook een aantal commando's. Die staan altijd tussen het daaropvolgende paar accoladen. Dit is de code die op verschillende andere plaatsen in de het programma opgeroepen zal worden.
  • Als laatste moet de functie ook een waarde teruggeven. Dit wordt aangeduid met de statement "return value". Het datatype van value komt overeen met de datatype die vlak voor de naam van de functie staat. Een return-statement beëindigt altijd het verloop van de functie. Dit geldt ook voor procedures waar er na de return-statement geen waarde staat! Alle code die na een return-statement staat wordt nooit uitegevoerd.

Hieronder wordt een voorbeeld gegeven van een functie die de som van 2 getallen retourneert.

// write a function to sum two values
private int Sum(int value1, int value2)
{
	int s = 0;
	s = value1 + value2;
	// return the value, function will exit here even if 
	// there is code behind the return statement
	return s;
}

De functie kan ook aangeroepen worden. Merk op dat een functie een waarde teruggeeft. Dit betekent dus dat we deze waarde eerst in een variabele moeten opslaan. Dit gebeurt op dezelfde manier als het toewijzen van een waarde naar een variabele. Het verschil is echter dat de functie nu rechts van het gelijkheidsteken staat. De datatype van de variabele moet overeenkomen met de return-statement.

// first declare a variable for both input values
int val1 = 5;
int val2 = 10;
// declare a variable for the return-statement
int ret;
ret = Sum(val1,val2); // gives 15

WPO 10

Oefeningen werkcollege 10

Als laatste zullen we meerdimensionale arrays behandelen. We zullen ons in dit WPO beperken tot 2D arrays. het gebruik van hogere dimensies verloopt op dezelde manier. In tegenstelling tot lineaire arrays, ttz. arrays met 1 enkele index, hebben meerdimensionale arrays verschillende indices. Hierbij is het dus heel belangrijk bij te houden welke dimensie welke informatie bijhoudt. Over het algemeen worden meerdimensionale arrays met meer dan 3 dimensies niet gebruikt.

Een voorbeeld van meerdimensionale arrays zijn de afbeeldingen in bitmap-formaat. In een afbeelding wordt de informatie in een 3D array bijgehouden. Dankzij de eerste 2 indices kan men de een pixel op een bepaalde x- en y-positie aanspreken. De 3de dimensie van de array geeft de kleur van die ene pixel weer (R,G,B).

Het gebruik van een meerdimensionale array verschilt in weze niet veel van die van een lineaire array. Het enige verschil is het kunnen aanpreken van de verschillende dimensies. Dit wordt weergegeven in onderstaand codefragment.

// create a 2D array of 100 elements, note the ',' inside the brackets
double[,] arr = new double[10,10];
// fill our array with some values
for (int i=0;i<arr.GetLength(0);i++)
{
	for (int j=0;j<arr.GetLength(1);j++)
	{
		arr[i,j] = i+j;
	}
}

Merk op dat we voor elke dimensie een aparte for loop gebruiken. Omdat we over een meerdimensionale array itereren, moeten we voor elke dimensie de lengte opvragen. Dit doen we door de methode "GetLength(int dimensie)" op te vragen. Deze methode retourneert hoeveel cellen er voor die dimensie aanwezig zijn. Om elke dimensie aan te spreken volstaat het om de indices te scheiden door komma's. Elke komma wijst op een extra dimensie.

Het doorgeven van van meerdimensionale arrays aan functies verloopt op een heel gelijkaardige manier als het doorgeven van een lineaire. Dit wordt in onderstaande codefragment geïllustreerd.

//------------------------------------------
private void processArray(double[,] arr)
{
	...
}
//------------------------------------------
private double[,] returnArray()
{
	double[,] arr = new double[10,10];
	...
	return arr;
}
//------------------------------------------

Meerdimensionale arrays kunnen uiteraard aangemaakt worden van eender welk datatype.

Een laatste stap dat we hier willen behandelen zijn de null-waarden. Arrays kunnen in het algemeen ook gelijkgesteld worden aan null. Null in C# komt overeen met "het bestaat niet". Dit kan een handig mechanisme zijn indien men foutieve waarden uitkomt in een functie en dus niets wilt/kan retourneren. Een eenvoudige test op null laat toe om na te gaan of de array effectief geldige data bevat. Dit wordt hieronder weergegeven.

//------------------------------------------
private double[,] returnArray()
{
	double[,] arr = new double[10,10];
	// an error occured during calculations, so make the array null
	arr = null;
	return arr;
}
//------------------------------------------
private void callerFunction()
{
	double[,] arr = returnArray();
	if (arr!=null)
	{
		// do something with the array
	}
	else
	{
		MessageBox.Show("The array does not exist!");
	}
}

WPO 11

In deze les worden de laatste vragen over de voorgaande WPO's behandeld. Tijdens deze les wordt ook een finale demo getoond waarin duidelijk wordt gemaakt hoe de samenhang van de verschillende aangeleerde programmatorische onderdelen tot een finaal programma kan leiden.

Daarom wordt tijdens deze les "The Matrix" als screensaver-programma gedemonstreerd. Hieronder kan een voorproevertje gevonden van hoe het finaal programma er zal uitzien.

The matrix demo application

De finale oplossing (Visual Studio solution) kan hier gedownload worden. De map bevat de Visual Studio solution tesamen met de gepaste font ("matrix.ttf"). Het volstaat om de font te installeren in Windows om het effect in de screensaver te zien. In de submap "the_matrix\the_matrix\bin\Debug" kan het uivoerbaar bestand "the_matrix.exe" gevonden worden. Dit bestand kan ingesteld worden als echte Windows screensaver door de .exe extensie eerst te veranderen naar .scr. Een rechtermuisklik op dit bestand gevolgd door een install laat toe om dit ook effectief te doen. Via deze link kan meer informatie gevonden worden.