UWAGA! Promocja dla firm - MICROSOFT OFFICE 365  na 12 miesiecy ZA DARMO! Tylko na CentrumXP.pl!
Wielka promocja Office 365 na CentrumXP.pl!
Do góry Skomentuj

Analogowy zegarek

Analogowy zegarek

Autor: Maciej Zelwak Opublikowano: 7 grudnia 2007 Odsłon: 101 086

W artykule zajmiemy się programowaniem analogowego zegarka. Przy okazji ćwicząc posługiwanie się biblioteką GDI +, która to oferuje dostęp do szeregu metod graficznych. Począwszy od tych najprostszych, jak rysowanie figur oraz ich wypełnianie, skończywszy na bardziej zaawansowanych własnościach, takich jak anti-aliasing czy też alpha blending. Oczywiście będziemy korzystać tylko z niewielkiej ich części, co jednak nie będzie przeszkodą, w uzyskaniu efektu podobnego do jednego z gadżetów systemu Windows Vista.

Niezbędna matematyka

Zanim zajmiemy się aspektem programistycznym, musimy sobie przypomnieć pewne podstawy matematyczne. Wiadomo, że okrąg ma 360°, czyli 2? lub 1 radian. Dzieląc tą wielkość, przez ilość godzin na tarczy zegara, otrzymamy odległość jaka powinna dzielić kolejne etykietki godzin, czyli 30°. W podobny sposób wyznaczymy kąt dla poszczególnych wskazówek.

sekundyTic = 2.0 * Math.PI * sekundy / 60.0;

Wyrażenie sekundy/60 możemy potraktować jako wartość procentową obrotu wskazówki. Dla przykładu kiedy liczba sekund wynosi 30, czyli wskazówka znajduje się nad szóstką, wartość ta jest równa 50%. Ponieważ wartości kątów muszą być wyrażone w radianach, procent obrotu jest mnożony przez 2?. Znając wartość kąta oraz promień, możemy obliczyć współrzędne punktu określającego koniec wskazówki bądź położenie etykietki. Używamy do tego celu funkcji trygonometrycznych, cosinus do wyznaczenia współrzędnej x, sinus do wyznaczenia współrzędnej y.

Piszemy aplikację

Pora zabrać się za implementację. Tworzymy nowy projekt typu Window Application i wprowadzamy nazwę, czyli AnalogClock. Zmieniamy nazwę pliku z formą na MainForm.cs. Tarczę zegara będziemy rysować w środku okna, więc ustawimy jego rozmiar (Size) na 170x170. Przechodzimy do widoku kodu i sprawdzamy czy używamy niezbędnych przestrzeni nazw.

using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Drawing;

Na początku klasy dodamy zmienne globalne wykorzystywane w programie.

private Rectangle rect;
private LinearGradientBrush obramowanieKolor;
private SolidBrush tarczaKolor;
private SolidBrush liczbyKolor;
private SolidBrush podpisKolor;
private Pen cienTarczyKolor;
private Pen pioro;
private Pen pioroSek;
private int srednica;
Następnie utworzymy pierwszą metodę, którą nazwiemy inicjujNarzedzia(), a jej wywołanie dopiszemy do konstruktora. Zainicjujemy w niej wszystkie obiekty graficzne, których będziemy używać. GDI+ umożliwia rysowanie każdym obiekcie graficznym, może to być  PictureBox, Panel, lub po prostu mapa bitowa. W tworzonym właśnie programie będzie to obszar roboczy formy. Zmienna ClientSize zawiera jego wymiar. Użyjemy jej do stworzenia obiektu typu Rectangle, czyli prostokąta, o wymiarach zegarka.  srednica = 120;
rect = new Rectangle(this.ClientSize.Width / 2 - srednica / 2, this.ClientSize.Height / 2 - srednica / 2, srednica,srednica);

Następnie zaalokujemy resztę potrzebnych zasobów. Jednym z nich jest pióro (pen), za pomocą którego możemy kreślić po ekranie. Posiada ono wiele właściwości, najważniejszymi dla nas są: kolor (Color), szerokość linii (Width), styl (DashStyle) oraz rodzaj początku i końca linii (StartCap i EndCap). Do określenia niestandardowych barw używamy metody FromArgb klasy Color. Parametrami tej funkcji są trzy liczby całkowite z zakresu 0..255, określające intensywność czerwieni, zieleni oraz błękitu w tworzonym kolorze. Obiekty Brush, czyli inaczej mówiąc pędzle, pozwalają określić rodzaj wypełnienia. 

