PDA

View Full Version : سوال: اجرای فرمی حاوی Progressbar که هنگام فریز شدن mainthread بکار خود ادامه دهد



rahro
دوشنبه 11 فروردین 1393, 11:24 صبح
سلام به دوستان سال نو بر همهگان مبارک
فرمی دارم بنام TestForm و در این فرم یک progressbar قرار دارد که دایم بوسیله یه تایمر در حال پر شدن و خالی شدن است
بنده در MainThread اصلی کد ذیل را اجرا کردم مثلا فرض کنید در یک button.click
وقتی که برنامه را اجرا و روی button کیک میکنم پروژه فریز میشه و تا زمانی که کد Sleep اجرا نشه فرم TestForm منو فریز نگه میداره
بنده چطور میتوانم کاری کنم که TestForm فریز نشه .
در ضمن بنده نمیخوام Sleep رو در یک Thread ثانویه بزارم ام چنانچه TestForm در یک ترد اجرا بشه ممانعتی نداره
دوستان به کد ذیل نگاهی بیندازید و بنده را راهنمایی بفرمائید.
TestForm:=TTestForm.Create(nil);
TestForm.Show;
Sleep(5000);

AliReza Vafakhah
دوشنبه 11 فروردین 1393, 13:24 عصر
Application.ProcessMessage رو در تایمر بگذار ، ببین مشکل حل میشه

یوسف زالی
دوشنبه 11 فروردین 1393, 15:44 عصر
progress1.refresh
این رو تست کنید، اگر نه، روش ترد رو پیش ببریم.

rahro
چهارشنبه 13 فروردین 1393, 12:14 عصر
progress1.refresh
این رو تست کنید، اگر نه، روش ترد رو پیش ببریم.

ممنون از پاسخ دوستان. اما این جواب مشکل من نبود.
وقتی کامپایل دلفی در زمان اجرا به sleep می رسه فریز میشه در نتیجه تا وفتی کار sleep تمام نشه به سایر عملیات توجهی نمیکنه اینکه درون تایمر application.processmessage رو بزارم و یا progress1.refresh رو در کد قرار بدم باز عمل فریز رخ می ده
من میخوام وقتی sleep اجرا میشه عملیات فریز نشه

BORHAN TEC
چهارشنبه 13 فروردین 1393, 16:53 عصر
با سلام،
به جای تابع sleep می توانید از روالی مثل این استفاده کنید:
procedure SpecialSleep(const ms: cardinal);var
oldTime, newTime: cardinal;
begin
oldTime := GetTickCount;
while True do
begin
Application.ProcessMessages;
newTime := GetTickCount;
if (newTime - oldTime >= ms) then
break;
end;
end;
موفق باشید.

rahro
پنج شنبه 14 فروردین 1393, 06:19 صبح
از پاسخ شما ممنونم اما هنوز پاسخ سوال من پیدا نشده ، شاید واسه اینه که من سوالمو واضح نپرسیدم پاسخ شما صحیح بود فقط اینکه من جای sleep هر کد سنگینی رو میخوام قرار بدم تا فرم حاوی progressbar فریز نشه موردی که شما اشاره کردید تنها جهت وقفه کاربردی است اگه ممکنه راه حل این موردو به من بگید خیلی توی فروم های خارجی گشتم اما نتونستم پاسخم رو پیدا کنم .ممنون

Mask
پنج شنبه 14 فروردین 1393, 20:12 عصر
میتونید عملیات پردازشیتون رو ببرید در یه ترد جدا، و بوسیله Sync مقدار پردازش رو به پروگرسبار اعلام کنید.

rahro
جمعه 15 فروردین 1393, 08:28 صبح
میتونید عملیات پردازشیتون رو ببرید در یه ترد جدا، و بوسیله Sync مقدار پردازش رو به پروگرسبار اعلام کنید.
جناب گلد. اگر امکان داره یه نمونه رو واسم بزار ممنون میشم.

Mask
جمعه 15 فروردین 1393, 16:54 عصر
این یه نمونست ، میتونید ازش ایده بگیرید:

unit Unit1;

interface


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


Type
MyThread = Class(TThread)
protected
procedure Execute; override;
end;


type
TForm1 = class(TForm)
ProgressBar1: TProgressBar;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
procedure SendWorking;
{ Public declarations }
end;


var
Form1: TForm1;


implementation


{$R *.dfm}


procedure TForm1.SendWorking;
begin
if ProgressBar1.Position = 10 then
ShowMessage('Opration Complit')
else
ProgressBar1.Position := ProgressBar1.Position + 1;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
T: MyThread;
begin
ProgressBar1.Position := 0;
ProgressBar1.Max := 10;
T := MyThread.Create(True);
T.FreeOnTerminate := True;
T.Resume;
end;


