Inledning
Med några få komponenter i .NET så kan vi skapa ett användbart program utan att krångla till det för mycket. Det som kommer att var nytt i denna artikel är just hur komponenterna används. Programmet som ska konstrueras ska fungera som ett tidtagarur. Vi ska använda en knapp för att starta och stoppa tidtagningen. När tidtagningen är aktiv så ska tiden fortlöpande visas i programmet. Vi kommer att använda oss av en del nya komponenter, bl. a.
- DateTime, tidangivelse.
- TimeSpan, skillnad i tid.
- Timer, Windows Forms komponent.
Börja med att skapa ett nytt Windows Application projekt och döp det till Tidtagarur.
Visuell design
De komponenter som använts i bilden nedan är en Button, en Label samt en Timer. Alla dessa komponenter hittar du i Toolbox'en, det är bara att dra och släppa på formuläret.
För at få utseendet att likna det som bilden ovan visar så måste en hel del properties ändras på komponenterna. I listan nedan kan du se vilka properties vi har valt att ändra:
- Form1
- FormBorderStyle = FixedDialog. Formuläret kommer inte att kunna ändra storlek.
- MaximizeBox = False. Maximeringsfunktionen kommer att vara inaktiverad.
- Size = 298; 180. Storleken på formuläret.
- Text = Tidtagarur
- label1
- AutoSize = True. Storleken på textrutan anpassas efter innehåll.
- Font.Size = 25. Storleken på texten.
- Font.Bold = True
- Location = 58; 22. Position.
- Text = 00:00:000
- button1
- Font.Size = 20. Storleken på texten.
- Font.Bold = True
- Location = 12; 82. Position.
- Size = 268; 61. Storlek.
- Text = Start
- timer1
- Interval = 20. Hur många milisekunder det dröjer mellan timerns varje Tick-event.
Events
Vi kommer att använda oss av tre events. Knappens event, Click, har beskrivits i föregående artikel. Du skapar den enklast den genom att dubbelklicka på knappen. Timerns event, Tick, skapar du också enklast genom att dubbelklicka på timern. Slutligen ska vi använda eventet Load på Form1. Enklast är återigen att dubbelklicka, denna gång på formulärets bakgrund. Koden ser nu ut som:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Tidtagarur
{
public partial class Form1 : Form
{
DateTime start;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
}
private void timer1_Tick(object sender, EventArgs e)
{
}
}
}
Knappens event inträffar varje gång du trycker på knappen. Formulärets event (Load) insträffar endast en gång och det är då programmet startar. Timerns event (Tick) inträffar, om timern är aktiverad, med jämna intervall.
Variabler för hela programmet
Eftersom vi ska mäta tid från den tidpunkt mätningen började så behöver vi en variabel för detta. Det är dags att använda en DateTime för första gången.DateTime är en speciell typ konstruerad just för detta ändamål. Frågan är bara vart vi ska deklarera den?
Deklarerar vi variabeln inne i någon av metoderna Form1_Load, button1_Click eller timer1_Tick så kommer den bara att finnas tillgänglig i dessa metoder. Dvs. varje gång programmet kommer till den punkt variabeln deklareras så kommer variabeln att skapas om. Variabler deklarerade i metoder eller begränsade kodblock kommer bara att finnas just där och kommer att frigöras när programmet lämnar det aktuella området.
I vårt exempel har vi deklarerat DateTime start på rad 13 i exemplet ovan. På så vis hör variabeln till hela klassen Form1 och kommer att finnas tillgänglig så länge vårt program körs. Vi kommer att använda variabeln start o både button1_Click och timer1_Tick.
Sätta ihop pusselbitarna
button1_Click
Tanken är att när knappen trycks in så ska tidtagning börja. Skulle tidtagningen vara igång så ska den avslutas. Detta ska vi kontrollera genom att starta eller stoppa timern. Timerna har inbyggda metoder för detta som kallas Start() och Stop(). Anropar vi timer1.Start() så sätts timern igång och eventet Tick körs med jämna mellanrum.
Samtidigt som vi växlar mellan läget att inte mäta tid eller att mäta tid så ändrar vi texten på knappen. Det ska stå "Start" när vi inte mäter tid och "Stop" när vi mäter tid. När vi trycker på knappen så vet vi inte i vilket läge vi befinner oss. Därför måste vi använda en if-sats för att undersöka läget. Antingen kollar vi då om timern är aktiv eller vilken text vi har på knappen. Vi har valt att undersöka texten på knappen.
Koden för att göra allt detta blir:
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "Start")
{
start = DateTime.Now;
timer1.Start();
button1.Text = "Stop";
}
else
{
timer1.Stop();
button1.Text = "Start";
}
}
När vi startar tidtagningen så sparar vi undan den aktuella tiden i variabeln start. Inbyggt i variabeltypen DateTime finns tiden DateTime.Now som alltid get datorns aktuella inställda tid. DateTime.Now ger alltså ett resultat av typen DateTime.
timer1_Tick
Nu gäller det att räkna ut tiden. När timern är aktiverad ska vi räkna ut tidsskillnaden mellan nu och när tidtagningen började. Resultatet ska skrivas ut till label1 på ett snyggt sätt.
Två DateTime variabler minus varandra ger in tidsskillnad av typen TimeSpan. Ur TimeSpan kan vi sedan fmå ut det exakta antalet minuter, sekunder och millisekunder.
För att bilda en textsträng kan vi alltid anropa metoden ToString() för att få siffror som text. Vi kör detta på minuter, sekunder och millisekunder. Samtidigt kan vi passa på att efterarbeta texten med metoden PadLeft() som finns inbyggd i alla strängar. PadLeft() utökar en sträng till att alltid ha en viss bredd genom att lägga till fyllnadstecken på den vänstra sidan. Detta blir perfekt då vi vill presentera tiden 1 minut och 5 sekunder som 01:05 istället för 1:5. Parametrarna till PadLeft() är först minimal längd och sedan vilket tecken som ska användas som fyllnad.
Koden blir kort och gott:
private void timer1_Tick(object sender, EventArgs e)
{
TimeSpan tid = DateTime.Now - start;
label1.Text = tid.Minutes.ToString().PadLeft(2, '0')
+ ":" + tid.Seconds.ToString().PadLeft(2, '0')
+ ":" + tid.Milliseconds.ToString().PadLeft(3, '0');
}
Form1_Load
För att enkelt starta och stoppa så ska vi se till att knappen är markerad vid start. När vi trycker enter i programmet så kommer knappen att vara markerad.
private void Form1_Load(object sender, EventArgs e)
{
button1.Select();
}
Avslutning
Det finns mycket färdigt inom .NET som bara väntar på att användas. Problemet är oftast att hitta rätt metod att göra saker.
Det bör tilläggas att timer-komponenten har väldigt dålig upplösning. Om du sätter Interval=20 så kommer Tick i praktiken inte att genereras exakt var 20:e millisekund, snarare någonstans mellan var 10-30:e millisekund. Nu är det inget problem i exemplet för det påverkar bara hur jämt uppritningen sker, tidtagningen blir väl så exakt eftersom tiden mäts från startögonblicket.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Tidtagarur
{
public partial class Form1 : Form
{
DateTime start;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
button1.Select();
}
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "Start")
{
start = DateTime.Now;
timer1.Start();
button1.Text = "Stop";
}
else
{
timer1.Stop();
button1.Text = "Start";
}
}
private void timer1_Tick(object sender, EventArgs e)
{
TimeSpan tid = DateTime.Now - start;
label1.Text = tid.Minutes.ToString().PadLeft(2, '0') + ":"
+ tid.Seconds.ToString().PadLeft(2, '0')
+ ":" + tid.Milliseconds.ToString().PadLeft(3, '0');
}
}
}