obramowanieKolor = new LinearGradientBrush(rect, Color.FromArgb(0, 0, 0), Color.FromArgb(60, 60, 60), 60);
tarczaKolor = new SolidBrush(Color.WhiteSmoke);
liczbyKolor = new SolidBrush(Color.FromArgb(10, 10, 10));
podpisKolor = new SolidBrush(Color.Blue);
cienTarczyKolor = new Pen(Color.FromArgb(180, 180, 180), 3);
pioro = new Pen(Color.FromArgb(10, 10, 10), 4);
pioroSek = new Pen(Color.Red, 2);

Teraz ustawiamy parametry końcówek piór, które będą odpowiedzialne za rysowanie wskazówek. Jedna z końcówek będzie okrągła a druga zakończona strzałką.

pioro.EndCap = LineCap.ArrowAnchor;
pioro.StartCap = LineCap.RoundAnchor;
pioroSek.EndCap = LineCap.ArrowAnchor;
pioroSek.StartCap = LineCap.RoundAnchor;
cienTarczyKolor.EndCap = LineCap.ArrowAnchor;
cienTarczyKolor.StartCap = LineCap.RoundAnchor;

Wróćmy do widoku formy i dodajmy do niej obsługę zdarzenia Paint, w którym to będziemy wywoływać funkcję odpowiedzialną za rysowanie. Obsługa zdarzenia Paint jest wykonywana za każdym razem, kiedy zachodzi potrzeba odświeżenia wyświetlanej kontrolki. 

private void MainForm_Paint(object sender, PaintEventArgs e)
{
rysuj(e.Graphics);
}

Po czym przechodzimy do tworzenia metody odpowiedzialnej za rysowanie, czyli rysuj(Graphics graphics). Zacznijmy od zdefiniowania niezbędnych zmiennych:

//wspolrzedne srodka okna
int srWidth;
int srHeight;

//czas w danej chwili
int minuty;
int godziny;
double sekundy;

//rotacje wskazowek
double minutyTic;
double godzinyTic;
double sekundyTic;

float promien; //dlugosc wskazowki
int ramka; //szerokość czarnej ramki
int stopnie; //odleglosc miedzy liczbami

DateTime czas;

Zainicjujemy część z nich. W zmiennych srWidth i srHeight przechowujemy współrzędne środka formy. Szerokość czarnego obramowania przechowuje ramka.

srWidth = this.ClientSize.Width / 2;
srHeight = this.ClientSize.Height / 2;

ramka = 18;

Możemy już zająć się tarczą zegara. Korzystamy z metod FillEllipse i DrawEllipse, które umożliwiają rysowanie elips. Pierwsza z nich wypełnia wnętrze figury przy pomocy pędzla, który podajemy jako parametr. Efektem wypełnienia może być gradient, wzór zaczerpnięty z bitmapy lub po prostu wybrany kolor. Druga z metod pozostawia środek pusty. Oprócz pędzla podajemy również wymiary oraz położenie rysowanego okręgu. Możemy to zrobić na dwa sposoby, podając cztery liczby, czyli współrzędne dwóch przeciwległych narożników prostokąta w który będzie wpisana elipsa. Bądź też podając prostokąt w który będzie wpisana elipsa jako obiekt typu Rectangle.

graphics.FillEllipse(obramowanieKolor, srWidth - srednica / 2 - ramka/2, srHeight - srednica / 2 - ramka/2, srednica + ramka, srednica + ramka);
graphics.FillEllipse(tarczaKolor, rect);
graphics.DrawEllipse(cienTarczyKolor, rect);

Ułatwimy sobie pozycjonowanie liczb i przenieśmy początek układu współrzędnych obszaru roboczego formy z lewego górnego rogu do jej środka.

graphics.TranslateTransform(srWidth, srHeight);

Następnie ustawimy rozmiar, typ i formatowanie czcionki. Oczywiście jej wygląd nie jest obligatoryjny i zależy od upodobań programisty.

StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
Font textFont = new Font("Century", 12F, FontStyle.Bold);

Ponieważ nie zdefiniowaliśmy jeszcze położenia kolejnych liczb, robimy to teraz:

stopnie = 360 / 12;
promien = 49;

