Budzik w C#
Autor:
Marcin Hałaczkiewicz
Opublikowano:
20 maja 2006
Odsłon:
101 993
Zajmiemy się dzisiaj napisaniem prostego budzika. Nauczymy się minimalizować
program do traya, wykorzystamy także menu kontekstowe (pojawia się po
naciśnięciu prawego przycisku myszy). Do odliczania czasu posłużymy się
kontrolką Timer, która 10 razy na sekundę będzie sprawdzać czas systemowy
i odpowiednio reagować. Teoretycznie można by wykorzystać sam Timer do
odmierzania czasu, jednak element ten robi to dość niedokładnie.
Tworzymy nowy projekt o nazwie Budzik, formę nazywamy frmBudzik
i jeszcze raz wpisujemy Budzik we właściwości Text formatki. Ustawiamy pole
AcceptButton na cmdUstaw, dzięki czemu przycisk, który za chwilę
utworzymy będzie domyślnie aktywny dla formy. Następnie zmieniamy
AutoSizeMode na GrowAndShrink oraz MaximizeBox na false
- uniemożliwi to zmianę rozmiaru formy i jej maksymalizację. Kolejną rzeczą
będzie utworzenie czterech etykiet. We właściwościach Text pierwszych
dwóch wpisujemy Alarm i Czas, ich nazwy są nieistotne. Kolejne
dwie nazywamy lblAlarm (w polu Text wpisujemy nie ustawiono)
i lblCzas (czyścimy Text). Dodajemy jeszcze pole tekstowe oraz
przycisk i kolejno nadajemy im nazwy txtAlarm i cmdUstaw. Dla
txtAlarm ustawiamy właściwość Visible na false,
następnie układamy elementy, zmieniamy rozmiar formy. Wszystko powinno wyglądać
mniej więcej tak (oczywiście czasu nie będzie widać):

txtAlarm ma być w tym samym miejscu co lblAlarm. Oto screen,
gdy kontrolka ta jest widoczna:

