Jak narysować krzyżyk na ekranie w danej lokalizacji?

0

Witam,

proste pytanie: **jak narysować krzyżyk na ekranie w miejscu określonym w zmiennej **

pt: TPoint

?

Chodzi mi o uzyskanie dwóch skrzyżowanych ze sobą lini, najlepiej żebym mógł określić ich grubość i kolor.

Póki co mam taki kod:

var
  dc : THandle;
  canvas : TCanvas;
begin
  dc := GetWindowDc(Panel1.Handle);
  canvas := Tcanvas.Create;
  try
    canvas.Handle := dc;
    canvas.Brush.Color := clBlue;
    //canvas.FillRect(Rect(20,2,2,7));
    canvas.Brush.Color := clRed;

    canvas.MoveTo(10,0);
    canvas.LineTo(25, 0);
    canvas.MoveTo(20,10);
    canvas.LineTo(25,0);

   // canvas.FrameRect(Rect(20,2,2,7));
  finally
    releaseDC(GetDeskTopWindow,dc);
    canvas.Free;
  end;

Ogólnie chodzi mi o to, że chcę stworzyć procedurę, do której przekażę uchywyt kontrolki/okna obcej aplikacji (np. przycisku) i chciałbym narysować krzyżyk w miejscu X i Y tego przycisku.
Za cholere nie wychodzi mi krzyżyk i nie mogę ustalić grubości linii ani koloru... nigdy nie rysowałem niczego po canvasie, i szczerze nie bardzo wiem jak to ugryźć.

0

Użyj do tego celu TPaintBox.
Rysuj w zdarzeniu OnPaint

0

Używając PaintBoxa, będę mógł rysować na obszarze ekranu ?
PaintBox to kontrolka, a ja nie chcę rysować w swojej aplikacji tylko na ekranie monitora w wyznaczonym miejscu lub na kontrolce obcego okna

0

Porywasz się z motyką na słońce, z kodu wnioskuje że jak na razie nie dasz rady z tym zagadnieniem.

0

Stąd ten tematu na forum.... jeśli wiesz to napisz w jaki sposób rozwiązać mój problem, jak napisałem (nie rysowałem nigdy wcześniej)

0

dc:=GetDC(0);
ale pamiętaj że to tylko na chwile i windows może w dowolnym momencie to zamalować tak jak było.

Alternatywa - okienko które ma kształt tego krzyżyka ustawione przez Poligon.

0

Ja chyba piszę po chińsku... Dragon, ok poczytałem na MSDN co robi GetDC i GetWindowDC, ale to nie rozwiązuje problemu.
Jak narysować krzyżyk? za pomocą TPainBoxa jakimś cudem? Czy canvas, możesz odwołać się do kodu powyżej?

0

Narysować to nie problem, tylko że jak narysujesz to narysowany przez ciebie krzyżyk sam się nie przerysuje gdy okno tej aplikacji będzie odrysowywane. Kiedy lata temu (jeszcze miałem Windowsa 98) napisałem aplikację, która rysowała kalendarz na pulpicie (i oczywiście odrysowywała go kiedy trzeba było) i do tego używałem jakiegoś hooka w DLL, który w odpowiednim momencie wysyłał komunikat do mojej aplikacji (niewidocznego okna tego kalendarza) informujący że trzeba odrysować. Ogólnie z odrysowywaniem to trochę zabawy... Po co chcesz to robić? Musi się sam odrysowywać?

0

Właśnie, że nie musi, stworzyłem aplikację nagrywającą ruch myszy i klikanie po kontrolkach innych aplikacji, teraz przy odtwarzaniu nagranego schematu chciałbym, aby PRZED kliknięciem w dane miejsce na ekranie (kontrolkę lub okno) pojawił się tam widoczny dla użytkownika KRZYŻYK w którym miejscu nastąpi kliknięcie, ma to być rysowane dosłownie na moment i później zmazane.

2

Masz przykład rysuje on na pierwszym znalezionym przycisku kalkulatora z Windows:

var
  hWnd, hButton: Windows.HWND;
  hDC: Windows.HDC;
  hPen, hOldPen: Windows.HPEN;
  r: TRect;
  p: TPoint;