Dla przejrzystości kodu dodajmy dwie osobne metody, których jedynym zadaniem będzie zwracanie współrzędnych dla cyfr i dekoracji.

private float obliczX(float stopnie, float r)
{
return (float)(r * Math.Cos((Math.PI / 180) * stopnie));
}

private float obliczY(float stopnie, float r)
{
return (float)(r * Math.Sin((Math.PI / 180) * stopnie));
}

Wracamy do funkcji rysuj(Graphics graphics) i w pętli dodajemy po kolei dwanaście liczb.

for (int i = 1; i <= 12; i++)
{
graphics.DrawString(i.ToString(), textFont, liczbyKolor, -1 * obliczX(i * stopnie + 90, promien)+1, -1 * obliczY(i * stopnie + 90, promien)+2, format);
}

Bezwzględnie należy pamiętać o pomnożeniu obu współrzędnych przez -1, w przeciwnym wypadku otrzymalibyśmy liczbę 12 na dole zegarka.

Dalej w podobny sposób dodajemy cztery elementy dekoracyjne. Oczywiście pętlę można wykonać dwanaście razy.

promien = 61;
stopnie = 360 / 4;

for (int i = 1; i <= 4; i++)
{
graphics.DrawEllipse(pioro, -1 * obliczX(i * stopnie + 90, promien)-1, -1 * obliczY(i * stopnie + 90, promien)-1, 2, 2);
}

Przechodzimy do kreślenia wskazówek. Aplikacja będzie odświeżana kilkanaście razy na sekundę, dzięki temu uzyskamy efekt ciągłego ruchu wskazówki sekund, taki jak w cyfrowych zegarkach. Najpierw pobieramy aktualny czas i zapisujemy go do zmiennych:

czas = DateTime.Now;
godziny = czas.Hour;
minuty = czas.Minute;
sekundy = czas.Second + (czas.Millisecond * 0.001);

Obliczamy rotację:

godzinyTic = 2.0 * Math.PI * (godziny + minuty / 60.0) / 12.0;

Każda wskazówka będzie rzucała cień na tarczę. Obliczamy współrzędne obu końców i rysujemy linię wykorzystując metodę DrawLine().

Point pktSrodek = new Point(0, 0);
Point pktCienGodzina = new Point((int)((promien * Math.Sin(godzinyTic)) + 2),(int)((-(promien) * Math.Cos(godzinyTic)) + 2));
graphics.DrawLine(cienTarczyKolor, pktSrodek, pktCienGodzina);

Point pktWskGodzina = new Point((int)(promien * Math.Sin(godzinyTic) ), (int)(-(promien) * Math.Cos(godzinyTic)));
graphics.DrawLine(pioro, pktSrodek, pktWskGodzina);

Podobną technikę wykorzystujemy do dodania minut i sekund. Zmieniamy tylko długość promienia.

minutyTic = 2.0 * Math.PI * (minuty + sekundy / 60.0) / 60.0; promien = 57;
Point pktCienMinuta = new Point((int)(promien * Math.Sin(minutyTic) + 2), (int)(-(promien) * Math.Cos(minutyTic) + 2));
graphics.DrawLine(cienTarczyKolor, pktSrodek, pktCienMinuta);
Point pktWskMinuta = new Point((int)(promien * Math.Sin(minutyTic)), (int)(-(promien) * Math.Cos(minutyTic)));
graphics.DrawLine(pioro, pktSrodek, pktWskMinuta);

Wskazówka zegara jest znacznie cieńsza i w kolorze czerwonym.

Point pktCienSekunda = new Point((int)(promien * Math.Sin(sekundyTic)), (int)(-(promien) * Math.Cos(sekundyTic)));
graphics.DrawLine(pioroSek, pktSrodek, pktCienSekunda);

Point pktWskSekunda = new Point((int)(promien * Math.Sin(sekundyTic)), (int)(-(promien) * Math.Cos(sekundyTic)));
graphics.DrawLine(pioroSek, pktSrodek, pktWskSekunda);

Jeśli teraz uruchomimy program, po chwili zorientujemy się, że wskazówki w ogóle się nie poruszają. Musimy przerysować okno aplikacji. Przechodzimy do zakładki formy i z okna Toolbox przeciągamy Timer. Zmieniamy jego nazwę na timer. We własnościach czasomierza, ustawiamy czas odświeżania (Interval) na 100. Jeśli wpiszemy 1000 (1 sekunda), otrzymamy klasycznie poruszającą się wskazówkę. Ustawiamy Enabled na true. Klikamy dwa razy kontrolkę. Wygeneruje się metoda, do której dodamy tylko jedną linię:

