Zegar analogowy. Podstawowe funkcje graficzne. Visual Studio C#
Aplikacje okienkowe można wzbogacać grafiką, które może być statyczna lub dynamiczna. W jednym i drugim przypadku należy uzyskać uchwyt do kontrolki, w której będzie prezentowana grafika. Większość kontrolek ma tę możliwość, ale podstawową kontrolką do prezentowania grafiki jest PictureBox.
Cel: Wykorzystując bieżący czas systemowy napisz aplikację symulującą zegar analogowy
Krok 1. Układ komponentów
- PictureBox- sztuk 1
- StatusStrip- sztuk 1
- Timer- sztuk 1
Proponowany układ kontrolek przedstawia poniższa ilustracja
Krok 2. Definiujemy zmienne
Każda z trzech wskazówek zegar analogowego zachowuje się prawie w identyczny sposób. Różnice, to prędkość poruszania oraz długość. Można tak opracować (zoptymalizować) zmienne oraz funkcje, które tym samym kodem obsłużą każdą ze wskazówek.
Wykorzystamy typ wyliczeniowy enum do zdefiniowania rodzaju wskazówek oraz kilka zmiennych, do przechowywania długości wskazówek oraz współrzędnych osi wskazówek
enum TYPWSKAZOWKI {SKUNDOWA, MINUTOWA, GODZINOWA};
public partial class Form1 : Form
{
int Lh,//dlugosc godzinowej
Lm,//dlugosc minutowej
Ls;//dlugosc sekundowej
int x0;//wspoprzedne zaczepienia osi wskazowek
int y0;
public Form1()
Krok 3. Ustalamy parametry zegara
Funkcja ustalająca parametry zegara związane z długością wskazówek oraz współrzędnymi zaczepienia ich osi obrotu, może być użyta w kilku sytuacjach. Po pierwsze, w momencie uruchomienia programu (zdarzenie Load). Po drugie, przy zmianie rozmiarów okna aplikacji ( zdarzenie Resize kontrolki pictureBox1).
Kod funkcji ustalającej parametry zegara
void ParametryZegara()
{
//oblicz wsp. osi wskazowek
x0 = pictureBox1.Width / 2;
y0 = pictureBox1.Height / 2;
//oblicz dlugosci wskazowek
Lh = x0 / 3;
Lm = (int)(x0 / 2.5f);
Ls = x0 / 2;
}
Wywołujemy ją w dwóch miejscach
private void Form1_Load(object sender, EventArgs e)
{
ParametryZegara();
}
oraz
private void pictureBox1_Resize(object sender, EventArgs e)
{
ParametryZegara();
}
Sprawdź czy program się kompiluje bez błędów. Na tę chwilę po uruchomieniu programu nic wizualnego nie będzie się dziać.
Krok 4. Ruch wskazówki
Ruch dowolnej wskazówki odbywa się na tych samych zasadach. Należy ustalić bieżący kąt wychylenia wskazówki na podstawie odczytu aktualnego czasu. Ustalony kąt należy zamienić na radiany i skorzystać z funkcji sinus i cosinus. Obie funkcje wymagają podania argumentu wartości kąta wyrażonego w radianach.
Współrzędne końca dowolnej wskazówki obliczymy z zależności trygonometrycznych w trójkącie prostokątnym
Oprócz powyższych zależności trygonometrycznych musimy odpowiednio ustalić bieżący kąt wychylenia. Wychylenie każdej wskazówki zależy od bieżącego czasu.
Na przykład dla wskazówki godzinowej, wartość 14 h oznacza, że na tarczy zegara jest wychylona o 30o w prawo od pionu (godziny 12). Odpowiednie analogie należy ustalić dla wskazówki minutowej i sekundowej.
Proponowany kod uniwersalnej funkcji ustalającej współrzędne końca dla każdej wskazówki liczone względem punktu zaczepienia znajduje się poniżej
void wskazowka(Graphics g, Color k, int grubosc, int wspX, int wspY, int dl, int czas, TYPWSKAZOWKI typ)
{
int wartoscNaTarczy = 0;
switch (typ)
{
case TYPWSKAZOWKI.SEKUNDOWA: wartoscNaTarczy = (czas % 60)*360/60; break;
case TYPWSKAZOWKI.MINUTOWA: wartoscNaTarczy = (czas % 60)*360/60; break;
case TYPWSKAZOWKI.GODZINOWA: wartoscNaTarczy =(czas % 12)*360/12; break;
}
float alfa = (float)(wartoscNaTarczy)-90;
float radiany = 3.14f * alfa / 180;
int yk = (int)(dl * Math.Sin(radiany));
int xk = (int)(dl * Math.Cos(radiany));
g.DrawLine(new Pen(k, grubosc), wspX, wspY, wspX + xk, wspY+yk);
}
Uwaga. Parametr Graphics g jest uchwytem do kontrolki, na której powierzchni będzie rysowana wskazówka (cały zegar). Ponadto, linia kodu
float alfa = (float)(wartoscNaTarczy)-90;
przesuwa w fazie o 90o w lewo ustalony kąt wychylenia wskazówki z tego powodu, że układ odniesienia współrzędnych ekranowych jest obrócony o 90o w prawo.
Funkcja wskazówka, będzie cyklicznie wywoływana w funkcji rysującej zegar. Skompiluj program i sprawdź czy nie masz błędów w kodzie.
Krok 5. Rysujemy zegar
Kod proponowanej funkcji rysującej wszystkie wskazówki zegara ma postać
private void rysuj(IntPtr uchwytEkranuObiektu, int wspX, int wspY, int Lh, int Lm, int Ls)
{
int x0 = wspX;
int y0 = wspY;
string t = DateTime.Now.ToString("T");
DateTime czas = DateTime.Now;
toolStripStatusLabel1.Text = t;
Graphics g = Graphics.FromHwnd(uchwytEkranuObiektu);
Color c = Color.FromArgb(255, 255, 255, 255);
g.Clear(c);
c = Color.FromArgb(255, 244, 109, 18);
wskazowka(g, c, 5, wspX, wspY, Lh, czas.Hour,TYPWSKAZOWKI.GODZINOWA);
wskazowka(g, c, 3, wspX, wspY, Lm, czas.Minute,TYPWSKAZOWKI.MINUTOWA);
wskazowka(g, c, 1, wspX, wspY, Ls, czas.Second, TYPWSKAZOWKI.SEKUNDOWA);
g.Dispose();
}
Na wstępie wywołamy ją w zdarzeniu zmiany rozmiaru kontrolki PictureBox. Uwaga. Właściwość Dock tej kontrolki należy ustawić na Fill.
Uaktualnij zawartość funkcji Resize kontrolki pictureBox1 na tę postać
private void pictureBox1_Resize(object sender, EventArgs e)
{
ParametryZegara();
rysuj(pictureBox1.Handle, x0, y0, Lh, Lm, Ls);
}
Skompiluj program i sprawdź efekt działania po rozciągnięciu myszką rozmiarów okna formatki. Prawidłowo działająca aplikacja pokaże obraz bieżącego czasu na zegarze analogowym
Krok 6. Uruchamiamy zegar
Ustaw odpowiednie właściwości kontrolki Timer (pole Enabled na True, pole Interval na 1000, czyli 1000 milisekund, co odpowiada jednej sekundzie)
Jeżeli już mamy wszystkie funkcje gotowe i właściwie podpięte pod zdarzenia, to uruchomienie zegara jest proste. Wystarczy wywołać zdarzenie Tick kontrolki timer1
private void timer1_Tick(object sender, EventArgs e)
{
rysuj(pictureBox1.Handle, x0, y0, Lh, Lm, Ls);
}
Skompiluj i uruchom program. Jeżeli nie masz błędów kompilacji, to zegar zwraca analogowo czas odczytany z systemu