begin
  hWnd:= Findwindow('CalcFrame', nil);
  if hWnd > 0 then
  begin   //ech w tym kalkulatorze w Win 7 znaleź przycisk to dopiro sztuka ;)
    hWnd:= FindWindowEx(hWnd, 0, 'CalcFrame', nil);
    hWnd:= FindWindowEx(hWnd, 0, '#32770', nil);
    while hWnd > 0 do
    begin
      hButton:= FindWindowEx(hWnd, 0, 'Button', nil);
      if hButton > 0 then break;
      hWnd:= GetNextWindow(hWnd, GW_HWNDNEXT);
    end;

    if  hButton = 0 then exit;

    Windows.GetClientRect(hButton, r); //wymiary
    p.X:= r.Right div 2;  //wyliczamy srodek
    p.Y:= r.Bottom div 2;

    //rysowanie
    hDC:= GetDC(hButton);

    //bedziemy rysowac ciagla linie 3px czerwona dlatego tworzymy sobie takie pioro
    hPen:= CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
    hOldPen:= SelectObject(hDC, hPen);  //i je ustawiamy

    //bardziej tego rysowania nie dalalo sie skomplikowac ale nie chcialo mi sie liczyc ;)
    MoveToEx(hDC, p.X, p.Y, nil); //na srodek
    LineTo(hDC, p.X, p.Y - 10);  //ramie krzyża ma 10px
    MoveToEx(hDC, p.X, p.Y, nil); //na srodek
    LineTo(hDC, p.X, p.Y + 10);
    MoveToEx(hDC, p.X, p.Y, nil); //na srodek
    LineTo(hDC, p.X - 10, p.Y);
    MoveToEx(hDC, p.X, p.Y, nil); //na srodek
    LineTo(hDC, p.X + 10, p.Y);

    //robimy po sobie porzadek
    SelectObject(hDC, hOldPen);
    DeleteObject(hPen);
    ReleaseDC(hButton, hDC);

    Sleep(2000); //czekamy dla demonstracji (po 2 sekundach zostanie wymazany)
    Windows.InvalidateRect(hButton, nil, True); //tak mozesz wymazac
  end;
0

Wielki dzięki za pomoc @kAzek, sprawdzę przykład jak będę w domu. Póki co, wygląda kosmicznie :)

0

@kAzek, wszystko pięknie ładnie, tylko czy istnieje uniwersalna metoda, żeby narysować coś na puplicie w wyznaczonym miejscu, nawet jeżeli okno jest przykryte innym?
tzn. żeby było tak jak jest z tą różnicą, że rysuje na ekranie na podstawie zmiennej TPoint?
Da radę ten kod tak zmodyfikować? Przykład:

procedure TfrmMenu.PaintX(p: TPoint);
var
  hButton: Windows.HWND;
  hDC: Windows.HDC;
  hPen, hOldPen: Windows.HPEN;
  r: TRect;
begin
    //rysowanie
    hDC:= GetDesktopWindow;

    //bedziemy rysowac ciagla linie 3px czerwona dlatego tworzymy sobie takie pioro
    hPen:= CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
    hOldPen:= SelectObject(hDC, hPen);  //i je ustawiamy

    //bardziej tego rysowania nie dalalo sie skomplikowac ale nie chcialo mi sie liczyc ;)
    MoveToEx(hDC, p.X, p.Y, nil); //na srodek
    LineTo(hDC, p.X, p.Y - 10);  //ramie krzyża ma 10px
    MoveToEx(hDC, p.X, p.Y, nil); //na srodek
    LineTo(hDC, p.X, p.Y + 10);
    MoveToEx(hDC, p.X, p.Y, nil); //na srodek
    LineTo(hDC, p.X - 10, p.Y);
    MoveToEx(hDC, p.X, p.Y, nil); //na srodek
    LineTo(hDC, p.X + 10, p.Y);

    //robimy po sobie porzadek
    SelectObject(hDC, hOldPen);
    DeleteObject(hPen);
    ReleaseDC(hButton, hDC);

    Sleep(2000); //czekamy dla demonstracji (po 2 sekundach zostanie wymazany)
    Windows.InvalidateRect(hButton, nil, True); //tak mozesz wymazac
  end;
end;
1
hButton:=  GetDesktopWindow;
//rysowanie
hDC:= GetDC(hButton);
1

@kAzek - dla pulpitu nie będzie to GetDC, a GetWindowDC; No i inaczej trzeba odświeżać pulpit, dlatego że InvalidateRect tego nie robi.


Znalazłem na MSDN sposób na to; Kod przekreślający cały pulpit wielkim białym krzyżykiem poniżej; Po dwóch sekundach odmalowywany jest cały pulpit i wszystkie okna potomne;

procedure DrawDesktopCross();
var
  hDesktop:     Windows.HWND;
  dcDesktop:    Windows.HDC;
  rctDesktop:   Windows.TRect;
  hpOld, hpNew: Windows.HPEN;