private void timer_Tick(object sender, EventArgs e)
{
Invalidate();
}

Metoda Invalidate() powoduje odświeżenie zawartości kontrolki, dla której została ona wywołana. Wywołuje metodę OnPaint(), której nie należy jednak wywoływać jawnie. Metoda OnPaint() wysyła komunikat o wydarzeniu Paint do wszystkich obiektów, które potrzebują o tym wiedzieć.

Po uruchomieniu aplikacji zauważamy nieprzyjemne miganie podczas odświeżania obrazka. W celu eliminacji tego efektu włączamy podwójne buforowanie (double buffering). Technika ta polega na wykonaniu wszystkich operacji rysowania w tle, w sposób niewidoczny dla użytkownika, a następnie wyświetlenie za pomocą szybkiej operacji kopiowania. Należy odpowiednio zmodyfikować konstruktor aplikacji.

this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

Wykorzystujemy metodę SetStyle() do modyfikacji trzech właściwości: DoubleBuffer (uruchmienie podwójengo buforowania), UserPaint ( sami rysujemy od podstaw) i AllPaintingInWmPaint (za rysowanie odpowiada metoda Paint).

Następnie polepszymy jakość generowanej grafiki, poprzez wprowadzenie wygładzania krawędzi. Każdy kto grał w gry komputerowe, spotkał się z techniką anti-aliasingu. Dotyczy ona prawie wszystkich krzywych. Ze względu na konieczność uzyskania rozsądnego kompromisu między gładkością, a rozmyciem, stosuje się różne sposoby zaniku jasności. w programie decydujemy się na HighQualityBicubic.

Wystarczy dopisać gdzieś na początku metody rysuj(Graphics graphics):

graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

Dodając do konstruktora następujący kod, pozbywamy się zakładki programu z paska zadań.

this.ShowInTaskbar = false;

Działanie zegarka będziemy kończyć wybierając pozycję z rozwijanego menu. Przeciągamy z Toolboxa następną kontrolkę, tym razem będzie to ContextMenuStrip. Zmieniamy nazwę na contextMenuStrip. Dodajemy opcję Zamknij i klikamy ją dwukrotnie. Dodajemy wywołanie jednej metody:

private void zamknijToolStripMenuItem_Click(object sender, EventArgs e)
{
Close();
}

Menu pojawi się gdy klikniemy formę prawym przyciskiem myszy. Dołączamy obsługę zdarzenia reagującego na kliknięcie myszką, gdzie sprawdzamy który przycisk został użyty, jeśli prawy to wyświetlamy menu kontekstowe.

private void MainForm_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.contextMenuStrip.Show(Control.MousePosition);
}
}

Gadżet jest już prawie na ukończeniu, pozostało jeszcze pozbyć się otaczającej zegar formy. Trzeba zmienić jej kolor (BackColor) na taki, który nie występuje w obrębie zegarka. To bardzo ważne, ponieważ w przeciwnym wypadku zniknie część pikseli. Nie możemy jednak wybrać koloru zdecydowanie różniącego się od czarnej ramki, gdyż pojawi się wtedy wokół niej nieciekawa obwódka. Eksperymentalnie ustawiamy kolor RGB 59;59;59. Następnie wpisujemy tą samą wartość do właściwości TransparencyKey. Usuwamy górny pasek okna, zmieniając w tym celu własność FormBorderStyle na None.

Dopóki nie obsłużymy odpowiednich zdarzeń, nie będzie można przesuwać zegarka po ekranie. Dopiszmy więc do klasy aplikacji zmienne globalne.

private Point MouseAktualnaPoz, MouseNowaPoz, formPoz, formNowaPoz;
private bool mouseDown = false;

Wróćmy do widoku okna i dołóżmy zdarzenia dla myszki jeśli jej klawisz jest wciśnięty (MouseDown), jeśli wskażnik się porusza (MouseMove) i kiedy klawisz jest puszczony (MouseUp).

Jeśli wciśniemy lewy przycisk, w zmiennych MouseAktualnaPoz i formPoz zostaną zapisane aktualne położenia myszki i formy.

private void MainForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mouseDown = true;
MouseAktualnaPoz = Control.MousePosition;
formPoz = Location;
}
}

