Naprzemienne wczytywanie obrazka

0

Witam wszystkich ponownie

Zdecydowałem się napisać ponownie ponieważ nie daję sobie rady z napisaniem kodu który ma za zadanie podczas zdarzenia On MouseMove na komponencie TMemo wczytywanie obrazka a na zdarzenie on MouseLeave wczytywanie ponownie obrazka który jest domyślie załadowany. Problem polega na tym że obrazki różnią się tylko kolorem jednej rzeczy i chciałbym żeby zamienne wczytywanie odbywało się płynnie bez "mrugania" i aby nie było śladu że w tle zamianiają się te obrazki.
Proszę o pomoc.
Próbuję to zrobić w ten oto sposób :

procedure TForm7.Memo1MouseLeave(Sender: TObject);

begin
    Obrazek.FreeImage;
    Obrazek.LoadFromFile ('człowiek - wymiary kpl_v3.bmp');
    Image3.Picture.Bitmap := Obrazek;
    Refresh;

end;

procedure TForm7.Memo1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin

  Obrazek.FreeImage;
  Obrazek.LoadFromFile ('człowiek - wymiary_2_v3.bmp');
  Image3.Picture.Bitmap := Obrazek;
  Refresh;

end;
0
Obrazek.FreeImage;
Obrazek.LoadFromFile ('człowiek - wymiary kpl_v3.bmp');

To niepotrzebne – LoadFromFile najpierw zwalnia pamięć zajmowaną przez bieżący obraz, a następnie ładuje nowy z zadanego pliku.

Image3.Picture.Bitmap := Obrazek;
Refresh;

To też niepotrzebne – po przypisaniu referencji do właściwości Bitmap, komponent automatycznie przemalowuje się. Całe te cztery linijki można by wymienić na jedną, a program i tak będzie działał tak samo:

Image3.Picture.Bitmap.LoadFromFile('człowiek - wymiary kpl_v3.bmp');

Tak samo, czyli źle, bo nieoptymalnie.


Ten sposób i tak jest do bani, ale wypadało napisać o tym, że przekombinowujesz.

Podstawowym problemem jest to, że ciągle ładujesz obrazki z plików, zamiast je raz załadować do pamięci i tylko przepisywać referencje do komponentu w odpowiednich zdarzeniach. Przydadzą się dwa pola:

private
  FPictureNormal: TBitmap;
  FPictureHover: TBitmap;

Drugi podstawowy błąd to użycie zdarzenia OnMouseMove. Ono wywoływane jest za każdym razem, jeśli pozycja kursora zmieni się choćby o piksel. Zakładając, że Twoje Memo ma 300px szerokości i przesuniesz kursor od lewej krawędzi do prawej, obrazek zostanie 300x załadowany z pamięci i wpisany do Image3, a ten z kolei zostanie 300x przemalowany. Dziwisz się, że miga? Bo ja nie.

Przydatne dwie metody – jedna tworzy instancje i ładuje obrazy z plików do pamieci, a druga zwalnia obiekty:

procedure TMyForm.LoadPictures();
begin
  FPictureNormal := TBitmap.Create();
  FPictureNormal.LoadFromFile('człowiek - wymiary kpl_v3.bmp');

  FPictureHover := TBitmap.Create();
  FPictureHover.LoadFromFile('człowiek - wymiary_2_v3.bmp');
end;

procedure TMyForm.UnloadPictures();
begin
  FPictureNormal.Free();
  FPictureHover.Free();
end;

Następnie do wykrycia najechania kursora na Memo użyj zdarzenia OnMouseEnter, w którym użyj obrazu Hover:

Image3.Picture.Bitmap := FPictureHover;

A do wykrycia zabrania kursora znad kontrolki, użyj zdarzenia OnMouseLeave, w którym użyj obrazu Normal:

Image3.Picture.Bitmap := FPictureNormal;

Amen. ;)

0

Witam ponownie

