Szybkie przesuwanie obiektów klasy `TImage` po formularzu

0

Przedstawiam kod:

 
unit code;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Timer1: TTimer;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;
  Tab: array [1..10] of TImage;
  Img: TImage;
  Obiekt: Integer = 1;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
var
I: Integer;
begin
Button2.Enabled := True;
Button1.Enabled := False;
I := 0;

for I := 1 to 10 do
begin
Img := TImage.Create(Self);
Img.Parent := Form2;
Img.Picture.LoadFromFile('ikona.bmp');
Img.Top := I*Img.Height;
Img.Height := 50;
Img.Width := 50;
Img.Stretch := true;
Img.Transparent := True;

Tab[I] := Img;
end;

Form2.WindowState := wsMaximized;
end;

procedure TForm2.Button2Click(Sender: TObject);
begin
Timer1.Enabled := True;
Button2.Enabled := False;

Form2.DoubleBuffered := True;

Form2.Caption := 'Przesuwaj Lewo/Prawo';
end;

procedure TForm2.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
Inc(Obiekt);
if Obiekt > 10 then Obiekt := 1;

//if TImage(Tab[Obiekt]) <> nil then

if GetKeyState(VK_Right) < 0 then
TImage(Tab[Obiekt]).Left := TImage(Tab[Obiekt]).Left + 10;

if GetKeyState(VK_Left) < 0 then
TImage(Tab[Obiekt]).Left := TImage(Tab[Obiekt]).Left - 10;

Timer1.Enabled := true;
end;

end.

próbowałem zrobić błyskawiczne przesuwanie elementów z tablicy po formie... poniosłem totalną klęskę działa to fatalnie wolno a potrzebuję błyskawicznie... macie jakieś pomysły jak szybko przesunąć 100 TImage? 10 też przesuwa się makabrycznie wolno przy intervale timera 1ms

dzięki za sugestie

0

Niepotrzebnie używasz tutaj zmiennej o nazwie 'obiekt' - to przez nią kod się tak 'kiepsko' wykonuje.
Spróbuj poniższy kod w Timerze z niskim intervalem (np. 10 ms):

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: Integer;
begin
  if GetKeyState(VK_RIGHT) < 0 then
    for i := 1 to 10 do
      TImage(Tab[i]).Left := TImage(Tab[i]).Left + 10
  else if GetKeyState(VK_LEFT) < 0 then
    for i := 1 to 10 do
      TImage(Tab[i]).Left := TImage(Tab[i]).Left - 10;
end;

Jednak rezultat robienia takich rzeczy na Timerze jest mało wydajny. Mógłbyś spróbować użyć zdarzenia OnKeyDown formy, lub (to trochę bardziej skomplikowane) założyć hooka na klawiaturę.

2
toffik napisał(a)

poniosłem totalną klęskę działa to fatalnie wolno a potrzebuję błyskawicznie...

Poul napisał(a)

Niepotrzebnie używasz tutaj zmiennej o nazwie 'obiekt' - to przez nią kod się tak 'kiepsko' wykonuje.

Wiecie dlaczego tak wolno to działa? Bo operacje wykonywane na interfejsie programu są potwornie powolne; Nawet podwójne buforowanie czy pozbycie się zmiennych pomocniczych nic tutaj nie pomoże, bo tego jest po prostu zbyt wiele (na Twój sprzęt pytaczu);

Podstawowe pytanie - koniecznie musisz używać komponentów klasy TImage? Jeżeli nie musisz, to użyj jednego komponentu (np. TPaintBox), każdą klatkę animacji buduj w pamięci (na pomocniczej, 24-bitowej bitmapie) i maluj raz na tym komponencie;

Istnieje wiele ważnych rzeczy, które trzeba wiedzieć i znać, aby animacja była płynna; Podaj więc więcej szczegółów, a postaram się coś doradzić.

0

Robię wirtualny pulpit, muszę rysować ikony, mają być przesuwane w lewo/prawo/górę i dół, pulpit jest nieograniczonych rozmiarów, właściwie jest ograniczony tylko ilością pamięci ram. Wcześniej rysowałem canvasem na TBitmap i ładnie działało ale teraz coś się popierdzieliło i strasznie przycina. Zmienna Obiekt to identyfikator przesuwanego obiektu, jest konieczna do odwołania się w tablicy, może nazywać się np I. Mam dobrego kompa, ale rezultaty są makabryczne. Nie wiem czy canvas coś przyspieszy, w OpenGL jestem zielony wiem że było by szybko i pięknie... hmm może być to tablica TBitmap ale nie wiem czy to coś zmieni, spróbuję

