Transparent panel i zrzut części ekranu

0

Mam na formie paintbox na którym użytkownik rysuje linie. Potrzebuję jakiejś przezroczystej kontrolki (może to być panel lub Timage lub inna) na którą nakładam siatkę linii, a cały komponent leży na paintbox'ie. I jeszcze jedno: jak w delphi otrzymać zrzut ekranu, a potem wydrukować go na drukarce?

1
Romlus napisał(a):

Mam na formie paintbox na którym użytkownik rysuje linie. Potrzebuję jakiejś przezroczystej kontrolki (może to być panel lub Timage lub inna) na którą nakładam siatkę linii, a cały komponent leży na paintbox'ie.

Nie. Absolutnie nie.

Funkcja malowania linii oraz tła powinna być zrealizowana w tym samym komponencie. Utwórz w pamięci bitmapę pomocniczą (back buffer), na tej bitmapie maluj to co chce użytkownik. W zdarzeniu PaintBox.OnPaint najpierw namaluj zawartość pomocniczej bitmapy, a następnie na wierzchu siatkę linii.

Nie dość, że ograniczysz się do jednego komponentu, to samo malowanie i renderowanie kontrolki będzie dużo szybsze.

I jeszcze jedno: jak w delphi otrzymać zrzut ekranu, a potem wydrukować go na drukarce?

Jak zrobić zrzut z ekranu

0

Możesz napisać więcej na ten temat? Chodzi mi o to że użytkownik rysuje ściany, czyli linie na paintbox'ie, a potem nakłada na ten obraz siatkę którą ma mieć możliwość przesuwać aż ustali odpowiednie położenie i wydrukuje całość.

0

Tu nie ma co wyjaśniać – sposób jest zbyt prosty. :]

Potrzebujesz pomocniczej bitmapy, o takim samym rozmiarze co PaintBox. Wszystko co może malować użytkownik (czyli linie) malujesz na tej pomocniczej bitmapie, nie w OnPaint komponentu. Dzięki temu zawsze będziesz miał dostęp do surowego rysunku. W zdarzeniu PaintBox.OnPaint malujesz na płótnie kontrolki zawartość tej pomocniczej bitmapy, a następnie – również na płótnie komponentu – malujesz tę dodatkową siatkę.

Dzięki temu użytkownik na ekranie będzie widział swój rysunek wraz z siatką, a Ty będziesz posiadał w pamięci sam surowy rysunek. To pozwoli dowolnie przesuwać siatkę, bo jest malowana dynamicznie (czyli jest tworem wirtualnym).

Najlepiej by było napisać do tego celu własną, prostą kontrolkę i umieścić pomocniczą bitmapę wewnątrz niej (w sekcji private). Tworzyć ją w konstruktorze komponentu, zwalniać w destruktorze, zmieniać rozmiar np. w SetBounds i dać do niej dostęp za pomocą dodatkowej właściwości. Również całą funkcjonalność dotyczącą malowania (czyli ustawień stylu linii, klikania itd.) też należy umieścić w kodzie kontrolki. Dopisać sobie metody przetwarzające odpowiednie komunikaty (np. WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE) i zaimplementować w nich rysowanie.

0

W jaki sposób rysować w czasie rzeczywistym po bitmapie.

Tworzę bitmapę:

bitmapa:=TBitmap.Create;
bitmapa.Width:=paintbox1.Width;
bitmapa.Height:=paintbox1.Height;

Potem rysuję na płótnie:

bitmapa.canvas.Pen.Color:=clblack;
bitmapa.canvas.MoveTo(x1,y1);
bitmapa.canvas.LineTo(x3,y3);

Lecz efektu nie widać.

0
var
  BackBuffer: TBitmap;
begin
  BackBuffer := TBitmap.Create();
  BackBuffer.PixelFormat := pf24bit;
  BackBuffer.Width := PaintBox1.Width;
  BackBuffer.Height := PaintBox1.Height;

A zdarzenie OnPaint? Nie dziw się że nie widać nic na ekranie.

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  Self.Canvas.Draw(0, 0, BackBuffer);
end;

Zapomniałeś też o wypełnieniu tła pomocniczej bitmapy. Domyślnie – jeśli pamięć mnie nie myli – będzie czarne.

BackBuffer.Canvas.Brush.Color := clWhite;
BackBuffer.Canvas.FillRect(BackBuffer.Canvas.ClipRect);
0

Jak rozumiem, użytkownik w czasie działania programu rysuje na bitmapie w zdarzeniu paintbox.onmousemove?

0

Nie wiem czy w swoim programie masz już zaimplementowaną obsługę myszy i ogólnie całego mechanizmu malowania, ale jeśli tak, to jedyne co musisz zrobić to wymienić wszystkie linijki malujące po PaintBox.Canvas na te malujące po BackBuffer.Canvas.

To spowoduje, że wszystko co namaluje użytkownik, znajdzie się na pomocniczej bitmapie (a nie na ekranie), więc po namalowaniu czegokolwiek na bitmapie, wywołaj PaintBox.Invalidate – ta metoda wywoła m.in. zdarzenie OnPaint, dzięki czemu kontrolka na ekranie zostanie odmalowana.


To pozwoli również na podgląd rozciągania linii podczas malowania. Przykładowo, w OnMouseDown zapamiętujesz współrzędne kliknięcia i ustawiasz flagę włączającą tryb malowania linii (zwykła zmienna logiczna), w OnMouseMove, jeśli ta flaga jest ustawiona, zapamiętujesz bieżące współrzędne kursora i wołasz Invalidate, a w OnPaint (jeśli flaga jest ustawiona) malujesz zawartość bitmapy na ekranie, następnie na podstawie zapamiętanych współrzędnych malujesz dynamicznie linię, a na koniec również dynamicznie malujesz siatkę na samej górze.

Zaraz coś naskrobię – tak będzie najłatwiej. ;)

2

@Romlus: znalazłem chwilkę i wystrugałem małego PoC-a.

Nie wiem dokładnie jak to u Ciebie wygląda z tą siatką i liniami, więc dla testu napisałem apkę, w której użytkownik może malować prostokąty. Edytor posiada tylny bufor, na którym lądują dane naniesione przez użytkownika. W edytorze (na buforze nie) malowana jest też siatka na wierzchu. Podczas malowania prostokąta, widoczny jest w edytorze jego podgląd, a po puszczeniu klawisza myszy, ląduje w buforze.

Lewym przyciskiem myszy maluje się prostokąty (w taki sam sposób jak w zwykłym edytorze graficznym), a prawy przycisk służy do przesuwania siatki linii. Po lewej w oknie jest pole edytora, po prawej podgląd tego co znajduje się aktualnie w buforze.

Tutaj zrzut z działania: PaintBox PoC.webm

W razie gdybyś mial Lazarusa to również dołączam źródła w załączniku. Have fun. ;)

0

Dzięki za pomoc. Mój program działa właściwie.

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