{ MyThread }
procedure MyThread.Execute;
var
i: Integer;
begin
i := 0;
while True do
begin
if i = 11 then
Break;
Sleep(1000);
inc(i);
Synchronize(Form1.SendWorking);
end;
inherited;
end;


end.

rahro
جمعه 15 فروردین 1393, 17:34 عصر
این یه نمونست ، میتونید ازش ایده بگیرید:

unit Unit1;

interface


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


Type
MyThread = Class(TThread)
protected
procedure Execute; override;
end;


type
TForm1 = class(TForm)
ProgressBar1: TProgressBar;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
procedure SendWorking;
{ Public declarations }
end;


var
Form1: TForm1;


implementation


{$R *.dfm}


procedure TForm1.SendWorking;
begin
if ProgressBar1.Position = 10 then
ShowMessage('Opration Complit')
else
ProgressBar1.Position := ProgressBar1.Position + 1;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
T: MyThread;
begin
ProgressBar1.Position := 0;
ProgressBar1.Max := 10;
T := MyThread.Create(True);
T.FreeOnTerminate := True;
T.Resume;
end;


{ MyThread }
procedure MyThread.Execute;
var
i: Integer;
begin
i := 0;
while True do
begin
if i = 11 then
Break;
Sleep(1000);
inc(i);
Synchronize(Form1.SendWorking);
end;
inherited;
end;


end.

گلد جان ممنون اما من قبلا در اول تاپیک گفتم لنده با thread و sync آشنام اما متاسفانه بازم کد فریز میشه شما مثال خودتونو در نظر بگیر اگر در رویداد ذیل کد شما در انتهای پروسیجر sleep رو اضافه کنی تا زمانی که کار sleep تمام نشه thread اجرا نمیشه

procedure TForm1.Button1Click(Sender: TObject);
var
T: MyThread;
begin
ProgressBar1.Position := 0;
ProgressBar1.Max := 10;
T := MyThread.Create(True);
T.FreeOnTerminate := True;
T.Resume;
Sleep(3000);
end;

لازم بذکر است جای sleep هر پردازش زمان دار میتواند باشد اما نمیخوام اینجور عملیات زمان بر در thread اجرا بشن فقط میخوام فرم حاوی progressbar فریز نشه

rahro
جمعه 15 فروردین 1393, 19:05 عصر
از متنی که نوشتید میشه مطمئن شد ، تسلط کافی برای کار با ترد روندارید.
چرا sleep رو در دکمه قرار دادید؟ چرا sleep یا عملیات پردازشی تون رو در بدنه ترد پیاده نمیکنید.؟
اگه صلاح میدونید یک تکه از کد اصلیتون رو قرار بدید.
کد نمونه که قرار دادم مربوط به مثال جنابعالی بود ، و اینکه میگید تسلط کافی به ترد ندارم هیچ ادعای نداشتم واسه همین سوال پرسیدم
بهتر بود بجای قضاوت سریع کمی به نوشته های بنده توجه میکردید شاید بهتر است بگم هدف رفع مشکل است نه ایجاد حاشیه و جواب های بی مورد.
جناب گلد شما تنها بفرمائید چرا وقتی بنده دستور sleep را در پروسیجر button قرار دادم عملیات ترد بعد از sleep انجام میشه و برای حل این مشکل چکار باید کرد ، فبلا هم گفتم بنده با مفاهیم ترد آسنا هستم اینکه ترد رو ایجاد کنم و عملیات آبجکت ها را در sync مربوط به execute ترد قرار بدم و ...
اما بنده فرمی را جهت please Wait طراحی کردم که میخوام وقتی در mainthread عملیاتی اجرا میشود قبلش این فرم که دارای progressbar است به نمایش دربیاد بدون اینکه progressbar ان متوقف بشه یعنی همزمان عملیات proce در دو ترد اصلی و ثانویه بدون freez انجام بشه اگر همچنان منظور بنده نامفهوم است بفرمائید تا نمونه کدی را قرار دهم با تشکر

Mask
جمعه 15 فروردین 1393, 19:39 عصر
پیشنهاد میکنم کدتون رو قرار بدید.


چرا وقتی بنده دستور sleep را در پروسیجر button قرار دادم عملیات ترد بعد از sleep انجام میشه
این حرف درست نیست.عملیاتی که در ترد جانبی انجام میشه ربطی به Sleep مین ترد نداره.


میخوام وقتی در mainthread عملیاتی اجرا میشود
با در نظر گرفتن این نوشته، میشه حدس زد ، عملیات پردازشیتون در مین ترد هست، که بنده قبلا هم گفتم، عملیات پردازشی رو در ترد دوم پیاده سازی کنید.