Dziękuję bardzo @furious programming za odpowiedz
Zastosowałem się do wskazówek ale nadal mi to mruga gdy najeżdzam na Memo i go opuszczam
Dodaję że mam takich obrazków 19 różniących się szczegółami kolorystycznymi. Niestety dalej mi to miga. Proszę o pomoc co jeszcze można by było zrobić?
Uporczywie to jest wkurzające gdy szybko przesuwam myszką po innych polach memo przypisanych do obrazków.
Tak pomyślałem a może za dużo objętości zajmują te mapy bitowe bo jedna mapa ma objętość około 1,5MB?

pozdrawiam
Arek

0
solark napisał(a):

Dodaję że mam takich obrazków 19 różniących się szczegółami kolorystycznymi.

Szczegóły kolorystycznie nie mają żadnego znaczenia, jeśli chodzi o proces renderowania kontrolki.

Niestety dalej mi to miga.

To, czyli co? Jak mamy Ci pomóc, skoro nie mamy dostępu do kodu?

Proszę o pomoc co jeszcze można by było zrobić?

Wymień wszystkie Image na PaintBox, ew. dodatkowo skorzystaj z tylnego buforowania.

Owe miganie pojawia się wtedy, gdy komponent najpierw wypełnia swoje tło jednolitym prostokątem, a dopiero po tym maluje coś na wierzchu. Jeśli namalujesz sobie wszystko na pomocniczej bitmapie i na koniec namalujesz całą bitmapę na płótnie komponentu, to nic nie mignie.

Uporczywie to jest wkurzające gdy szybko przesuwam myszką po innych polach memo przypisanych do obrazków.

Jak są one ułożone na formularzu? Zrób zrzut ekranu (a raczej samego formularza) i pokaż go tutaj.

Tak pomyślałem a może za dużo objętości zajmują te mapy bitowe bo jedna mapa ma objętość około 1,5MB?

Ile?! Strasznie duże te obrazy… Jaki jest ich rozmiar w pikselach i czemu tak dużo? :P

0

Grafika jak na załączonym obrazku
Chodzi o to że chcę zmieniać kolor wymiaru na czerwony po najechaniu na Memo w związku z tym mam 19 obrazków a na każdym inny wymiar w kolorze czerwonym
Plik zajmuje tyle bo jest to obraz BMP zapisany z obrazka wektorowego. Rozmiar w pikselach to 594 na 697 pikseli. Ile w takim razie powinien zajmować taki plik aby się to odbywało płynnie?
A jak w ogóle wczytać obrazek do tego PaintBoxa i jak zrobić to tylne buforowanie?

A oto kod który udało mi się stworzyć:

 private
    { Private declarations }
      FMaleST0 : TBitmap;
      FMaleST1 : TBitmap;
      FMaleST2 : TBitmap;
      FMaleST3 : TBitmap;
      FMaleST4 : TBitmap;
      FMaleST5 : TBitmap;
      FMaleST6 : TBitmap;
      FMaleST7 : TBitmap;
      FMaleST8 : TBitmap;
      FMaleST9 : TBitmap;
      FMaleST10 : TBitmap;
      FMaleST11 : TBitmap;
      FMaleST12 : TBitmap;
      FMaleST13 : TBitmap;
      FMaleST14 : TBitmap;
      FMaleST15 : TBitmap;
      FMaleST16 : TBitmap;
      FMaleST17 : TBitmap;
      FMaleST18 : TBitmap;
      FMaleST19 : TBitmap;

  public
    { Public declarations }

  end;

var
  Form7: TForm7;

implementation

{$R *.dfm}

uses Unit8;

 procedure TForm7.LoadPictures();