0

Robię wirtualny pulpit, muszę rysować ikony, mają być przesuwane w lewo/prawo/górę i dół, pulpit jest nieograniczonych rozmiarów, właściwie jest ograniczony tylko ilością pamięci ram.

Dlatego będzie z tym problem;

Pulpit na Windows to coś jak komponent TListView z ViewStyle ustawionym na vsIcon; No właśnie - to jest komponent, a nie zbiór komponentów; Poza tym jego kod zapewne jest mocno zoptymalizowany, dlatego wszystko działa płynnie;

Wcześniej rysowałem canvasem na TBitmap i ładnie działało [...]

To znaczy jak? Kanwą rysowałeś po bitmapie? Czy rysowałeś na kanwie bitmapy?

Zmienna Obiekt to identyfikator przesuwanego obiektu, jest konieczna do odwołania się w tablicy, może nazywać się np I.

Pomijając fakt, iż używasz samych zmiennych globalnych co jest w tym przypadku złe, to co jak co, ale identyfikatory powinny mieć konkretne wartości, mówiące o swoim przeznaczeniu; Przenieś je albo do wnętrza klasy formularza do sekcji Private, albo zrób z nich zmienne lokalne w odpowiednich metodach; A te, które przeniesz do klasy formularza - inicjuj w konstruktorze okna;

Mam dobrego kompa, ale rezultaty są makabryczne.

Nawet jeśli Twój komputer jest mocny i u Ciebie będzie działać płynnie, to musisz napisać kod tak, aby na wolniejszym sprzęcie też tak wszystko działało; Chyba że to program tylko dla Ciebie;

Nie wiem czy canvas coś przyspieszy, w OpenGL jestem zielony wiem że było by szybko i pięknie...

Kanwa sama nie przyspieszy - sam musisz zadbać o efektywność; OpenGL raczej nie nadaje się do tego co chcesz zrobić - to API zostaw w spokoju, bo jeszcze zbyt wcześnie na to;
____Osobiście poleciłbym napisanie komponentu, który umożliwiłby wyświetlanie ikon i obsługę myszy/klawiatury; Jednak widząc Twój kod mogę stwierdzić, że jesteś początkujący i nie poradzisz sobie z tym; Dla prostego efektu nie było by zbyt wiele roboty, jednak trzeba by zaznajomić się co najmniej z podstawami programowania obiektowego, aby móc spokojnie napisać taki komponent.

0

Możemy nawiązać współpracę jeśli chcesz, ja daję pomysł.... Wirtualnie jeżdżące ikony na pulpicie, Ty pomagasz jeśli chcesz. Komponentu nie piszę dlatego że zainstalowałem sobie Delphi Code Gear 2007 i nie ma możliwości instalacji nowych komponentów. Pomysł jest niezły, Pulpit Microsoftu zapycha się po tygodniu. Ten jest nieograniczony, przesiądę się na Canvas. Rysowałem na kanwie formy, niestety przy TBitmap znowu trzeba ręcznie dorabiać zdarzenia OnClick, on DblClick, zabawy jest sporo. Początkujący nie jestem siedzę w Delphi od 18 roku życia a mam 31 lat. Jeśli chcesz napisz na maila [email protected], chętnie podzielę się z Tobą moimi próbami. Kod był klepany na szybko

0

Wiecie dlaczego tak wolno to działa? Bo operacje wykonywane na interfejsie programu są potwornie powolne

Dokładnie. Na TImage miałem tysiące operacji do wykonania. Stworzyłem wtedy zmienną typu TBitmap, wykonywałem na niej operacje, a na koniec przypisywałem zawartość do TImage, co znacznie przyspieszyło iterację. Tak samo miałem na przykład z sortowaniem w ListBox.

0

co ciekawe taki kod:

 
unit code;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Timer1: TTimer;
    procedure Button1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;
  Bitmap: TBitmap;
  Foldery: array [1..2000] of TBitmap;
  X: Integer = 0;
  Y: Integer = 0;
  Number: Integer = 2000;




implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
var
I: Integer;
begin
Button1.Enabled := False;

Form2.WindowState := wsMaximized;
try
for I := 1 to Number do
begin
Application.ProcessMessages;
Bitmap := TBitmap.Create;
Bitmap.LoadFromFile(ExtractFilePath(ParamStr(0)) +    'ikona.bmp');
Bitmap.Width := 50;
Bitmap.Height := 50;
Form2.Caption := 'Tworzę folder numer ' + IntToStr(I);