یوسف زالی
شنبه 16 فروردین 1393, 12:34 عصر
معمولا در ترد جداگانه عناصر گرافیکی نمی گذارن، مثلا اگر فرم بگذارید بالاخره برای نمایشش باید دست به دامن ترد اصلی بشید.
می تونید مثلا از توابع API استفاده کنید.
دستور Sleep در حقیقت ترد مربوطه رو می خوابونه، اگر فقط منظور نظر شما همین دستور باشه می تونید از روش زیر استفاده کنید:


procedure Delay(milliseconds: Cardinal);
// this procedure sleeps without suspend current thread
var
Start: Cardinal;
begin
Start := GetTickCount;
Form2.Show;


while GetTickCount -Start < milliseconds do
begin
Form2.Caption := IntToStr(GetTickCount);
// or progress bar step it
end;


Form2.Hide;
end;




اما این دستورات به درد مثلا نمایش در تاخیرات کانکت شدن به دی بی نمی خوره.
برای این کارها بهتره برعکس عمل بشه. یعنی این که کاری که باعث شده ترد بخوابه، در ترد جدا انجام بشه، اما نمایش وضعیتش رو ترد اصلی به عهده بگیره.

rahro
دوشنبه 18 فروردین 1393, 15:52 عصر
معمولا در ترد جداگانه عناصر گرافیکی نمی گذارن، مثلا اگر فرم بگذارید بالاخره برای نمایشش باید دست به دامن ترد اصلی بشید.
می تونید مثلا از توابع API استفاده کنید.
دستور Sleep در حقیقت ترد مربوطه رو می خوابونه، اگر فقط منظور نظر شما همین دستور باشه می تونید از روش زیر استفاده کنید:


procedure Delay(milliseconds: Cardinal);
// this procedure sleeps without suspend current thread
var
Start: Cardinal;
begin
Start := GetTickCount;
Form2.Show;


while GetTickCount -Start < milliseconds do
begin
Form2.Caption := IntToStr(GetTickCount);
// or progress bar step it
end;


Form2.Hide;
end;




اما این دستورات به درد مثلا نمایش در تاخیرات کانکت شدن به دی بی نمی خوره.
برای این کارها بهتره برعکس عمل بشه. یعنی این که کاری که باعث شده ترد بخوابه، در ترد جدا انجام بشه، اما نمایش وضعیتش رو ترد اصلی به عهده بگیره.


You-See جان
آخه من خودم یه example دارم گه از سایت های خارجی گرفتم اینکارو انجام داده در زمان آقای کشاورز هم توی یکی از مقالاتش یه توضیحاتی داده بود اینکه پیامای سیستمی رو بفرستیم به mainthread و به این شکل آگاهش کنیم ?!?!

rahro
سه شنبه 19 فروردین 1393, 20:27 عصر
جناب You-See شما چرا آخه؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟؟
تا حالا اینجوری راه انداختن رو ندیده بودم بابا یکی نیست یه جواب درست به ما بده اگر نیست بگین تا یه جا دیگه برم؟!؟!؟؟!:عصبانی++:

یوسف زالی
سه شنبه 19 فروردین 1393, 22:20 عصر
لطف مکرر، حق مسلم؟!
یه کار می کنید واقعا آدم خستگی تو تنش می مونه.
دوست گل من دو شبه بعد از کار خسته و کوفته فقط روی سوال شما دارم کار می کنم.
از طرفی؛ من که قسم نخوردم! تو خود حدیث مفصل بخوان از این مجمل.
به هر جهت شما مختارید هر کجا خواستید برید، پیدا کردید برای ما هم بیارید ممنون می شم.
اما اگر جواب خوب می خواهید باید صبر کنید.

(خیلی ناراحت.. )

یوسف زالی
چهارشنبه 20 فروردین 1393, 15:01 عصر
دوستان عزیز این هم از کامپوننت مورد نظر:
http://barnamenevis.org/showthread.php?447655-%DA%A9%D8%A7%D9%85%D9%BE%D9%88%D9%86%D9%86%D8%AA%D B%8C-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%86%D9%85%D8%A7%DB%8C%D8%B4-%DB%8C%DA%A9-%D8%A7%D9%86%DB%8C%D9%85%DB%8C%D8%B4%D9%86-%D8%AF%D8%B1-%D9%87%D9%86%DA%AF%D8%A7%D9%85-Freeze-%D8%B4%D8%AF%D9%86-%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87&p=2002703#post2002703

در پست مربوطه توضیحات مفصلا داده شد.