Форум: "Начинающим";
Текущий архив: 2009.10.25;
Скачать: [xml.tar.bz2];
ВнизЗапуск расчета сразу после отрисовки формы Найти похожие ветки
← →
Franzy (2009-09-01 13:43) [0]Есть программа, выполняющая некий трудоемкий расчет. Нужно, чтобы расчет начинался сразу после запуска программы, при этом окно программы должно быть активировано, т.е. в фокусе и поверх остальных окон, т.к. на форму в соотв. оконшки выводятся различные компоненты отчета о прогрессе расчета.
Если пуск прописать в OnCreate, окошко не рисуется вообще до окончания расчета. В OnShow - окошко не активируется. Вставка form1.activate не помогает. Т.е. программа статует как бы в свернутом состоянии. Причем при этом "висит" и не разворачивается, несмотря на вставки Application.processmessages при каждом обновлении отчета.
Как это реализовать правильно?
← →
clickmaker © (2009-09-01 13:48) [1]> Как это реализовать правильно?
Запускать расчет в отдельном потоке. Тогда не суть важно, в каком событии.
Оповещать различные компоненты отчета о прогрессе расчета можно через PostMessage форме.
← →
Franzy (2009-09-01 13:50) [2]Забыл уточнить: сами расчетные процедуры находятся в подключаемой dll.
← →
Медвежонок Пятачок © (2009-09-01 13:50) [3]и правильно что забыл. ибо уточнение лишнее.
← →
Franzy (2009-09-01 14:03) [4]А еще варианты есть?
← →
clickmaker © (2009-09-01 14:09) [5]> А еще варианты есть?
Application.ProcessMessages в цикле расчета после очередной итерации.
А чем поток не устраивает?
← →
sniknik © (2009-09-01 14:11) [6]можно послать самому сете сообщение и уже в нем чтото делать, точно будет после OnShow, если посылать в нем.
или банально поставить таймер, включать там же и выключать после 1й сработки.
или поток стартовать, к тому времени когда нужда будет синхронизироваться для отрисовки результатов, форма уже успеет появиться.
← →
Медвежонок Пятачок © (2009-09-01 14:14) [7]у него же уже колбаки вовсю прогресс расчета рисуют. чем не место для процессмессаджес?
← →
Franzy (2009-09-01 14:16) [8]А внутри потока можно обращаться к объектам формы?
← →
Медвежонок Пятачок © (2009-09-01 14:17) [9]можно, если поток главный.
← →
Franzy (2009-09-01 14:22) [10]Я так понимаю, проблема в том, что onCreate и onShow вызываются прямо ПЕРЕД тем, как окончатся соотв. процессы. А мне нужно ПОСЛЕ их окончания :( Похоже, придется использовать треды. Кстати, сразу вопрос по ним: можно ли обращаться внутри треда к элементам формы (если я объвлю класс треда внутри модуля формы)?
← →
Медвежонок Пятачок © (2009-09-01 14:26) [11]если я объвлю класс треда внутри модуля формы)?
Модуль формы - понятие времени написания программы.
После F9 никаких модулей уже нет и нет разницы где задекларирован класс потока.
← →
Сергей М. © (2009-09-01 14:29) [12]
> Franzy (01.09.09 14:22) [10]
> мне нужно ПОСЛЕ их окончания
Просто создавай форму ПОСЛЕ их окончания.
← →
Медвежонок Пятачок © (2009-09-01 14:29) [13]Автор, в обработчике OnCreate посылай сам себе сообщение c помощью postmessage
в обработчике сообщения все уже будет отрисовано. в нем и запускай свои мега-расчеты.
← →
Сергей М. © (2009-09-01 14:31) [14]
> можно ли обращаться внутри треда к элементам формы
Это смотря что ты подразумеваешь под "элементами формы"
← →
Franzy (2009-09-01 14:41) [15]Я хочу разобраться с тредами, мне это может пригодиться в других приложениях :)
Сделал через треды так:
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Math;
type
TForm1 = class(TForm)
.....
end;
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
var
Form1: TForm1;
GridThread : TMyThread;
///////////////////////////////
implementation
{$R *.dfm}
.......
procedure TMyThread.Execute;
begin
....
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
GridThread:=TMyThread.Create(false);
GridThread.Execute;
end;
end.
Вылетает с ошибкой "Canvas does not allow drawing"
← →
Медвежонок Пятачок © (2009-09-01 14:45) [16]Это очень мудро, привести здесь весь код, а тот который имеет отношение к ошибке заменить многоточием
← →
Franzy (2009-09-01 14:46) [17]Сделал тестовое приложение, в котором только тред, меняющий капшн формы - все работает нормально, ошибки нет. Может быть, дело в том, что из треда у меня вызывается процедура длл, которая вызывает коллбэк, который находится внутри основной программы?
← →
Franzy (2009-09-01 14:46) [18]
> Это очень мудро, привести здесь весь код, а тот который
> имеет отношение к ошибке заменить многоточием
Там не один десяток страниц :(
← →
Anatoly Podgoretsky © (2009-09-01 14:47) [19]> Franzy (01.09.2009 14:41:15) [15]
GridThread.Execute; запускай в отдельном методе, после начальных обработчиков.
← →
Медвежонок Пятачок © (2009-09-01 14:48) [20]Там не один десяток страниц :(
Может тебе и ответы давать многоточием?
:)))
← →
Franzy (2009-09-01 14:49) [21]Закомментиовал коллбэк (в смысле, функция теперь ничего не делает), но ошибка все равно выскакивает.
← →
Медвежонок Пятачок © (2009-09-01 14:50) [22]Сделал тестовое приложение, в котором только тред, меняющий капшн формы - все работает нормально, ошибки нет.
мало тредов потому и нет. а еще просто потому нет потому что повезло.
зы
пациент помойму просто хочет поболтать или пытается прикалываться над форумом
← →
Медвежонок Пятачок © (2009-09-01 14:52) [23]но ошибка все равно выскакивает.
в [9] можно узнать почему это происходит.
← →
Franzy (2009-09-01 14:54) [24]
> GridThread.Execute; запускай в отдельном методе, после начальных
> обработчиков.
Вот такой код прекрасно работает:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
var
Form1: TForm1;
MyThread: TMyThread;
implementation
{$R *.dfm}
procedure TMyThread.Execute;
begin
form1.caption:="Hello World";
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
MyThread:=TMyThread.create(false);
MyThread.Execute;
end;
end.
← →
clickmaker © (2009-09-01 14:55) [25]> GridThread.Execute;
это не нужно.
если параметр в конструкторе false, он сразу запустится.
если true, то после установки свойств треда нужно вызвать Resume
← →
Медвежонок Пятачок © (2009-09-01 14:56) [26]ну так и используй его. а тот код, что с ошибкой сотри.
← →
clickmaker © (2009-09-01 14:57) [27]> Вот такой код прекрасно работает
потому что ты просто запустил метод Execute явно и в основном потоке. Смысла отдельного потока здесь теряется. С таким же успехом это мог быть TSomeObject.Execute
← →
Franzy (2009-09-01 14:57) [28]Объясните, тогда как правильно, я не понимаю и хочу разобраться. В справке все очень кратко, только про Synchronize что-то упоминается.
← →
Franzy (2009-09-01 15:05) [29]Ага, ошибка появляется, если внутри execute использовать ShowMessage! Почему так?
← →
Медвежонок Пятачок © (2009-09-01 15:27) [30]у попа была собака, он ее любил ....
← →
Franzy (2009-09-01 15:36) [31]2Медвежонок Пятачок
Если не можете ничего сказать по существу, не флеймите, пожалуйста, для этого, кажется, есть отдельный подфорум. У меня есть реальная проблема и я хочу с ней разобраться.
← →
clickmaker © (2009-09-01 15:36) [32]> Почему так?
потому что
When you use objects from the class hierarchy, their properties and methods are not guaranteed to be thread-safe. That is, accessing properties or executing methods may perform some actions that use memory which is not protected from the actions of other threads.
Если уж сильно приспичило показать сообщение в потоке, используй апишную MessageBox()
← →
Amoeba © (2009-09-01 15:37) [33]
> только про Synchronize что-то упоминается.
Вот-вот! И не просто так упоминается! И не только в справке, а также и в тексте, который автоматически генерируется при создании модуля потока.
← →
Franzy (2009-09-01 15:41) [34]2sniknik
Вариант с postmessage самому себе сработал, спасибо.
Хотя с тредами по-прежнему не понятно :(
← →
Leonid Troyanovsky © (2009-09-01 15:44) [35]
> Franzy (01.09.09 15:36) [31]
> У меня есть реальная проблема и я хочу с ней разобраться.
Проблема не одна.
В dll от Synchronize практической пользы нет.
--
Regards, LVT.
← →
sniknik © (2009-09-01 15:45) [36]> мало тредов потому и нет. а еще просто потому нет потому что повезло.
и еще потому, что каптион присваивается посылкой сообщения (WM_SETTEXT), т.е. код с ним вообще не показатель.
← →
Юрий Зотов © (2009-09-01 15:50) [37]> Franzy (01.09.09 15:05) [29]
1. Расчет запускаете в отдельном потоке из OnShow главной формы. При создании объекта TMyThread форма передает ему свой хэндл и тот запоминает полученный хэндл в своем поле с именем MainFormHandle.
2 Определяете структуру данных, которые поток будет передавать форме, например:type
TMyData = record
data1: integer;
data2: string[255];
...
end;
PMyData = ^TMyData;
3. В секции interface модуля потока определяете сообщение для передачи данных:const
WM_UserPlus100 = WM_USER + 100;
4. Метод Execute потока:procedure TMyThread.Execute;
var
MyData : TMyData;
begin
while not Terminated do
begin
MyData.data1 := ...;
MyData.data2 := ...;
...
PostMessage(MainFormHandle, WM_UserPlus100, @MyData, 0);
... // Здесь выполняем шаг расчета
end
end;
5. В секции protected формы делаете метод:procedure WMUserPlus100(var Message: TMessage); message WM_UserPlus100;
и реализуете этот метод:procedure TForm1.WMUserPlus100(var Message: TMessage);
begin
inherited;
with PMyData(Message.WParam)^ do
begin
ProgressBar1.Position := data1;
Edit1.Test := data2;
...
end
end;
← →
Franzy (2009-09-01 15:56) [38]2clickmaker
А, т.е. они имели ввиду class hierarchy в широком смысле, т.е. вообще все объекты и контролы? Я просто так понял, что речь идет об объектах, которые одновременно используются в разных потоках. Ясно. Т.е. нужно избегать прямого обращения к свойствам и методам объектов, а вместо это использовать WinAPI и мессаджи?
← →
Franzy (2009-09-01 15:59) [39]
> Расчет запускаете в отдельном потоке из OnShow главной формы
А при этом расчет не будет перезапускаться каждый раз, когда окно сворачивается на панель задач и затем разворачивается?
← →
Amoeba © (2009-09-01 16:01) [40]http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1370
← →
Юрий Зотов © (2009-09-01 16:11) [41]> Franzy (01.09.09 15:59) [39]
> А при этом расчет не будет перезапускаться каждый раз, когда
> окно сворачивается на панель задач и затем разворачивается?
Не будет. Событие OnShow возникает, когда свойство Visible формы меняется и становится равным True. Вы же не собираетесь "моргать" главной формой, насколько я понимаю?
:o)
← →
clickmaker © (2009-09-01 16:15) [42]> Т.е. нужно избегать прямого обращения к свойствам и методам
> объектов, а вместо это использовать WinAPI и мессаджи?
в не главных потоках, и смотря, к каким методам и свойствам. К тем, которые затрагивают vcl-ную часть UI - да.
← →
Leonid Troyanovsky © (2009-09-01 16:15) [43]
> sniknik © (01.09.09 15:45) [36]
> каптион присваивается посылкой сообщения (WM_SETTEXT),
А там не SendMessage, but Perform, так что и с заголовком не все чисто.
--
Regards, LVT.
← →
Franzy (2009-09-01 16:18) [44]Так, с потоками разобрался, кажется, спасибо. Я правильно понял, что "главный поток" - это само приложение, в котором все эти треды объявляются?
Но сделал все через отправку сообщения самому себе :) Там мороки существенно меньше.
← →
oldman © (2009-09-01 16:27) [45]
> Franzy (01.09.09 13:43)
Будь проще.
Запусти нужный тебе расчет в отдельном потоке из TTimer.
При запуске потока дизабли таймер.
Форма отрисуется, будет активной, поток пойдет.
Время старта таймера поставь опытным путем.
← →
Leonid Troyanovsky © (2009-09-01 17:48) [46]
> Franzy (01.09.09 16:18) [44]
> Так, с потоками разобрался, кажется, спасибо. Я правильно
> понял, что "главный поток" - это само приложение
MainThreadId - идентификатор первичного потока, т.е., того, что
создает CreateProcess и возвращает в PROCESS_INFORMATION structure.
Для обычных дельфийский приложений он же и VCL thread.
--
Regards, LVT.
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2009.10.25;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.051 c