Перейти к содержанию
Fire Monkey от А до Я

gonzales

Пользователи
  • Постов

    334
  • Зарегистрирован

  • Посещение

  • Победитель дней

    27

Весь контент gonzales

  1. Спасибо! До меня начало доходить, нужно полностью отойти от метода программирования, когда в коде основной формы пишутся все процедуры и функции, все выносить в отдельные юниты, в которых в потоках (потоке) обрабатывается вся логика и лишь через синхронизацию выдает информацию в главный поток. А главный поток по сути свободен, занят лишь перерисовкой форм и получением событий мыши.
  2. Ну да уж))) Я читал этот Ваш пост и вот этот http://www.cyberforum.ru/blogs/469693/blog4909.html, натыкался на него еще до этого обсуждения. Тем не менее я считаю, что использование ProcessMessages в простых случаях оправдано. Ведь это ни что иное, как изменение приоритетов процессов, например когда нужно просто перерисовать форму, с помощью ProcessMessages останавливаем текущий процесс и запускаем процессы в очереди. Но это сугубо ИМХО. Зачем было убирать его мне не понятно, хочешь используй, не хочешь - не используй, делай костыли, как предложил IS1 со слипами, потоками и прочими радостями. С потоками мне все понятно, сам их активно использую, например при раскодировании изображений с ip-камер. Но как их использовать, когда есть очередность действий в главном потоке? Не сочтите за труд, я думаю это многим было бы интересно, покажите, как переписать пример выше используя Вашу концепцию.
  3. Прошу прощения за долгое отсутствие Вот накидал простой исходникtest10.3.zip. В проекте 3 формы, первой создается SplashForm. Остальные формы имеют в OnCreate высоконагруженные вычисления, поэтому после каждого создания формы отображаю на SplashForm статус формы. Дабы все это отрисовывалось использую Application.processmessages.
  4. sleep здесь исключительно для наглядности, и вообще весь код. Реальная задача: имеется окно заставки, на нем отображается процесс загрузки приложения. Не могу добиться нормального функционирования, потоки не помогают. Разве что действительно таймер использовать)))
  5. Можно. Но этот выход не выход))) procedure TForm1.Button1Click(Sender: TObject); var a,b:integer; begin a := 1; b := 2; label1.Text:=inttostr(a); //application.ProcessMessages; sleep(2000); a := a + b; label1.Text:=inttostr(a); //application.ProcessMessages; sleep(2000); a := a + b; label1.Text:=inttostr(a); //application.ProcessMessages; sleep(2000); end; Боюсь представить, какой код будет в таком случае
  6. Спасибо, идею я понял, надо мне ее осмыслить. А что делает главный поток, пока класс ждет ответа от потока? Вот, например, инициализация устройств, я шлю команду "КОЛ-ВО_УСТРОЙСТВ", получаю ответ, допустим 5, далее цикл от 1 до 5 с командой "ОПРОС_УСТРОЙСТВА", получаю ответ "ОК", отдаю в интерфейс информацию. В Вашем примере получается, я создаю в основном потоке очередь сообщений из одной команды, отправляю ее в класс, который эту команду из очереди отправляет в поток, а вот дальше не понятно, класс ждет ответа, или может формировать какие-то еще очереди команд? Ну допустим есть какой-то коллбэк из потока в класс, вернулась информация о кол-ве устройств, кто дальше должен сформировать очередь команд на опрос устройств? Класс отдает информацию в главный поток, а он ведь уже трудится дальше и не ждет прихода информации от класса, или ждет? Тогда зачем поток?
  7. Спасибо за поддержку! Суть в следующем, есть сервер (самописный TCP), крутится на микроконтроллере, есть клиенты (в основном Android, iOS). К серверу подключен ряд устройств. Клиенты управляют сервером посредством управляющих команд (конфигурируют устройства, настраивают логику работы и т.д), и получают ответы об изменениях в устройствах. Был разработан некий универсальный протокол общения (id адресата, id отправителя, id команды, параметры) в 15 байт. То есть клиент посылает пакет в 15 байт, и сервер отвечает пакетом в 15 байт. На текущий момент есть около 100 команд для общения. Например для конфигурирования устройства я посылаю команду с указанием типа устройства, после получения положительного ответа, посылаю команду с уставкой, после получения ответа посылаю команду на старт, и так далее. Также сервер рассылает информацию клиентам об изменениях в устройствах. В общем все работает в одном потоке, но если какое-то из устройств не ответит вовремя, то возникает задержка, из-за чего хочется запихнуть все общение на клиенте в поток. Надеюсь понятно расписал, но мог что-то уточнить.
  8. да, еще создаем вставки на асме, , всего стопиццот строк кода и всего делов Уже неделю вспахиваю интернет, но пока ничего внятного.
  9. Может я совсем тупой, но я не могу этого понять. Вот банальный пример, одна кнопка, один лэйбл. Вот весь код unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls; type TForm1 = class(TForm) Label1: TLabel; Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.fmx} procedure TForm1.Button1Click(Sender: TObject); begin label1.Text:='2'; //application.ProcessMessages; sleep(5000); label1.Text:='3'; end; end. Как заставить это все работать без ProcessMessages? Хочу увидеть при нажатии на кнопку "2", затем "3". Пипец задачка(((((
  10. также не работает((( procedure TSplashForm.LoadProgramm; begin Application.CreateForm(TForm1, Form1); tthread.CreateAnonymousThread( procedure begin // Асинхронная логика sleep(100); tthread.Synchronize(nil, procedure begin StartUpLabel.Text := 'Инициализация!!!'; Label1.Text := VERSION; end); end).Start; end; Вот кусок кода, LoadProgramm вызывается при показу Splash формы. Я хочу после создания формы Form1 показать на сплэше текст "Инициализация!!!"
  11. надо делать какие-то callback функции, каким-то образом их менять в зависимости от ситуации, в общем скила мне не хватает(
  12. Есть у меня такой. Проблема не в идентификации ответа, а в очередности прихода сообщений, как выполнить следующий запрос на основании ответа от предыдущего, если я не знаю, когда его (ответ) получу, и какой он будет в очереди.
  13. Проблема в том, что клиентов может быть много, соответственно приходов много))), и то, что флаг поднят, еще не значит, что это нужный ответ. Вот над этим я думаю постоянно, но внятного решения пока не вижу. Например мне нужно послать один запрос, получить ответ и на основании этого ответа послать еще тот или иной запрос. при линейной логике, запрос-ответ, запрос-ответ, это работает, а если у меня есть асинхронный поток, в который сыплется очередь из сообщений в которой есть "нужные" ответы, как организовать правильную логику работы - я пока не придумал. Если есть какие-нибудь соображения, буду благодарен?
  14. Спасибо за пример, но по ходу я нуб 80 уровня, я не вижу, чем он может мне помочь. Посмотрите плиз конструкцию, она работает очень криво, но я не могу понять почему Вот класс type TClusterClient = class(TThread) public procedure ReadPacket(HTTPAnswer: THTTPAnswer); procedure ChechClient; protected procedure Execute; override; end; procedure TClusterClient.ChechClient; var Len: integer; Buf: TIdBytes; H: THTTPAnswer; begin if form1.Client1.Socket.InputBufferIsEmpty = false then begin try SetLength(Buf, SizeOf(THTTPAnswer)); form1.Client1.Socket.ReadBytes(Buf, SizeOf(THTTPAnswer), false); Move(Buf[0], H, Length(Buf)); ReadPacket(H); finally SetLength(Buf, 0); end; end; end; procedure TClusterClient.Execute; begin while not Terminated do begin try if form1.Client1.Connected then begin if form1.Client1.Socket.CheckForDataOnSource(100) then begin ChechClient; end; end; except end; end; end; procedure TClusterClient.ReadPacket(HTTPAnswer: THTTPAnswer); var t_out, t_in: TIdBytes; Size: TSizeF; i, j: integer; l: integer; // d, a: byte; VirtualNode: IXMLNode; VirtualElementNode: IXMLNode; c: cardinal; s: string; begin if (HTTPAnswer.Preamble[0] = 67) and (HTTPAnswer.Preamble[1] = 76) and (HTTPAnswer.Preamble[2] = 85) then begin TThread.Synchronize(nil, procedure begin form1.AnswerIsComming := HTTPAnswer.Command; form1.HTTPAnswer := HTTPAnswer; end); end else if (HTTPAnswer.Preamble[0] = 85) and (HTTPAnswer.Preamble[1] = 80) and (HTTPAnswer.Preamble[2] = 68) then begin if HTTPAnswer.Command = HTTP_SEND_ELEMENT_UPDATE then begin for i := 0 to Length(form1.RoomElements) - 1 do begin if HTTPAnswer.Data10 = 1 then // устройства begin if (form1.RoomElements[i] is TRele) { and (MasterTask.Status <> TTaskStatus.Canceled) } then begin TThread.Synchronize(nil, procedure var d, a: byte; begin d := (form1.RoomElements[i] as TRele).Device_ID; a := (form1.RoomElements[i] as TRele).Device_Adress; if (d = HTTPAnswer.Device_ID) and (a = HTTPAnswer.Device_Adress) then form1.device[d].Board[a].CurrentValue := HTTPAnswer.Data2; (form1.RoomElements[i] as TRele).ReleSwitch.IsChecked := form1.device[d].Board[a] .CurrentValue.ToBoolean; form1.ConnectImage.Bitmap := form1.IconList.Bitmap(Size, 15); end); end; end; end; end; end; end; А вот запрос информации с сервера из главного потока procedure TForm1.SendHTTPMessage(ReadTimeout: integer); var t_out, t_in: TIdBytes; Size: TSizeF; begin TriesToSend := 0; if ReadTimeout = -1 then begin if LocalIP = true then begin Client1.ConnectTimeout := 500; Client1.ReadTimeout := 1000; end else begin Client1.ConnectTimeout := 500; Client1.ReadTimeout := 2000; end; end else begin Client1.ConnectTimeout := 1000; Client1.ReadTimeout := ReadTimeout; end; HTTPAnswer.Preamble[0] := 0; HTTPAnswer.Preamble[1] := 0; HTTPAnswer.Preamble[2] := 0; HTTPAnswer.Device_ID := 0; HTTPAnswer.Device_Adress := 0; HTTPAnswer.Command := 0; HTTPAnswer.Data1 := 0; HTTPAnswer.Data2 := 0; HTTPAnswer.Data3 := 0; HTTPAnswer.Data4 := 0; HTTPAnswer.Data5 := 0; HTTPAnswer.Data6 := 0; HTTPAnswer.Data7 := 0; HTTPAnswer.Data8 := 0; HTTPAnswer.Data9 := 0; HTTPAnswer.Data10 := 0; try Size.cx := 16; Size.cy := 16; if Client1.Connected = false then Client1.Connect; if Client1.Connected = true then begin Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, 15); AnswerIsComming := 0; SetLength(t_out, SizeOf(HTTPRequest)); Move(HTTPRequest, t_out[0], SizeOf(HTTPRequest)); Client1.Socket.WriteBufferOpen; Client1.Socket.Write(t_out, SizeOf(HTTPRequest)); Client1.Socket.WriteBufferFlush; Client1.Socket.WriteBufferClose; Client1.Socket.CheckForDataOnSource(100); while Client1.Socket.InputBufferIsEmpty = true do Client1.Socket.CheckForDataOnSource(100); if Client1.Socket.InputBufferIsEmpty = false then begin while HTTPRequest.Command <> Form1.AnswerIsComming do begin Client1.Socket.CheckForDataOnSource(100); TriesToSend := TriesToSend + 1; if TriesToSend < 10 then begin ClusterClient.ChechClient; end else begin Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, 7); AnswerIsComming := 0; break; end; end; end; end else begin Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, 7); AnswerIsComming := 0; end; except on E: Exception do begin AnswerIsComming := 0; Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, 7); end; end; end; Суть в том, что после передачи на сервер команды я жду появления Form1.AnswerIsComming той команды, которую я послал. Пока ее нет, обращаюсь ClusterClient.ChechClient; Работает как-то не стабильно, то получаю ответ, то нет
  15. Так вот в этом как раз и вопрос, как мне заставить главный поток ждать ответа от сервера, если ответ приходит не в главном потоке?
  16. вот поэтому я и спрашивал. Созрел еще вопрос, ситуация такая, в главном потоке идет запрос на сервер и должна быть обработка ответа, которая приводит к определенным действиям, опять же в главном потоке. Но так как я вынес ответ сервера в поток, то в главном потоке я не вижу реакции. То есть было вот так FillHTTPRequest(0, 0, HTTP_GET_DEVICE_COUNT); if AnswerIsComming = HTTP_GET_DEVICE_COUNT then begin DeviceCount := HTTPAnswer.Data1; end; я делал запрос (FillHTTPRequest), и выдавал ответ (HTTPAnswer), а теперь у меня HTTPAnswer появляется в отдельном потоке. Могу ли я принудительно вызвать обработку потока Execute. То есть примерно вот так FillHTTPRequest(0, 0, HTTP_GET_DEVICE_COUNT); Thread.Execute; if AnswerIsComming = HTTP_GET_DEVICE_COUNT then begin DeviceCount := HTTPAnswer.Data1; end; Но метод Execute - приватный, я могу сделать дополнительный метод для обработки данных на клиенте и просто запускать его в Execute, или это не безопасно?
  17. А можно еще вопрос, у idTCPClient есть свойство Socket и IOHandler, у которых все свойства и методы идентичны. В чем разница между ними? Работает и так и так.
  18. Да, интересно. Но для начала сделаю класс потока и переведу все общение клиентов на него. Потом подумаю о синхронизации))
  19. Спасибо большое, очень полезный пример! Сам уже думал о собственном классе. А можно комментарий, я по коду не совсем понял 1. Метод Execute вызывается после создания экземпляра класса и живет, пока экземпляр не будет уничтожен, верно? 2. По методу Execute while not Terminated do begin sleep(10); if MainFrm.MessagingClient.Connected then begin len := 0; try if MainFrm.MessagingClient.IOHandler.CheckForDataOnSource(100) then begin len := MainFrm.MessagingClient.IOHandler.InputBuffer.Size; try MainFrm.MessagingClient.IOHandler.ReadBytes(Buf, len, false); GetMem(pBuf, len); Move(Buf[0], pBuf^, len); ProcessPacket(pBuf); finally SetLength(Buf, 0); end; end; except on E:EIdException do Synchronize(procedure begin MainFrm.MessagingClientDisconnected(nil); end); У Вас клиент MessagingClient лежит на основной форме MainFrm, и Вы обращаетесь к нему из потока, но без синхронизации, это нормально, так работает? Мне казалось, что любые обращения с элементами главного потока должны идти через синхронизацию. if MainFrm.MessagingClient.Connected then И при этом же при в исключении идет синхронизация. Почему так, там обновляются визуальные компоненты? on E:EIdException do Synchronize(procedure begin MainFrm.MessagingClientDisconnected(nil); end);
  20. Да, см пост от alexg. Но и в потоке тоже не работает, или я не правильно его применяю
  21. Подниму тему. Перехожу с 10.1 на 10.3. Реализован SplashScreeen по методу AlexG, только вместо потоков был банальный Application.ProcessMessages. В 10.3. это перестало работать, но и с потоками не могу совладать. procedure TSplashForm.FormShow(Sender: TObject); begin TThread.Synchronize(TThread.CurrentThread, procedure begin Application.CreateForm(TForm1, Form1); end); //Application.ProcessMessages; TThread.Synchronize(TThread.CurrentThread, procedure begin StartUpLabel.Text := 'Инициализация!!!'; Label1.Text := VERSION; end); end; Не показывает саму форму SplashForm, заставка висит до самого отображения MainForm. Что можно предпринять?
  22. подниму тему, может у кого есть идеи есть SplashScreen по SplashScreen.onShow код procedure TSplashForm.FormShow(Sender: TObject); begin Application.CreateForm(TForm1, Form1); StartUpLabel.Text := 'Инициализация!!!'; Label1.Text := VERSION; end; Соответственно я не только не вижу изменений, я вижу, что даже стиль из Stylebook, который лежит на Form1 не применяется. procedure TSplashForm.FormShow(Sender: TObject); begin Application.CreateForm(TForm1, Form1); Application.ProcessMessages; StartUpLabel.Text := 'Инициализация!!!'; Label1.Text := VERSION; Application.ProcessMessages; end; Вот так все прекрасно работает на 10.1 Соответственно вопрос, как это добро переделать под Андроид на 10.3
×
×
  • Создать...