begin
  FMaleST0 := TBitmap.Create();
  FMaleST0.LoadFromFile('człowiek - wymiary kpl.bmp');

  FMaleST1 := TBitmap.Create();
  FMaleST1.LoadFromFile('człowiek - wymiary_1.bmp');

  FMaleST2 := TBitmap.Create();
  FMaleST2.LoadFromFile('człowiek - wymiary_2.bmp');

  FMaleST3 := TBitmap.Create();
  FMaleST3.LoadFromFile('człowiek - wymiary_3.bmp');

  FMaleST4 := TBitmap.Create();
  FMaleST4.LoadFromFile('człowiek - wymiary_4.bmp');

  FMaleST5 := TBitmap.Create();
  FMaleST5.LoadFromFile('człowiek - wymiary_5.bmp');

  FMaleST6 := TBitmap.Create();
  FMaleST6.LoadFromFile('człowiek - wymiary_6.bmp');

  FMaleST7 := TBitmap.Create();
  FMaleST7.LoadFromFile('człowiek - wymiary_7.bmp');

  FMaleST8 := TBitmap.Create();
  FMaleST8.LoadFromFile('człowiek - wymiary_8.bmp');

  FMaleST9 := TBitmap.Create();
  FMaleST9.LoadFromFile('człowiek - wymiary_9.bmp');

  FMaleST10 := TBitmap.Create();
  FMaleST10.LoadFromFile('człowiek - wymiary_10.bmp');

  FMaleST11 := TBitmap.Create();
  FMaleST11.LoadFromFile('człowiek - wymiary_11.bmp');

  FMaleST12 := TBitmap.Create();
  FMaleST12.LoadFromFile('człowiek - wymiary_12.bmp');

  FMaleST13 := TBitmap.Create();
  FMaleST13.LoadFromFile('człowiek - wymiary_13.bmp');

  FMaleST14 := TBitmap.Create();
  FMaleST14.LoadFromFile('człowiek - wymiary_14.bmp');

  FMaleST15 := TBitmap.Create();
  FMaleST15.LoadFromFile('człowiek - wymiary_15.bmp');

  FMaleST16 := TBitmap.Create();
  FMaleST16.LoadFromFile('człowiek - wymiary_16.bmp');

  FMaleST17 := TBitmap.Create();
  FMaleST17.LoadFromFile('człowiek - wymiary_17.bmp');

  FMaleST18 := TBitmap.Create();
  FMaleST18.LoadFromFile('człowiek - wymiary_18.bmp');

  FMaleST19 := TBitmap.Create();
  FMaleST19.LoadFromFile('człowiek - wymiary_19.bmp');

end;

procedure TForm7.UnloadPictures();
begin
  FMaleST0.Free();
  FMaleST1.Free();
  FMaleST2.Free();
  FMaleST3.Free();
  FMaleST4.Free();
  FMaleST5.Free();
  FMaleST6.Free();
  FMaleST7.Free();
  FMaleST8.Free();
  FMaleST9.Free();
  FMaleST10.Free();
  FMaleST11.Free();
  FMaleST12.Free();
  FMaleST13.Free();
  FMaleST14.Free();
  FMaleST15.Free();
  FMaleST16.Free();
  FMaleST17.Free();
  FMaleST18.Free();
  FMaleST19.Free();
end;

procedure TForm7.FormClose(Sender: TObject; var Action: TCloseAction);
begin

    UnloadPictures();

end;

procedure TForm7.FormCreate(Sender: TObject);
begin

  PageControl1.ActivePageIndex := 0;
  PageControl2.ActivePageIndex := 0;
  LoadPictures();

end;

procedure TForm7.Memo1MouseEnter(Sender: TObject);
begin
    Image3.Picture.Bitmap := FMaleST1;
end;

procedure TForm7.Memo1MouseLeave(Sender: TObject);
begin
    Image3.Picture.Bitmap := FMaleST0;
end;

procedure TForm7.Memo2MouseEnter(Sender: TObject);
begin
     Image3.Picture.Bitmap := FMaleST2;
end;

procedure TForm7.Memo2MouseLeave(Sender: TObject);
begin
     Image3.Picture.Bitmap := FMaleST0;
end;

procedure TForm7.Memo3MouseEnter(Sender: TObject);
begin
   Image3.Picture.Bitmap := FMaleST3;
end;

procedure TForm7.Memo3MouseLeave(Sender: TObject);
begin
   Image3.Picture.Bitmap := FMaleST0;
end;

end.
0
solark napisał(a):