begin
  hDesktop  := GetDesktopWindow();
  dcDesktop := GetWindowDC(hDesktop);

  GetClientRect(hDesktop, rctDesktop);

  hpNew := CreatePen(PS_SOLID, 8, RGB(255, 255, 255));
  hpOld := SelectObject(dcDesktop, hpNew);

  MoveToEx(dcDesktop, rctDesktop.Left, rctDesktop.Top, nil);
  LineTo(dcDesktop, rctDesktop.Right, rctDesktop.Bottom);
  MoveToEx(dcDesktop, rctDesktop.Right, rctDesktop.Top, nil);
  LineTo(dcDesktop, rctDesktop.Left, rctDesktop.Bottom);

  SelectObject(dcDesktop, hpOld);
  DeleteObject(hpNew);
  ReleaseDC(hDesktop, dcDesktop);

  Sleep(2000);
  RedrawWindow(hDesktop, nil, 0, RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN);
end;

Przy rysowaniu czegokolwiek ponad oknem tylko jednej aplikacji, na podstawie współrzędnych rysowanego krzyżyka pobrać należy uchwyt do tego okna, po czym wywołać metodę RedrawWindow, tyle że już bez flagi RDW_ALLCHILDREN;

Może istnieje jakiś bardziej elegancki sposób na odświeżenie całej zawartości pulpitu, ale aż tak dobrze nie znam WinAPI.

0

Prawdę mówiąc sam dokładnie nie wiem czym się różni GetDC od GetWindowDC. Po mojemu z tego co rozumiem pierwsze to tylko obszar klienta (client area) a druga całe okno (razem z paskiem tytułu, menu itp.) a więc w przypadku pulpitu to raczej nie ma różnicy której funkcji użyjesz. Gdzie na pulpicie jest non client area? Co do odświeżania fakt nie pomyślałem o tym (tamto pisałem bez sprawdzania) ale i Twoje rozwiązanie nie działa... w sumie to nie wiem o co chodzi z RDW_ALLCHILDREN może bierze pod uwagę tylko okna którym jest rodzicem bezpośrednio, zresztą przecież pulpit nie jest rodzicem wszystkich okien. Z tym odświeżaniem to rzeczywiście prosta sprawa nie jest. Trzeba by nad tym pomyśleć albo coś poszukać.

0

Wielki dzięki, to rozwiązało mój problem i działa jak talala :)
Szacunek!

1
kAzek napisał(a)

Co do odświeżania fakt nie pomyślałem o tym (tamto pisałem bez sprawdzania) ale i Twoje rozwiązanie nie działa...

Jak to nie działa? Sprawdzałem ten kod przed dołączeniem do posta - efekt poniżej :]

after_btn_click.png
po wciśnięciu przycisku

after_scr_repaint.png
po odmalowaniu ekranu

Wszystko gra (przynajmniej u mnie) - zamalowywane są wszystkie okna, po czym za pomocą metody RedrawWindow odmalowywane są wszystkie jego elementy (pasek zadań, wszystkie okna potomne itd.); Flaga RDW_ALLCHILDREN pozwala na przemalowanie wszystkich okien potomnych względem desktopu; Bez niej żadne okna potomne nie zostaną odmalowane, czyli żadne okna aplikacji, pasek zadań itd.; Ona być musi - jest to podane w MSDN; Sprawdzałem bez tej flagi i w sumie żadne okno nie zostało odmalowane - krzyż po prostu zostaje na ekranie;

Nie wiem dlaczego GetDC nie chce działać poprawnie, w każdym razie wczoraj dłuższą chwilę testowałem różne kodu, i tylko za pomocą GetWindowDC udało się pomalować pulpit nad wszystkimi oknami; Podobnie z metodą InvalidateRect - kombinowałem na różne sposoby, ale tylko RedrawWindow pozwolił odświeżyć cały pulpit, oczywiście z flagą RDW_ALLCHILDREN;


Ja testowałem ten kod na WinXP, a Ty @kAzek jak przypuszczam po UA masz Win7 i jak widać taki kod jest niepoprawny; Nie wiem w jaki sposób takie rzeczy maluje system (np. malowanie cyferek przy identyfikacji ekranów), w każdym razie nie jest to takie oczywiste - trzeba by nieco więcej poczytać na temat różnych funkcji API Windowsa, żeby wybrać rozwiązanie uniwersalne dla różnych wersji systemu.

0

Mam Win8 :) po najechaniu na przycisk, lub ruszeniu okna, wszystko jest odmalowywane :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1