Zamrażanie obiektu Shape

0

:/
Witam Na formie mam obiekt Shape który dla przykładu zmienia kolor na losowy. Uruchamiam to jako oddzielny wątek i wszystko jest ok do momentu kiedy kliknę na górny pasek okna. Wówczas zmiana kolorów Shape zatrzymuje się do momentu aż nie puszczę przycisku myszki lub nie przeciągnę okna. Przy rozciąganiu okna program działa prawidłowo. Wygląda tak jakby tylko obiekt Shape na ten czas przestawał wyświetlać, pętla pracuje nieprzerwanie. Proszę o poradę jak pozbyć się tego problemu. Poniżej mój kod programu.

procedure TForm1.start;
var i: integer;
begin
for i := 1 to 5000 do
begin
form1.Caption := inttostr(i);
shape1.Brush.Color:=rgb(random(255),random(255),random(255));
sleep(10);
end;
end;

0

Jedyny pomysł jaki przychodzi mi do głowy to użycie wątku. Zrób tak jak poniżej. I jeżeli chesz mieć
koniecznie postęp wyświetlony na Caption Formatki. Jeżeli nie to usuń zmienną Postep z klasy wątku
oraz procedurę Pokazuj_Postep, która musi być w wątku wywołana poprzez Synchronize, ponieważ o
ile mi wiadomo niektóre metody odwołujące się do formularza nie będą wtedy działać. Na przykład jak
chcesz pokazać postęp na Captionie w procedurze Execute - to nic Ci się nie wyświetli na pasku. No
i przy okazji poczytam o funkcji Rand. Jeżeli losujesz chcesz mieć wylosowany pełen przedział bajtu,
czyli od 0 do 255 (włącznie) to jako parametr Random musisz podać 256, bo funkcja Random, losuje
z zakresu 0 < wylosowana liczba < X. Gdzie X to parametr dla funkcji. Na przykłąd jak dasz Random
i jako parametr (1) to wylosuje Tobie jedynie zero. Zresztą w ogóle poczytaj o wątkach, losowaniu itd.

// ... ciach ...
  TTHr = class(TThread)
  private
    Postep : integer;
    procedure Pokazuj_Postep;
  protected
    procedure Execute; override;
  end;
    
var
  Form1 : TForm1;
  Watek : TThr;
  
implementation

{$R *.dfm}

procedure TThr.Execute;
var
  I : integer;
begin
  FreeOnTerminate := True;
  with Form1 do
  begin
    for I := 1 to 5000 do
    begin
      Shape1.Brush.Color := RGB(Random(256), Random(256), Random(256));
      Sleep(10);
      Postep := I;
      Synchronize(Pokazuj_Postep);
    end;
  end;
end;

procedure TThr.Pokazuj_Postep;
begin
  with Form1 do
  begin
    Caption := IntToStr(Postep);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Randomize;
  Watek := TThr.Create(False);
end;
// ... ciach ...
0

Dzięki za zainteresowanie problemem Olesio. Teraz po kliknięciu i przytrzymaniu klawisza lewego myszki na pasku program na około pół sekundy zatrzymuje się i pracuje dalej. Kiedy klawisz kliknę i przytrzymam na ikonce minimalizacji, maksymalizacji lub krzyżyku program nadal się zatrzymuje. Po kliknięciu i przytrzymaniu klawisza prawego na pasku wyświetlanie obiektu shape także jest blokowane na czas trzymania klawisza. Przeszukałem forum ale niestety nic na ten temat nie znalazłem. Proszę jeszcze o podpowiedź.

0

Spróbuj użyć Application.ProcessMessages

0

Application.ProcessMessages już próbowałem i nic to nie daje</ort>

0

Hmmm, nawet jak na formatce mam wyłączoną możliwość maksymalizacji to po kliknięciu na ikonę
wątek się zamraża. Nie bardzo wiem jak to obejść. Chyba się w łatwy sposób nie da, skoro wątek
też nie jest odporny na to, a jedyne na przesuwanie formatki za pomocą górnej "belki tytułowej" :-/