Przesunięcie w tym stanie myszki spowoduje wyliczenie nowych pozycji i przeniesienie zegarka w nowe miejsce.

private void MainForm_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown == true)
{
MouseNowaPoz = Control.MousePosition;
formNowaPoz.X = MouseNowaPoz.X - MouseAktualnaPoz.X + formPoz.X;
formNowaPoz.Y = MouseNowaPoz.Y - MouseAktualnaPoz.Y + formPoz.Y;
Location = formNowaPoz;
formPoz = formNowaPoz;
MouseAktualnaPoz = MouseNowaPoz;
}
}

private void MainForm_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
mouseDown = false;
}

W ten sposób zakończyliśmy tworzenie zegarka. Najlepszym sposobem na poszerzenie wiedzy z zakresu GDI+ jest eksperymentowanie z jej klasami. Dzięki temu artykułowi poznaliśmy podstawy i bazując na nich, już jesteśmy w stanie pisać własne, równie interesujące programy.

Zobacz również

Komentarze

świetny artykuł żadnych błędów, dużo nowych funkcji
compaq11, 7 grudnia 2007, 17:55
Super
ShaViNoj, 7 grudnia 2007, 22:51
Bardzo ciekawy artykuł. Zero błędów :-). W sam raz dla początkujących. ;-) Pozdrawiam, - - - John Krauch :">
Programista C#, 7 grudnia 2007, 22:54
U mnie po dodaniu graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.TextRenderingHint = TextRenderingHint.AntiAlias; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; Zegar wygląda jak bez anti-aliasingu. Kto wie jak to naprawić? I jeszcze jedno pytanie. Jak można usunąć tę aplikację z "ALT + TAB", tzn. żeby po naciśnięciu tych klawiszy nie było można wybrać tego zegarka?
shay, 8 grudnia 2007, 10:00
Witam fajny artykuł tylko szkoda że redakcja centrumxp nie dodała całego gotowego projektu do pobrania czasem bardzo to pomaga mogąc analizować kod jeśli jest taka możliwość serdecznie proszę o publikację całego projektu pozdrawiam Łukasz
Llukkass, 9 grudnia 2007, 11:32
No właśnie ja też bym bardzo prosił o cały projekt. Jestem początkujący w C# i jest to dla mnie chyba trochę za duży przeskok pomiędzy poprzednimi dwoma kursami, a tym. Z góry dziękuję i pozdrawiam.
Grzesiek, 15 grudnia 2007, 18:42
mam kilka uwag odnośnie artykułu: 0) nie ma nigdzie co zrobić aby znikła belka tytułowa aplikacji 1) niektóre obliczenia są "na około" 2) większość obliczeń można zrobić znacznie szybciej 3) cały zegarek można stworzyć używając połowy tych zmiennych których użyłeś tutaj. Jako przykład do punktu trzeciego dam choćby to przesuwanie formy. Można to samo zrealizować posiadając 2 zmienne: private Point mouseOldPos; private bool mouseDown; wtedy kod w MouseDown() powinien byc taki: mouseDown = true; mouseOldPos = Control.MousePosition; W MouseUp() oczywiscie wystarczy tylko: mouseDown = false; Natomiast kod w MouseMove() mam taki: if (mouseDown) { Point p = new Point( Location.X + Control.MousePosition.X - mouseOldPos.X, Location.Y + Control.MousePosition.Y - mouseOldPos.Y); Location = p; mouseOldPos = Control.MousePosition; } Jest to 100 razy krotsze i 10000 razy bardziej zrozumiale. Nie rozumiem także po co tworzyć po 2 punkty dla każdej wskazówki - jeden na cień a drugi dla samej wskazówki. Lepiej najpierw narysować wskazówkę, a potem zmniejszyc obie wspolrzedne punktu o 2 i narysowac wskazowke zamiast obliczac znowu funkcje trygonometryczne ktore sa strasznie wolne :| Podsumowujac: Artykul bylby fajny gdyby nie beztroskie podejscie do szybkosci dzialania i ilosci dostepnej pamieci.
moriturius, 19 grudnia 2007, 19:07
ma ktoś zrobiony cały kod?? i mógłby go podesłac na maila?? albo gdzies umieścic?
bubek, 20 stycznia 2008, 13:10
no właśnie, ma ktoś to może sklecone, działające ?... bo jakoś nie moge dojść do ładu..,jestem bardzo początkujący i zapewne popełniam jakieś oczywiste błędy..
Sielu, 20 stycznia 2008, 21:47
a już rozgryzłem :) już wsio śmiga :D
Sielu, 20 stycznia 2008, 23:43
Mozna prosic o zrodlo calosci?agencja618@wp.pl
Aleksander, 25 lutego 2008, 09:21
Zmieszałem dwa tutki: "Analogowy zegarek" i "budzik". Nie miałem zbyt wiele czasu na poprawienie błędów, więc mogą się jakieś trafić. Link do projektu: http://www.chomikuj.pl/qic/Programowanie/c*23/Alarm+Clock.7z
kwaq, 6 marca 2008, 00:24
graphics.FillEllipse(obramowanieKolor, srWidth - srednica / 2 - ramka/2, srHeight - srednica / 2 - ramka/2, srednica + ramka, srednica + ramka); graphics.FillEllipse(tarczaKolor, rect); graphics.DrawEllipse(cienTarczyKolor, rect); Po tych poleceniach powinny pojawic sie okregi a moje okno z MainForm wciaz jest cale szare - nic sie nie zmienilo. 0 errors, 0 warnings. Co jest nie tak?
m, 31 marca 2008, 11:49
przepraszam moze to glupie pytanie?? ale w czym jest pisany ten zegarek (w jakim programie?)
michalek, 17 maja 2008, 14:15
Kurs, jak sama nazwa działu wskazuje, dotyczy C# A najlepszym sposobem na pisanie w C# jest skorzystanie z visual studio C# , np. wersji Express...
DeyV, 19 maja 2008, 19:22
Niech ci Bóg w dzieciach wynagrodzi. Bardzo ciekawy tutorial.
Zubr, 21 czerwca 2008, 15:14
Super artykul:) Bardzo mi sie podoba i dobrze wprowadza do korzystania z System.Drawing ;)
Kasiek, 16 lipca 2008, 16:38
Swietne, pokazuje czytelnie co i jak