Foldery[I] := Bitmap;



canvas.Draw(10,I*70,Bitmap);

end;

finally
Timer1.Enabled := True;

end;
Timer1.Enabled := True;


end;

procedure TForm2.FormCreate(Sender: TObject);
begin
DoubleBuffered := True;
Form2.Color := clGradientActiveCaption;
end;

procedure TForm2.Timer1Timer(Sender: TObject);
var
I: Integer;
begin


I := 1;

if GetKeyState(VK_Right) < 0 then
begin
X := X + 40;
Repaint;
end;

if GetKeyState(VK_Left) < 0 then
begin
X := X - 40;
Repaint;
end;

if GetKeyState(VK_Up) < 0 then
begin
Y := Y - 40;
Repaint;
end;

if GetKeyState(VK_Down) < 0 then
begin
Y := Y + 40;
Repaint;
end;




for I := 1 to Number do
begin
canvas.Draw(10+X,I*70 + Y,Bitmap);
end;


end;

end.

powoduje błyskawiczne przesuwanie 2000 ikon ;d

ale efekt mnie jeszcze nie zadowala przy 10 tysiącach ikon pojawia się błąd "Nieprawidłowe dojście OutOfResources" ;)

1

http://digital.ni.com/public.nsf/allkb/0AD85403D4772CC386257C550047E773

The error -12 Out of Memory error occurs because Windows 7 exceeded the maximum number of GDI Handles. This can happen when your UI has too many GDI Objects (Bitmaps, Brushes, Fonts, etc.) opened which are identified in OS by GDI Handles. There is per-process limit of 10,000 GDI Handles defined by default.

0

Lipa z tymi uchwytami jednym słowem;) w takim razie liczba ikon tak stworzonego Pulpitu ograniczona jest do 10000 ktoś ma chęć na zrobienie takiego explorera? zapraszam serdecznie

0

masz na stronie napisane, że można w rejestrze zmienić wartość do 65,536. Domyślnie jest 10000:

There are two ways to resolve this issue:

- Redesign your application to reduce the number of GDI resources.
- Increase the GDI Handles limit via registry value up to 65,536 (64k).

WARNING: Inappropriate changes to the Windows Registry can damage your operating system! To safeguard against such an event, you should backup your existing Registry by choosing File»Export after launching the Registry Editor and before making any changes.

The registry key which governs the limit of GDI Handles is

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsNT\CurrentVersion\Windows\GDIProcessHandleQuota
1
Krwawy Krawiec napisał(a)

Na TImage miałem tysiące operacji do wykonania. Stworzyłem wtedy zmienną typu TBitmap, wykonywałem na niej operacje, a na koniec przypisywałem zawartość do TImage, co znacznie przyspieszyło iterację.

Najważniejsze jest to, żeby nie wykonywać zbędnych operacji; Jeżeli stosunkowo dużo obiektów ma zostać namalowanych na kanwie, to trzeba zastosować podwójne buforowanie, ewentualnie "potrójne buforowanie" i interfejs odświeżyć jedynie raz (o ile w danym przypadku takie zachowanie jest pożądane);

Pojęcie potrójnego buforowania raczej nie jest stosowane - chodzi po prostu o ustawienie DoubleBuffered na True oraz wykorzystanie pomocniczej bitmapy do wirtualnego malowania po niej i na koniec namalowania jej na kanwie komponentu;

Sam już od kilku miesięcy pracuję nad komponentami, które używają animacji podczas jakichś zmian, np. przesuwanie strzałeczki po zmianie zakładki, przewijanie listy czy animowana zmiana serii wykresu; Trzeba się trochę natrudzić, aby animacje wyglądały płynnie i naturalnie (np. stopniowe zwalnianie obiektu); I choć sprzęt mam bardzo słaby jak na dzisiejsze czasy, to udało się dopracować animacje do tego stopnia, że działają płynnie; A skoro na moim sprzęcie wyglądają dobrze, to na współczesnych maszynach tym bardziej;

Jednak trzeba brać pod uwagę wiele rzeczy, przede wszystkim odświeżać tylko i wyłącznie te obszary komponentu, które odświeżenia faktycznie wymagają; Mając np. formatowalną etykietę i chcąc zmieniać styl linku po najechaniu nań kursorem, nie można odmalowywać całości - trzeba napisać kod tak, aby potrafił przemalować jedynie powierzchnię linku; Inna rzecz to "zgodność bitowa" - 32-bitowe grafiki malowane są o wiele wolniej niż 24-bitowe; Dlatego też jeśli przezroczystość nie jest wymagana, należy użyć grafik 24-bitowych; Z innych rzeczy to już pozostaje optymalizacja kodu i pozbycie się powtórzeń, zbędnych operacji czy niepotrzebnej alokacji pamięci;

