Z cyklu boso przez Śródziemie: biblioteka GDI+ oraz jak sprawdzić, czy kursor zawiera się w figurze geometrycznej.
Dziś wykorzystam bibliotekę graficzną GDI+ i pokażę jak przetestować czy kursor zawiera się w jakiejś figurze geometrycznej. Napiszę aplikację, która będzie wyświetlała nazwę wskazanej na mapie krainy.
W tym celu biorę kostkę rosołową Knorr, odpalam Visual Sudio 2008 i tworzę nowy projekt WinForms. Do utworzonej domyślnie formy dodaję kontrolkę PictureBox, nazywam ją mapkaPictureBox i wstawiam do niej gotowy obrazek (właściwość Image w oknie Properties). Obrazkiem będzie wyszukana w googlach mapka tolkienowskiego Śródziemia na licencji GNU. Zmieniam właściwość SizeMode na StretchImage, co spowoduje dopasowanie obrazka do rozmiarów kontrolki. Do formy dodaję jeszcze labelki, które nazywam xyLabel i krainaLabel. Gotuję na małym ogniu przez 3min. ciągle mieszając 🙂
Następnie tworzę metodę obsługująca zdarzenie MouseMove, która ułatwi mi dalszą pracę. (W Form1.cs[Design] klikam obrazek, następnie w oknie Properties wybieram grupę Events i podwójnie klikam na MouseMove – zostanie wygenerowany szkic metody w Form1.cs, oraz potrzebny kod w pliku Form1.Designer.cs . Środek metody wypełniamy sami.)
//ta metoda ma pomóc w określeniu współrzędnych punktów, //które będą wierzchołkami wielkąta ograniczającego Gondor private void mapkaPictureBox_MouseMove(object sender, MouseEventArgs e) { xyLabel.Text = String.Format("Współrzędne: x={0}, y={1}", e.X, e.Y); }
Od tej pory w labelce xyLabel będę widział aktualne położenie myszki na obrazku.
Następnie przystępuje do napisania metody, która obsłuży zdarzenie MouseDown dla mapkaPictureBox. Wygląda ona następująco:
private void mapkaPictureBox_MouseDown(object sender, MouseEventArgs e) { //tworzymy obiekt klasy Graphics, który będzie potrzebyny do narysowania ramek Graphics g = mapkaPictureBox.CreateGraphics(); //tworzymy prosokąt ograniczający Mordor Rectangle rMordor = new Rectangle(530, 270, 190, 100); //tworzymy wielkoąt, który będzie reprezentował granice Gondoru Point p1 = new Point(340, 280); Point p2 = new Point(310, 320); Point p3 = new Point(390, 320); Point p4 = new Point(400, 350); Point p5 = new Point(445, 300); Point [] pTab = new Point[] {p1,p2,p3,p4,p5}; GraphicsPath gpGondor = new GraphicsPath(); gpGondor.AddPolygon(pTab); //rysujemy na mapie prostokąt reprezentujący Mordor, //oraz wielkoąt reprezentujący Gondor //Możemy pominąć rysowanie, aby mapka ładniej wyglądała g.DrawRectangle(new Pen(Color.Red, 3), rMordor); g.DrawPath(new Pen(Color.Blue,3),gpGondor); //sprawdzamy czy kursor w czasie klkinięcia był w obrębie Mordoru lub Gondoru if (rMordor.Contains(e.X, e.Y)) krainaLabel.Text = "Wybrałeś Mordor"; else if (gpGondor.IsVisible(e.X, e.Y)) krainaLabel.Text = "Wybrałeś Gondor"; else krainaLabel.Text = "Wybierz Mordor lub Gondor"; }
Uwaga: klasa GraphicPath znajduje się w przestrzeni nazw System.Drawing.Drawing2D, która nie jest domyślnie dołączana w projekach Windows Forms.
Kluczowe są tu linijki 26 i 28. To tutaj sprawdzam metodą Contains (należącą do klasy Rectangle), czy kursor w czasie kliknięcia jest wewnątrz prostokąta rMordor , oraz metodą IsVisible (należącą do klasy GraphicPath) , czy jest wewnątrz wielokątu gpGondor.
Gotowy program wygląda tak:
Voilà!
Zachęcam do podzielenia się opinią na temat prezentowanego programu, a także całego wpisu. Z chęcią wyjaśnię niejasności. Głos uzasadnionej i wyrozumiałej krytyki będzie również mile widziany.
Całkiem pomocny poradnik.
Jednak nurtuje mnie jedna sprawa. Co jeśli zechcemy aby obsluga zdarzenia „MouseMove” odbyła się tak jakby dla naszego pulpitu.
Chodzi mi tutaj o przekazanie do „Labela” informacji na temat tego w jakiej pozycji znajduje się kursor względem pixela(0,0) na pulpicie, nie w danej kontrolce. Jak to ugryść?
Pozycję kursora na ekranie możemy pobrać używając właściwości Cursor.Position
lblX.Text = Cursor.Position.X.ToString(); // pozycja X zapisana do labelki
Zapisanie pozycji jest jednorazowe, ale możemy użyć Timer’a i jego zdarzenie Tick aby uzyskać efekt podobny do sprawdzania współrzędnych w MouseMove.
Jako ciekawostkę można potraktować starszy sposób z użyciem metody GetCursorPos z biblioteki user32.dll.
// dodajemy przestrzeń nazw wymaganą do użycia dll
using System.Runtime.InteropServices;
//w klasie formy deklarujemy metodę
[DllImport(„user32.dll”)]
static extern bool GetCursorPos(ref Point lpPoint);
// … i używamy metody do pobrania punktu kursora
Point punkt = new Point(); // tworzymy obiekt Point
GetCursorPos(ref punkt); // współrzędne zostają zapisane do punktu
lblX.Text = „X = ” + punkt.X.ToString(); // zapisujemy współrzędną X w labelce
lblY.Text = „Y = ” + punkt.Y.ToString(); // analogicznie Y
Dziękuję bardzo, kombinowałem z tym bo myślałem, że to trudniejsze.
Geniusz tkwi jednak w prostocie.
Ponadto dziękuję za dołożenie fragmentu z importowaniem bilbiotek, właśnie pisałem coś co z tego korzysta i sie zastanawiałem jak i po co.
Pozdrawiam
p.s
Liczę na więcej przykładów, tak naprawdę to one zachęcają do twórczego myślenia, oraz uzupełniają wiedzę z różnych dziedzin.
Ciesze się, że mogłem Ci pomóc. Też mam nadzieję, że opublikuję jeszcze sporo ciekawych artykułów. 😛
Mam nawet pomysł. Męczę się już z tym drugi dzień.
Temat po części związany z moim poprzednim pytaniem.
Mianowicie, przeczytałbym jakiś ciekawy opis tego jak poslugiwać się „Hook’ami”.
Bardzo ciekawe zagadnienie i uważam, że przydatne dla wielu aplikacji, które chcą pobierac info na temat interakcji użytkownika z komputerem z innego wątku niż jest w danymm momncie „ontop”.
Jest pare artykułów na msdn, ale co polski tutek to polski.
Da się zrobić ?
Pozdrawiam
Niestety nie da się 🙂 Nie czuję się na tyle pewnie w temacie haków, żeby pisać o tym tutka ( narazie określam się jako początkujący programista ). TUTAJ znajdziesz ciekawy polski artykuł ( może jeszcze na niego nie wpadłeś ) o hakach, autorstwa Maćka Aniserowicza, którego blog nawiasem mówiąc gorąco polecam. Maciek też wspomina, że ciężko coś znaleźć na ten temat w polskim internecie.