Coltain, 10 września 2008, 19:09
A jak dla mnie powinien byc dodany kod na samym koncu calosci bo jak ktps jest naprawde poczatkujacy to sie gubi w tym:/

canim, 16 października 2008, 16:54
Gdy ustawiam wartość timer.Interval = 100, zegar odswierza się dalej co 1 sekundę, czego może być to wina? wartość ustawiam w zakładce formy

staszic, 26 października 2008, 12:23
Naprawde staralem sie zrozumiec ten kurs moze jak ktos pisal juz cos takiego to wie, niestety nie wszyscy wiedza. Po komenatrzach widze ze mimo prośby uzytkowników owe forum nie postaralo sie umiescic w calości kodu. Wiec stwierdzam ze te artykuly sa nieczytelne dla wielu i sie nie nadaja.
 

Początujacy, 1 listopada 2008, 14:03
Odnośnie tej wypowiedzi:
"graphics.FillEllipse(obramowanieKolor, srWidth - srednica / 2 - ramka/2, srHeight - srednica / 2 - ramka/2, srednica + ramka, srednica + ramka); graphics.FillEllipse(tarczaKolor, rect); graphics.DrawEllipse(cienTarczyKolor, rect); Po tych poleceniach powinny pojawic sie okregi a moje okno z MainForm wciaz jest cale szare - nic sie nie zmienilo. 0 errors, 0 warnings. Co jest nie tak?"
U mnie to też występuje, doszegłem do tego, że nie wywołuje się zdażenie "Print".
ale jak to naprawić to nie mam pojęcia.

krz.rusz, 20 grudnia 2008, 23:53
Mam dokładnie ten sam problem co poprzednik. Nie moge wywołać zdażenia print i pojawia się puste okno. Jeśli chodzi o kod to został on przepisany w całości. Nie wklejony, tylko przepisany.

freemp3, 9 lutego 2009, 16:15
ja też mam ten problem co koledzy wyżej... wie ktoś jak sobie z tym poradzić?

yhy, 26 lutego 2009, 20:03
Super artykuł. Dzięki niemu napisałem zegarek w VB. Przetłumaczyłem sam z C# na VB

djmati11, 14 kwietnia 2009, 19:21
Jaki jest wzorek na sekundaTic ??

??, 23 lipca 2009, 15:45
sekundyTic = 2.0 * Math.PI * (sekundy) / 60.0; promien = 53;

