Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Потоки в визуальном компоненте


Автор: CHERRY 5.12.2013, 11:59
В разработке компонент «файловая панель» типа панель двухпанельного файлового менеджера. Для отображения файловой системы использую  TvirtualStringTree. 
Код

//Класс сканирования сети
  TNetScanThread = class(TThread)
  private
…...................... 
  protected
    procedure Execute; override;
    procedure Scan(Res: TNetResource; Root: boolean);
    procedure AddElement;
    procedure Stop;
  end;  

//Класс файловая панель
  TFm = class(TWinControl)
  private
    { Private declarations }
    VST:TVirtualStringTree;   
    Thread :TnetScanThread;
….......................
  End;


Захотел добавить сканирование сети на предмет сетевого окружения. Создаем поток   
Thread :=TnetScanThread.Create(false), 
результат сканирования для отображения передается в процедуру  AddElement
Код

procedure TNetScanThread.AddElement;
Var
  Data: PFMItem;
begin
  VST.FullExpand();
 …..........
End;


И вот здесь засада. Из класса  TnetScanThread нет доступа к  VST и другим экземплярам класса Tfm. В тестовом примере я писал Form1.VST.FullExpand(); А как поступить в компоненте? Выбился из сил.


Автор: Агрох 5.12.2013, 12:21
Form1.Экземпляр_класса_TFm.VST.FullExpand();

Автор: kami 5.12.2013, 12:22
Я бы сделал классу потока событие.
Это событие вызывал бы в основном потоке (хотя бы через syncronize).
А форма пусть после создания потока присвоит обработчик события и... делает там что захочет.

Добавлено через 1 минуту и 10 секунд
На всякий случай - напомню, что из потока обращаться к визуальным компонентам чревато боком, именно поэтому придумали всякие синхронайзы и т.п.

Автор: Akella 5.12.2013, 12:38
я бы в класс потока передавал ссылку на VST и с помощью  syncronize работал бы с VTS

Код

type
  TYrlThread = class(TThread)
  private
...
  procedure UpdateImage;

  public
...
....
    property ImageInProcess: TcxImage read fImageInProcess write fImageInProcess;
...
end;

...
...

      while not Terminated do
      begin
        Synchronize(UpdateImage);



...
...


procedure TYrlThread.UpdateImage;
begin
  if Assigned(fImageInProcess) then
    чегой-то делаем с fImageInProcess;
end;


Автор: CHERRY 5.12.2013, 12:42
Так формы нету! В тестовой программе с формой нет проблем.
Класс потока выглядит так:
Код

  TNetScanThread = class(TThread)
  private
    TreeNetWrk: PVirtualNode;
    TreeDomain: PVirtualNode;
    TreeServer: PVirtualNode;
    TreeShares: PVirtualNode;
    Param_dwType: Byte;
    Param_dwDisplayType: Byte;
    Param_lpRemoteName: String;
    Param_lpIP: String;
    StopScan:Boolean;
  protected
    procedure Execute; override;
    procedure Scan(Res: TNetResource; Root: boolean);
    procedure AddElement;
    procedure Stop;
  end;

Процедура Scan(Res: TNetResource; Root: boolean); сканирует сеть и через
Synchronize(AddElement); выводит результат.
Пробовал два варианта.
1. Без потока - программа замирает при сканировании сети, но работает.
2. Посылать результат из Scan(Res: TNetResource; Root: boolean) вместо Synchronize(AddElement)
в TList, а в главном классе в цикле или по таймеру проверять TList на предмет данных и выводить в VST.
Но как-то не кошерно. Вроде как и потока никаго нет.

Автор: kami 5.12.2013, 15:21
Не надо, чтобы поток чего-то там знал о форме/дереве и т.п. Он должен передать необходимую и достаточную информацию тому, кто знает о форме/дереве и в состоянии что-либо с ними и с информацией от потока сделать.

Автор: CHERRY 6.12.2013, 13:36
Поток оформил в виде класса в отдельном файле. Данные передаются через TList.
В принимающей программе в цикле
Код

  n1:=0;
  while not Thread.Stopped do
  Begin
     sleep(500);
    //Выводим найденные данные частями
    n2:=Thread.fNetScanInfo.Count;
     DisplayNetScanResult(n1,n2);
    n1:=Thread.fNetScanInfo.Count;
  End;

проверяем состояние потока и выводим данные частями, по мере заполнения списка.
Рабочий проект прилагается (может кому сгодится). Буду рад советам.
Спасибо за внимание.

Автор: kami 6.12.2013, 14:40
Цитата(CHERRY @  6.12.2013,  13:36 Найти цитируемый пост)
В принимающей программе в цикле

В чем тогда отличие от сканирования в основном потоке, если хоть так, хоть эдак "принимающая программа" висит в цикле, пока поток не отработает?

Автор: CHERRY 6.12.2013, 23:02
Цитата(kami @  6.12.2013,  11:40 Найти цитируемый пост)
В чем тогда отличие от сканирования в основном потоке,


Программа более свободна и управляема. Результат сканирования можно проверять реже  раз в 2-3 сек или не проверять совсем. Закончился поток - получили результат. Но как узнать, что поток закончился не проверяя регулярно какие-либо данные? 

Автор: Akella 7.12.2013, 11:49
Поток по окончании работы может оповестить кого-то/чего-то. Способов предостаточно. Смотря кого/что оповещать.

Автор: CHERRY 7.12.2013, 17:24
Цитата(Akella @  7.12.2013,  08:49 Найти цитируемый пост)
Поток по окончании работы может оповестить кого-то/чего-то.

Да, можно выбросить сообщение об окончании, написать в статусбаре, выполнить процедуру и т.д. 
Просто в моем случае ожидать окончания потока скучно (у меня на работе 20 раб.станций+2 сервера). Сканирование может занимать некоторое время, особенно если часть машин недавно покинули сеть, поэтому последовательный вывод результатов приятнее бесконечного прогрессбара.=)

Всем спасибо.

Автор: kami 7.12.2013, 19:41
Цитата(CHERRY @  6.12.2013,  23:02 Найти цитируемый пост)
Программа более свободна и управляема.

Ну да, Sleep(500), конечно, неизмеримо повышает свободу и управляемость основного потока.

Автор: Akella 9.12.2013, 12:35
Так в чем проблема в рамках той же самой synhronize заполнять список из потока?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)