0

Ty, a spróbuj jeszcze dwie rzeczy:

  1. Daj wyższy priorytet wątkowi
  2. Ustaw DoubleBuffered na formie na true(chociaż to raczej nic nie da)
0

Hmmm, sprawdziłem obie te rzeczy i niestety nic nie dały. Nie wiem w czym pisany jest, na przykład, taki
WinAmp, bo niektóre pluginy do niego są w Delphi chyba. Ale tam możemy sobie przesuwać jego oknem i
naciskać myszkę na przyciskach do minimalizacji itd no i nic nie zamrozimy, a podejrzewam że WinAmp
operacje wykonuje wątkach. Także nie wiem czy takie zamrażanie operacji na grafice w wątku to domena
Delphi czy każdego języka obiektowego. Bo na przykład mam inny program z wątkami napisany kiedyś no
i tam są jakby "wyścigi ProgressBarów" w wielu wątkach i tam naciskanie na przyciski na belce programu,
nie powoduje zatrzymania ProgressBarów. Ten problem dotyczy chyba Images, Shapes no i innych takich.

0

A próbowałeś Application.ProcessMessages w PokazujPostep po wypisaniu wartości na labelu?

[dopisane]

Już chyba wiem, co jest nie tak.
Synu, używasz Synchronize do wypisania wartości na labelu, ale kolor Shape'a robisz już bez tego. Bezpośrednio odwołujesz się do formy, zamiast też to robić poprzez Synchronize.

Czyli chodzi o to, żebyś odmalowywanie shape'a robił tak samo, jak labela. Poprzez Synchronize.
Spróbuj tak.

0

Niestety nic to nie dało. Mam takie pytanie odnośnie obiektów Shape tzn. czy można użyć na przykład w jednym wątku kilka shape i zmieniać im kolory czyli bezpośrednio odwoływać się do nich w wątku bez narażenia na konflikty lub błędy programu. Pytam bo wyczytałem gdzieś, że nie wolno tak robić na obiektach wizualnych a nie pamiętam gdzie to znalazłem.
Przykład kodu pracującego w wątku:

if (amp > 0) then Shape1.Brush.Color:=clLime else Shape1.Brush.Color:=clGreen;
if (amp > 1) then Shape2.Brush.Color:=clLime else Shape2.Brush.Color:=clGreen;
if (amp > 2) then Shape3.Brush.Color:=clLime else Shape3.Brush.Color:=clGreen;
if (amp > 3) then Shape4.Brush.Color:=clLime else Shape4.Brush.Color:=clGreen;
if (amp > 4) then Shape5.Brush.Color:=clLime else Shape5.Brush.Color:=clGreen;
if (amp > 5) then Shape6.Brush.Color:=clLime else Shape6.Brush.Color:=clGreen;
if (amp > 6) then Shape7.Brush.Color:=clLime else Shape7.Brush.Color:=clGreen;

0

Juhas: jak robiłem losowanie koloru w procedurze z Synchronize to program zamarażał się nawet jak
przesuwałeś za belkę tytułową. Dlatego z testów wywnioskowałem, że musi być tak, jak napisałem.

Andrrew: Nie bardzo rozumiem, ale jak zrobisz tak jak poniżej to nie będzie problemów, co innego w
przypadku gdy drugi wątek. Chociaż z moich testów wyszło, że odwoływanie się w drugim wątku do
Shape2 jednocześnie nie pokaże widocznego efektu ani nie spowoduje konfliktu, ale przy niektorych
komponentach jak właśnie TForm należy używać Synchronize, bo taki konflikt może jednak zaistnieć.

      Shape1.Brush.Color := RGB(Random(256), Random(256), Random(256));
      Shape2.Brush.Color := RGB(Random(256), Random(256), Random(256));

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