Latoo, 27 lipca 2009, 13:29
Zegarek bardzo fajny, duzo nowych funkcji, ale jest jeden błąd ponieważ sekundyTic nie sa nigdzie wyliczone i pogram widzi bład. Nalezy to poprawidz wtedy program działa bez zarzutów.
MateuszG., 14 listopada 2009, 16:13
moze ktos wrzucic gotowy projekt w visualu ??? bo niechce mi sie przepisywac a pare rzeczy by mi sie moglo przydac
hip9k, 8 grudnia 2009, 22:01
Świetny poradnik dla początkujących w C#, zero błędów, trzeba się troche zastanowić i wszystko ładnie składa się w całość. Pozdrawiam!
LuckyF, 14 lutego 2010, 11:38
http://www.speedyshare.com/files/21020552/AnalogClock.rar Czy ktos wie jak włączyć antyaliasing dla przeźroczystości? Na białym tle działa ale przy przeźroczystości krawędzie są poszarpane
lu, 19 lutego 2010, 17:29
Tym, którym to nie działa niech zastosują:   [color=#0000ff; font-size: x-small">[color=#0000ff">&lt;font size="2" color="#0000ff">public [/color">[color=#0000ff">  [/color">
[size= x-small"> MainForm(){ inicjujNarzedzia(); &lt;font size="2">    [color=#0000ff; font-size: x-small">this[/color">
[size= x-small">.Paint += [/size">[color=#0000ff; font-size: x-small">new[/color">
[size= x-small"> [/size">[color=#2b91af; font-size: x-small">PaintEventHandler[/color">
[size= x-small">(MainForm_Paint);} [/size">
b4art, 27 marca 2010, 14:23
Tym ,którym nie działa funkcja Paint i nic się nie chce rysować niech zastosują: public MainForm() { this.Paint += new PainEventHandler(MainForm_Paint); }
b4art, 27 marca 2010, 14:26
Czy ktoś może wysłać cały kod? Bratan4ik@gmail.com
brat, 19 kwietnia 2010, 10:38
Dzieki b4art za podpowiedz, lata by minely zanim bym na to wpadl
dizi, 30 kwietnia 2010, 19:52
Znalazlem to o czym nie wspomnial autor artykulu, czyli "co zrobic zeby sie narysowalo". Klikamy na forme->Properties->Events -> tam znajdujemy zdazenie "Paint" i wrzucamy tam wczesniej zdefiniowana metode do rysowania Moze sie to komus jeszcze przyda, dzieki za te artykuly - nieoceniona pomoc
dizi, 1 maja 2010, 01:07
coś nie tak mam z metodą inicjujNarzedzia() bo zwraca mi nulle, przez co graphics.FillEllipse(...) wywala się błędem value cannot be null proszę o pomoc - co mam nie tak? tak zapisałem mteodę: public void inicjujNarzedzia() { srednica = 120; rect = new Rectangle(this.ClientSize.Width / 2 - srednica / 2, this.ClientSize.Height / 2 - srednica / 2, srednica, srednica); obramowanieKolor = new LinearGradientBrush(rect, Color.FromArgb(0, 0, 0), Color.FromArgb(60, 60, 60), 60); tarczaKolor = new SolidBrush(Color.WhiteSmoke); liczbyKolor = new SolidBrush(Color.FromArgb(10, 10, 10)); podpisKolor = new SolidBrush(Color.Blue); cienTarczyKolor = new Pen(Color.FromArgb(180, 180, 180), 3); pioro = new Pen(Color.FromArgb(10, 10, 10), 4); pioroSek = new Pen(Color.Red, 2); pioro.EndCap = LineCap.ArrowAnchor; pioro.StartCap = LineCap.RoundAnchor; pioroSek.EndCap = LineCap.ArrowAnchor; pioroSek.StartCap = LineCap.RoundAnchor; cienTarczyKolor.EndCap = LineCap.ArrowAnchor; cienTarczyKolor.StartCap = LineCap.RoundAnchor; }
kk, 4 czerwca 2010, 13:20
To rzuc ktos rozwiazanie, bo wywala blad przy rysowaniu, najlepiej na rapidzie.
wole JAVA i netBeans, 18 listopada 2010, 10:57
Problem rozwiazany z rysuj(), najpierw trzeba wpisac w MainForm(){ inicjujNarzedzia(); this.Paint += new PaintEventHandler(MainForm_Paint); //pB.Paint += new System.Windows.Forms.PaintEventHandler(this.pB_Paint); }   nastepnie wybrac: private void MainForm_Paint(object sender, PaintEventArgs e) { //rysuj(e.Graphics); }   private void paintBox1_Paint(object sender, PaintEventArgs e) { rysuj(e.Graphics); } mam nadzieje ze sie przyda taka mala podpowiedz poczatkujacym. I tak JAVA lepsza, w netBeans-ie taki problem to 15min a nie cala noc w .net-cie. :-)
wole JAVE i netBeans, 18 listopada 2010, 12:33
Czy ktoś posiada działający kod? Dla początkującego artykuł bez całego kodu, jest bezużyteczny.
anonim, 23 listopada 2010, 20:33
Może ktoś przesłać cały kod?? gural1004@wp.pl
gural, 28 listopada 2010, 19:47
Ludziska macie ten kod bo jestem po kursiku a ten zegar to troche za wysoka poprzeczka poki co.Dajcie jakis link do tego kodu.
miho, 2 grudnia 2010, 12:39
wszystko ok do momentu w ktorym wskazowki powinny sie przesuwac. przy kompilacji nie ma zadnego bledu, kontrolka Timer jest opisana jak w przykladzie. ma ktos pomysl jak to rozwiazac?
Marek, 9 grudnia 2010, 13:49
Bardzo proszę kogoś o umieszczenie gdzieś całego kodu.
Sylwek, 5 czerwca 2011, 15:33
Witam ma ktoś może cały kod do tej aplikacji? gdyż jestem początkujący w tej sprawie i bardzo by mi się przydał. Jeśli ktoś ma to bardzo bym prosił o podesłanie na e-mail djwrzosa@wp.pl. Z góry dziękuję i pozdrawiam.
Robert, 14 czerwca 2011, 13:31
Fajny art, bardzo mi sie podoba ale ktoś by mógł dołączyć źrodła, sa małe błędy i dla kogoś zielonego to naprawde problem.
dydko, 29 czerwca 2011, 14:20
A ja widzę błąd, nieznaczący - ale jest. A mianowicie - 360° to nie ani jeden radian, ani dwa, tylko 2? radiana, co wynosi około 6.283rad.
Xiro, 21 sierpnia 2011, 17:56
Jestem początkujący w programu w C# i nie bardzo się orientuję gdzie mam wstawić metodę SetStyle(). Trzeba ją zdefiniować jako private void SetStyle() a potem wywoływać w programie? Jeśli tak to w którym miejscu? A jeśli nie to jak należy to zrobić?:)
borsuk, 22 sierpnia 2011, 19:07
Taki hint: zauważycie na pewno, że wskazówki brzydko skaczą. Jest to spowodowane rzutowaniem współrzędnych na (int). Zamiast Point polecam użyć PointF, który nie jest ograniczony do liczb całkowitych. Współrzędne należy rzutować na (float), np: PointF pktWskSekunda = new PointF((float)(promien * Math.Sin(sekundyTic)), (float)(-(promien) * Math.Cos(sekundyTic)));
mj, 2 marca 2012, 16:41
Czy mógłby ktoś przesłac na maila magnuskacerz@interia.pl pełny kod tej aplikacji. Próbuję go napisac, ale jestem zbyt zielony i nie mogę poradzic sobie z kilkoma problemami.
kacerz, 18 maja 2012, 17:05

Dodaj swój komentarz

Zasady publikacji komentarzyZasady publikacji komentarzy

Redakcja CentrumXP.pl nie odpowiada za treść komentarzy publikowanych na stronach Portalu
i zastrzega sobie prawo do usuwania wypowiedzi, które:

  • zawierają słowa wulgarne, obraźliwe, prowokujące i inne naruszające dobre obyczaje;
  • są jedynie próbami reklamowania stron internetowych (spamowanie poprzez umieszczanie linków);
  • przyczyniają się do złamania prawa bądź warunków licencyjnych oprogramowania (cracki, seriale, torrenty itp.);
  • zawierają dane osobowe, teleadresowe, adresy mailowe lub numery GG;
  • merytorycznie nie wnoszą nic do dyskusji lub nie mają związku z tematem komentowanego newsa, artykułu bądź pliku.

Autor:

Komentarz:

Dodaj komentarz