Zajmijmy się teraz ikonką w trayu oraz menu kontekstowym z nią związanym.
Najpierw utwórzmy menu, jest to kontrolka ContextMenuStrip, nadajemy jej
nazwę mnuIkonaTray (jej właściwości standardowo ukarzą się w okienku
Properties). U góry formy zobaczymy projekt naszej listy. W miejscu, gdzie
widoczny jest napis Type Here wpisujemy Pokaż, w polu pod spodem
Ustaw, a jeszcze niżej Wyłącz. Następnie klikamy kolejno na każdym
z elementów menu i w okienku z właściwościami zmieniamy ich nazwy na
odpowiednio: mnuPokaz, mnuUstaw i mnuWylacz. Teraz
utworzymy zdarzenia odpowiadające kliknięciu na każdej z nich. Zacznijmy od
mnuPokaz - klikamy na nim 2 razy. Wewnątrz funkcji wpisujemy:
IkonaTray.Visible = false;
this.Show();
this.WindowState =
FormWindowState.Normal;
Posłuży ona do pokazania formy (po zminimalizowaniu będziemy ją ukrywać, ale
o tym później) oraz ukrycia ikonki z traya.
Teraz ta sama procedura (podwójne
kliknięcie) z mnuUstaw, wpisujemy kod:
this.Show();
this.WindowState = FormWindowState.Normal;
IkonaTray.Visible = false;
cmdUstaw_Click(sender,
e);
Funkcja ta spowoduje pokazanie się okna programu oraz zostanie wywołany efekt
kliknięcia w przycisk cmdUstaw. Oprogramujmy teraz ostatni element menu
mnuWylacz. Będzie on po prostu wyłączać program za pomocą polecenia:
Application.Exit();
Menu już utworzone, zajmijmy się reprezentacją aplikacji w trayu.
Odpowiedzialna jest za to kontrolka NotifyIcon. Dodajemy ją do formy i
nazywamy IkonaTray. W katalogu z projektem znajduje się plik bell.ico. Użyjemy tej ikony jako ikonki do wyświetlania w trayu. Aby to zrobić wybieramy bell.ico we właściwości Icon dla kontrolki. Chcemy aby ikonka była widoczna tylko, gdy program
będzie zminimalizowany (wtedy forma będzie niewidoczna), więc właściwość
Visible ustawiamy na false. Aby menu, które utworzyliśmy było
powiązane z IkonaTray,
wybieramy jego nazwę w polu ContextMenuStrip. Dodajmy teraz obsługę dwóch
zdarzeń dla ikony: MouseClick oraz MouseMove. W kodzie pierwszego
wpisujemy:
if (e.Button == MouseButtons.Left)
mnuPokaz_Click(sender,
e);
Innymi słowy po kliknięciu lewym przyciskiem myszy na ikonce wywołamy ten sam
efekt co po wybraniu Pokaż w menu, czyli ukazanie się formy. W kodzie
zdarzenia MouseMove wpisujemy:
IkonaTray.Text = "Czas: " + lblCzas.Text +
"\nAlarm:
" + lblAlarm.Text
Gdy przytrzymamy myszkę nad obrazkiem w trayu pojawi nam się napis przechowywany we
właściwości Text. Zdarzenie MouseMove będzie pilnować, aby
etykieta ta zawierała aktualny.
Przejdźmy na chwilę do widoku kodu formy, dopiszmy w konstruktorze
licznik.Start(); i dodajmy do formy następujące zmienne:
private DateTime alarm = new
DateTime();
private DateTime teraz;
private bool gra = false;
private bool ustawiony = false;
private SoundPlayer dzwonek = new
System.Media.SoundPlayer("whistle.wav");
private TimeSpan czastrwania = new
TimeSpan(0, 1, 0);
private DateTime koniecalarmu;;
alarm posłuży do przechowywania czasu, w którym ma się uruchomić
budzik. teraz będzie pomocniczą zmienną reprezentującą aktualny w danym
momencie czas. gra będzie "wiedzieć" czy dzwonek budzika właśnie gra,
ustawiony "powie nam" czy budzik jest ustawiony. dzwonek należący do
klasy System.Media.SoundPlayer (nowość w .NET 2.0) będzie reprezentować
melodię wykorzystywaną do budzenia. Plik whistle.wav, który ją zawiera, musi znajdować
się w katalogu z programem. czastrwania przechowa długość trwania alarmu,
a koniecalarmu będzie "wiedzieć", o której dzwonek ma przestać grać.
Wracamy do widoku graficznego formy i dodajemy kontrolkę Timer.
Nazywamy ją licznik, właściwość Interval pozostawiamy bez zmian
(100). Klikamy na kontrolkę dwa razy, aby utworzyło się zdarzenie Tick. W
jego wnętrzu wpisujemy kod:
teraz = DateTime.Now;
lblCzas.Text = teraz.ToString("T");
if (ustawiony &&
teraz.Hour == alarm.Hour &&
teraz.Minute ==
alarm.Minute &&
teraz.Second ==
alarm.Second && !gra)
{
gra = true;
mnuUstaw.Text = "Stop";
cmdUstaw.Text = "Stop";
koniecalarmu =
DateTime.Now.Add(czastrwania);
dzwonek.PlayLooping();
}
if (gra)
{
if (koniecalarmu.Hour == teraz.Hour
&&
koniecalarmu.Minute == teraz.Minute
&&
koniecalarmu.Second == teraz.Second)
{
mnuUstaw.Text = "Ustaw";
cmdUstaw.Text = "Ustaw";
gra = false;
dzwonek.Stop();
}
}
Kod ten będzie kontrolował wyświetlanie aktualnego czasu, a w odpowiednim
momencie uruchomi alarm. Jeśli budzik gra, to wyłączy go po upływie czasu
zawartego w czastrwania (1 minuta). Do odgrywania pliku dźwiękowego
używamy funkcji PlayLooping(), która będzie odtwarzać melodię w kółko.
Zatrzymujemy ją przy pomocy metody Stop().
Zajmijmy się następnie przyciskiem cmdUstaw. Klikamy na nim dwa razy i
wewnątrz zdarzenia wpisujemy:
if (cmdUstaw.Text == "Ustaw")
{
cmdUstaw.Text = "OK";
lblAlarm.Visible = false;
txtAlarm.Visible
= true;
txtAlarm.Focus();
}
else if (cmdUstaw.Text == "OK")
{
DateTime tmp = new DateTime();
try
{
tmp =
DateTime.Parse(txtAlarm.Text);
}
catch
{
lblAlarm.Text = "nie ustawiono";
ustawiony = false;
txtAlarm.Visible = false;
lblAlarm.Visible = true;
cmdUstaw.Text
= "Ustaw";
MessageBox.Show("Błąd", "Błąd", MessageBoxButtons.OK,
MessageBoxIcon.Warning);
return;
}
alarm = tmp;
lblAlarm.Text =
alarm.ToString("T");
txtAlarm.Visible
= false;
lblAlarm.Visible
= true;
ustawiony = true;
cmdUstaw.Text = "Ustaw";
}
else if (cmdUstaw.Text == "Stop")
{
gra = false;
dzwonek.Stop();
cmdUstaw.Text = "Ustaw";
mnuUstaw.Text = "Ustaw";
}
Przycisk obsługuje trzy swoje wersje. Pierwsza to taka, gdy wyświetlany jest
napis Ustaw. Zmienia ona tekst na OK oraz ukrywa lblAlarm i
pokazuje txtAlarm, dzięki czemu można wpisać nowy czas alarmu. Druga
opcja - napis OK - akceptuje lub nie nowo wpisany czas. Robi to za pomocą
bloku try {} catch {}, który służy do przechwytywania wyjątków. Próbuje
przekształcić wpisany string na czas. Jeśli się nie uda, zostanie zgłoszony
wyjątek, znów ukarze się lblAlarm i schowa txtAlarm. W przeciwnym
wypadku nowy czas alarmu zostanie ustawiony oraz wyświetli się na odsłoniętej
lblAlarm (txtAlarm stanie się niewidoczne). Ostatnia funkcja
przycisku cmdUstaw - Stop - służy do zatrzymywania budzika, gdy
alarm się rozlega. Identyczną rolę jak cmdUstaw pełni element menu
mnuUstaw dlatego nazwy z Ustaw na Stop zmieniamy dla obydwu.
Na końcu oprogramujmy zdarzenie Resize dla formy. Zajmie się ono
uniewidocznieniem okna aplikacji oraz pokazaniem ikonki w trayu. Oto jego kod:
if (this.WindowState ==
FormWindowState.Minimized)
{
this.Hide();
IkonaTray.Visible = true;
}
Tak oto ukończyliśmy kolejny program. Nauczyliśmy się korzystać z traya oraz
z menu kontekstowych - bardzo ważnych elementów systemu Windows. Oprócz
oczywistej funkcji budzenia, programik można wykorzystać również do np.
poinformowania, o tym, że zaraz odjeżdża autobus czy nawet jako alternatywny dla windowskiego
zegarka :)
Stworzony tutaj program wraz z plikami źródłowymi możemy pobrać stąd.
Komentarze
Bardzo jasno i wyraźnie napisane
Przyda sie :)
Pozdro dla redakcji!
Buddy,
21 maja 2006, 20:06
Przydał by się jeszcze gotowy projekt do ściągnięcia.
Anonim,
21 maja 2006, 22:00
uuu Anonim ty... skypto-podbierco-żerco
Anonim,
21 maja 2006, 22:40
Na 2. stronie artykułu, na samym dole jest link do gotowego projektu...
Kuba,
22 maja 2006, 07:27
Zarobiste poprostu kul ale nimam tego na kompie tylko gram se u kolegi ,ale jest bardzo fajne
Komentarz,
25 maja 2006, 17:26
Świetny tutorial! :) Naprawe sporo cennych informacji, minusem jest tylko niekiedy zła kolejność przedstawiania kodu (odwoływanie się do komponentow, zanim jeszcze je wsadzimy na formę), ale ogólnie tutek na 5+! :)
m010ch,
11 czerwca 2006, 15:45
Jeszcze dwie sprawy, o których w opisie nie wspomniałeś: TRZEBA zdefiniować jakąs ikonę dla komponentu IkonaTray (właściwość 'Icon'), w przeciwnym wypadku - mimo, iż program jest minimalizowany do traya, to w trayu go nie widać, ponieważ nie ma co go tam reprezentować. Druga sprawa to brak instrukcji 'this.Show();' dla kliku na elemencie menu 'mnuPokaz' - przez co forma wraca do postaci normalnej, ikonka znika z traya, ale forma nie jest pokazywana ;)
m010ch,
11 czerwca 2006, 15:58
Bardzo trafne uwagi - po drobnych poprawkach wszystko jest już ok. Zauważ, że były to jedynie niedopatrzenia w treści artykułu, w treści programu wszystko było tak jak być powinno.
Marcin Hałaczkiewicz,
12 czerwca 2006, 21:53
Bardzo dobry tutorialik :) Gratuluje !
fones,
25 czerwca 2006, 13:45
The BEST:):):):)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!....................
KaSiA;),
28 czerwca 2006, 16:48
VS 2005 jest dla mnie nowym środowiskiem i mam problem w znalezieniu zdarzeń MauseMove i MauseClick w prperites IconaTay(co wynika z opisu). Gdzie jest konstruktor ? Z tego co się orietuje przy powoływaniu obiektu klasy uruchamiany jest konstruktor nazwany jak klasa tu kazdy przycisk ,label itp jest obiektem roznych klas i sorry za moje rozgarniecie ale nie widze jasno zadeklarowanego kodu konstruktora do ktorego mam wklepać kod :licznik.Start();
poczatkujący_a_jednak,
10 sierpnia 2006, 20:50
Super artykuł. Mam jednak pytanie. Po uruchomieniu program zajmuje w pamięci prawie 10 mb, po minimalizacji i dalszym użytkowaniu już mniej. Wiecie może co jest przyczyna?
WoojO,
17 sierpnia 2006, 00:04
Jestem poczatkujacy i ciezko jakos wychodzi rozumienie kodu. Co prawda pod kodem albo przed nim jest zawsze wyjasnienie ale bardziej zrozumiale by byly komentarze w kodzie z opisem co do czego a przynajmniej tak mi sie wydaje.
W kodzie odwolujemy sie czesto do czegos co jeszcze nie istnieje przez co trzeba recznie cale wpisac a przy debugowaniu sa informacje ze odwolujemy sie do czegos co nie istnieje ale tylko jednego nie da sie zrobic i to opisanego na samym poczatku: aby w AcceptButton ustawic cmdUstaw najpierw musimy go nanies na forme a nie odwrotnie.
Tutorial chyba rozni sie od gotowego projektu np zmieniamy tutaj nazwe formy a w gotowym tego nie ma...
Problem mialem z SoundPlayerem gdyz aby go urzyc po pierwsze trzeba dodac using System.Media a nie widze tego w tutorialu no i z wgraniem wave w odpowiednie miejsce gdyz wskazowka "do projektu" nie jest scisla gdyz nalezy go umiescic w \bin\debug
poczatkujacy_a_jednak:
MouseMove i MouseClick znajdziesz w Properties i Events(to taka zolta blyskawica)
konstruktor ktorego szukasz to fragment kodu:
public frmBudzik()
{
InitializeComponent();
licznik.Start();
}
Adam,
28 sierpnia 2006, 19:49
hey, mam trzy pytanka do programu: 1) deklarujemy 4 zmienne typu DateTime ale tylko przy dwoch jest "= new DateTime();" - dlaczego?? 2) przy konwersji czasu na stringa podajemy ("T") - jw 3) TimeSpan(0, 1, 0) - co oznaczja kolejne cyfry ??
Adam,
29 sierpnia 2006, 13:19
pod drugim obrazkiem zrobiłeś błąd: napisałeś "ukarzą"
:D,
14 sierpnia 2007, 20:50
Well done ... :)
Fuku,
26 września 2007, 00:52
Ogólnie świetna sprawa, fajnie, że coś takiego jest!
Jest parę rzeczy, które drażnią, np odwoływanie się obiektów, metod, których jeszcze nie ma. Dla osoby, która z programowaniem już miała kontakt nie będzie to wielką przeszkodą natomiast dla osoby świeżej będzie to zupełne zagmatwanie kodu. Taka osoba będzie się zastanawiała co to jest, skąd się to wzięło itd.
Paweł,
9 listopada 2007, 09:09
Ogólnie bardzo spoko ale dopatrzyłem się drobnego błędu - mało znaczącego ale jednak. Mianowicie timer "licznik" powinien być ustawiony na 1000ms a nie na 100ms. Dlaczego? Otóż w sekundzie, w której włącza się alarm, program rozpoczyna odgrywanie dźwięku 10-krotnie, ponieważ licznik sprawdza czas co 100ms, a więc 10 razy na sekundę. Niepotrzebnie, bo wystarczy jeden raz na sekundę, czyli timer powinien być ustawiony na 1000ms. Ten błąd może denerwować w przypadku kiedy chcemy zastąpić dźwięk np. jakimś komunikatem - okienko pojawia się wtedy na ekranie 10 razy.
Pozdro 4all ;))
Arturrrro,
20 marca 2008, 19:42
"wpisujemy Budzik we właściwości Text formatki." A dokładniej?
misiekk,
17 sierpnia 2008, 16:45
Dodałem swój plik dźwiękowy i po publikacji i instalacji w czasnie uruchamiania dźwieku wyskakuje błąd:
System.IO.FileNotFoundException: Sprawdź, czy plik dźwiękowy istnieje w podanej lokalizacji.
mtt,
4 października 2008, 19:04
Dokaladnie dobrze ktos napisal! Dlaczego odwolujecie sie najpierw do czegos co nie jest stworzone! To wszystko mega miesza!
Ale ogolnie tutorial siwetny choc bym w nim troche poprawila np te bledy ze brakuje srednika albo sa dwa... Ale to szczegoly bo sie wie o co chodzi najgorzej jak nagle pisze jakies odwolanie do czegos czego jeszcze nie mam:/
Canim,
18 października 2008, 13:59
Nie jest jasno napisane co trzeba zrobic... Jestem poczatkujacym w C# i juz nie rozumiem tego:"We właściwościach Text pierwszych dwóch wpisujemy Alarm i Czas, ich nazwy są nieistotne." Gdzie to jest?!
gosc,
8 czerwca 2009, 18:28
Padają tutaj pytania RETORYCZNE!!!!!!!!!!!!! Nie zadam kolejnego :|
gregor,
7 lipca 2009, 13:23
Wszystko działa poprawnie :) Idzie się pobawić :D
Mimek,
31 lipca 2009, 13:17
zastanawia mnie po co ten kurs jest skoro nie wprowadza po kolei wszystkich elelementów wykorzystanych w programie
żeby ci co już C# znają mogli się upewnić że potrafią budzik stworzyć?
lol,
30 października 2011, 11:28