toffik napisał(a)

Lipa z tymi uchwytami jednym słowem;) w takim razie liczba ikon tak stworzonego Pulpitu ograniczona jest do 10000 [...]

Nie rozumiem - czy ktokolwiek na świecie posiada na pulpicie więcej niż 100-150 ikon? Sam mam połowę pulpitu zajęte ikonami (pogrupowanymi tematycznie) i wcale nie martwiłbym się, gdyby miał ograniczenie choćby do 100 ikon;

Co innego eksplorer systemowy, umożliwiający wyświetlenie zawartości katalogów; Plików w katalogu można mieć dziesiątki tysięcy, więc to już inna sprawa; Jednak one wszystkie nie są wyświetlane na ekranie - komponent wyświetla tyle ile się zmieści, dlatego działa wystarczająco szybko.

0

niestety popełniłem błąd wszystko zadziałało szybko bo Delphi rysował kopię tylko jednej ikony...

 

for I := 1 to Number do
canvas.Draw(10+X,I*70 + Y,Bitmap);

po zmianie kodu na:

 
for I := 1 to Number do
canvas.Draw(10+X,I*70 + Y,Foldery[I]);

działa strasznie wolno :(

I to jest właśnie wada exploratora windows. Pulpit zapycha się po tygodniu mój jest nieograniczony

0

W pracy, do naszego flagowego programu (zarządzanie procesem produkcyjnym - dużo branżowej technologii), zrobiłem komponent (OCX bo aplikacja nie jest w Delphi) będący właśnie czymś w rodzaju Desktopu. Aplikacja wykonuje konkretne , także i sparametryzowane, akcje. No i każdy user może zapamiętać na swoim Desktopie wybrane przez niego akcje. Wraz z ewentualnymi parametrami. Te, których często używa. Czyli jest pokazywany i chowany panel z akcjami do wyboru, w trakcie wyboru są pobierane ewentualne parametry, o ile dana akcja je posiada i fru - drag&drop na ten desktop. Nawet klasę tego komponentu nazwałem TDesktop. Koledzy już pisali o ilości, ja tylko przypomnę taka starą metodę projektowania - wyobrażamy sobie, ile czegoś będzie i mnożymy przez 10. Bo aż tyle to będzie rzadko. Następnie drugi raz mnożymy przez 10. Tyle to właściwie nigdy nie będzie. I myślę, że w Twoim przypadku WORD zupełnie starczy. Ale ponieważ procesor szybciej obrabia liczby 32 bitowe niż 16 bitowe, to przechowuj wartości w integerach. To była pierwsza rada.

Kiedyś mój kolega, zresztą niesamowicie dobry delphiarz, napisał na pl.comp.lang.delphi, że Borland zrealizował TList w oparciu o tablice dynamiczne. To nic nowego - każdy może to zobaczyć. Ale napisał też, że to niewiarygodnie szybko działa. Poszukaj sobie w źródłach Delphi klasy TObjectList. I w razie potrzeby buduj sobie własne listy. To rada druga.

Już dostałeś info o grafice 24 bitowej. Ale, na litość boską, nie TImage. Nie TBitmap. TImageList to systemowy de facto komponent. Potrafi przechowywać także i ikony. Oczywiście wkładać będziesz 24 bitowe :-), no ale będziesz miał i szybkość i przenikalność. No i ta grafika szybko się maluje, w odróżnieniu od TBitmap. System od razu dostaje to, co potrzebuje i nie musi przekształcać. To była trzecia rada.

Jest taka biblioteka JEDI. Wygooglaj sobie "Project JEDI". W niej masz JvTransparentButton. Na podstawie tego zrób sobie swoja ikonkę na desktopie. To czwarta, ostatnia rada.

0

Pokaż deklarację tego Foldery, bo nie wiadomo co to jest; Poza tym - na której kanwie rysujesz te ikony? Na kanwie komponentu czy pomocniczej bitmapy?

I to jest właśnie wada exploratora windows. Pulpit zapycha się po tygodniu mój jest nieograniczony

Jaka niby wada? Jeśli nie potrafi się utrzymać porządku na komputerze, to i Twój pulpit zostanie zapchany do tego stopnia, że i tak nie będzie można się połapać.

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