Grafika jak na załączonym obrazku

Powinieneś ten obrazek malować w całości na PaintBox lub w oknie, dostosowanym do jego wymiarów.

Chodzi o to że chcę zmieniać kolor wymiaru na czerwony po najechaniu na Memo w związku z tym mam 19 obrazków a na każdym inny wymiar w kolorze czerwonym

Mhm. Zakładam, że te 19 obrazków różni się między sobą tylko tym, że ten podstawowy jest cały czarno-biały, a pozostałe posiadają kolorowe strzałki? Czyli wszystkie są tego samego rozmiaru, a jedynie niektóre ich fragmenty różnią się kolorami?

Jeśli dobrze rozumiem, to robisz bardzo duży błąd. Zwróć wagę na to, że odmalowanie tak wielkiego obrazu na ekranie trwa dość długo, a po drugie, taki obraz również bardzo dużo zajmuje. Dlatego też powinieneś mieć tylko jeden duży obrazek – dla tła – a pozostałe powinny zawierać wyłącznie obszar różniący się od oryginału. Czyli każdy z nich powinien zawierać tylko kolorowe strzałki, z tym co jest pod spodem.

Najprostsze rozwiązanie to malować tło na płótnie formularza. Następnie na nim położyć 18 różnych Image, załadować do nich obrazki (nie podczas działania programu – w oknie inspektora obiektów) i ułożyć je tak, aby pasowały do strzałek na tle. Wszystkim tym obrazkom ustawić Visible na False, tak aby po uruchomieniu wszystkie były niewidoczne. Na koniec wygenerować zdarzenia OnMouseEnter i OnMouseLeave dla pierwszego Memo, w nich odpowiednio pokazywać i ukrywać dany Image. Na koniec podłączyć te dwa zdarzenia pod wszystkie inne Image, tak aby nie dublować kodu.

Plik zajmuje tyle bo jest to obraz BMP zapisany z obrazka wektorowego. Rozmiar w pikselach to 594 na 697 pikseli. Ile w takim razie powinien zajmować taki plik aby się to odbywało płynnie?

Wyeksportuj grafikę źródłową (wektorową) do PNG to się przekonasz. ;)

A jak w ogóle wczytać obrazek do tego PaintBoxa i jak zrobić to tylne buforowanie?

Teraz już mniej więcej wiem co potrzebujesz zrobić, więc to co wcześniej napisałem nie jest aktualne. Ogólnie w tylnym buforowaniu chodzi o to, aby wszystkie operacje związane z malowaniem po ekranie (czyli np. bezpośrednio na płótnie formularza lub komponentu) wykonać na pomocniczej bitmapie, a dopiero po tym wszystkim namalować całą bitmapę na płótnie kontrolki. Dzięki temu obraz na ekranie zostanie odmalowany tylko raz, co skutecznie wykluczy miganie (tzw. flickering). Drugą istotną różnicą jest to, że tylne buforowanie daje solidnego kopa, dzięki czemu czas trwania procesu renderowania znacznie się skraca.

To tak w skrócie, i choć sposób ten jest bardzo prosty w implementacji, to można by pisać o nim bez końca. Przyklad back bufferingu znajdziesz w moim niedawnym poście, zajrzyj do kodu z załącznika i poczytaj – Transparent panel i zrzut części ekranu .


 private
    { Private declarations }
      FMaleST0 : TBitmap;
      FMaleST1 : TBitmap;
      FMaleST2 : TBitmap;
      FMaleST3 : TBitmap;
      FMaleST4 : TBitmap;
      FMaleST5 : TBitmap;
      FMaleST6 : TBitmap;
      FMaleST7 : TBitmap;
      FMaleST8 : TBitmap;
      FMaleST9 : TBitmap;
      FMaleST10 : TBitmap;
      FMaleST11 : TBitmap;
      FMaleST12 : TBitmap;
      FMaleST13 : TBitmap;
      FMaleST14 : TBitmap;
      FMaleST15 : TBitmap;
      FMaleST16 : TBitmap;
      FMaleST17 : TBitmap;
      FMaleST18 : TBitmap;
      FMaleST19 : TBitmap;

Słyszałeś kiedyś o tablicach, albo o listach generycznych? :P

procedure TForm7.Memo1MouseEnter(Sender: TObject);
begin
    Image3.Picture.Bitmap := FMaleST1;
end;

{..}

Nie używasz parametru Sender, a on pozwoli drastycznie skrócić kod.

0

Witam ponownie

Dzięki @furious programming za zaangażowanie.
Spróbowałem sposobu o którym mówisz tzn wyeksportowałem do png tych 19 obrazków z osobno każdą strzałką w kolorze czerwonym o rozmiarze takim jak postać,następnie ustawiłem właściwości Transparent na True a Visable na Folse ale to dalej miga - Tracę już powoli nadzieję że to się uda. Może to tylne buforowanie coś pomoże. Niestety nie wiem jak to ugryźć w moim przypadku i jak to oprogramować dla Image.
Wiem że może już się robię nudny ale proszę o pomoc

0
solark napisał(a):

Spróbowałem sposobu o którym mówisz tzn wyeksportowałem do png tych 19 obrazków z osobno każdą strzałką w kolorze czerwonym o rozmiarze takim jak postać […]

Nie, miałeś wyeksportować fragmenty obrazu źródłowego (same strzałki), do o wiele mniejszych obrazków. :P

[…] następnie ustawiłem właściwości Transparent na True […]

I tu jest problem – użycie 32-bitowych grafik w interfejsie potwornie spowalnia proces renderowania okna… Dlatego w celu zwiększenia wydajności używa się pomocniczych bitmap.

Nie pisałem Ci żebyś użył grafik przezroczystych – wszystkie powinny być 24-bitowe, a te malutkie grafiki powinny zawierać fragmenty o wymiarach strzałek, razem z tłem i czarnymi liniami. Dzięki temu wszystkie obrazy będą mogły być nieprzezroczyste, a renderowanie okna będzie bardzo szybkie.

I pamiętaj – to że najprostszym rozwiązaniem jest narobienie kupki komponentów i ich pokazywanie/ukrywanie, wcale nie oznacza, że jest to rozwiązanie dobre. Bo nie jest. Dobrym sposobem będzie malowanie tła bezpośrednio na płótnie komponentu/formularza, stosując back buffering do łącznia obrazu w całość (tło z konkretną strzałką).

Może to tylne buforowanie coś pomoże.

Na pewno pomoże.

Niestety nie wiem jak to ugryźć w moim przypadku i jak to oprogramować dla Image.

Nie nie nie – nie dla Image, bo ten komponent jest cholernie powolny. Tylny bufor ma posłużyć jako niewidoczne, pomocnicze płótno do złożenia obrazu do kupy, a następnie tak przygotowaną grafikę namalować w odpowiednim komponencie lub bezpośrednio na płótnie formularza.


Możesz dołączyć do załączników posta archiwum ze wszystkimi grafikami?

Mógłbym coś naskrobać w wolnym czasie. Najlepiej by było, gdybyś przygotował zestaw obrazków o tych samych rozmiarach (o rozmiarze głównego dla tła), gdzie jeden byłby czarno-białym tłem, a reszta posiadała dodatkowo pokolorowane strzałki, po jednej dla każdej grafiki.

0

Witam ponownie

Jeszcze raz dziękuję @furious programming za zaangażowanie i pomoc
Zgodnie z rozmową wysyłam rysunki do stworzenia przykładowej formatki
Gdyby się udało stworzyć odpowiedni kod to bardzo proszę o zamieszczenie go

pozdrawiam
Arek

0

Jeśli tymi dodatkowymi obrazkami są strzałki i odnośniki to nie lepiej mazać je bezpośrednio na canvasie tylko bawić się w ładowanie obrazków??

Można też stworzyć Shape'y ze strzałkami (trójkąt, linia, trójkąt) nad tym podkładem i tylko je ukrywać albo pokazywać :)
Trójkąt w shape-ie

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