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


Автор: chikistbuch 28.6.2012, 22:05
Всем привет.

Пишу все в unit1.
Код

...
type
   TPotok = class(TThread)
    private
      filename: string;
      procedure loaddata;
     { Private declarations }
    protected
      procedure Execute; override;
end;

var
    potok: TPotok;


Код

procedure TPotok.Execute;
begin
   Synchronize(loaddata); // Вызов метода с синхронизацией
end;

procedure TForm1.ToolButton7Click(Sender: TObject);
begin
  form1.OpenDialog1.Filter:='Файлы Excel|*.xls; *.xlsx';
  if form1.OpenDialog1.Execute() then begin
    potok := TPotok.Create(true);// true - после создания класса поток автоматически запущен не будет
    potok.FreeOnTerminate := true;//после завершения кода потока он сразу завершится
    potok.filename := form1.Opendialog1.FileName;
    potok.Priority := tpNormal;//Устанавливаем приоритет
    potok.Resume;//Запускаем поток
  end;
end;


Процедура loaddata запускается и выполняется, а вот форма в это время висит. 
про потоки читал здесь: http://callipso.bestcode.org/delphi/artical/num2.html

Автор: Чучмек 28.6.2012, 22:15
loaddata с формой взаимодействует?
Наверняка, иначе зачем тогда Synchronize?
Вот Synchronize и блокирует основной поток, наверно.

Автор: chikistbuch 28.6.2012, 22:54
Код

procedure TPotok.loaddata;
var
  WorkBook, Sheet: Variant;
  i, j, kolKolonok, kolStrok:integer;
  sql, sql_1: string;
  maxID: array [1..2] of string;
  sqlArray: OLEVariant;
  bool:boolean;
begin

  try
    Excel := CreateOleObject('Excel.Application');//создаем что-то типа excel
  except
    MessageBox(Application.ActiveFormHandle, 'MS Excel не найден!'+#13#10+'Для работы программы необходимо установить MS Excel.', 'Внимание!', MB_ICONWARNING or MB_OK);
    exit;
  end;

  Excel.Application.EnableEvents := false;// Отключаем реакцию Excel на события, чтобы ускорить вывод информации
  Excel.DisplayAlerts:=False;//отключаем сообщения excel'я

  WorkBook := Excel.WorkBooks.Open(filename);//открываем файл
  PostMessage(form1.Handle, WM_CloseExcel, 0, 0);//закрываем excel после выполнения данной процедуры

  try
    Sheet := Workbook.Sheets.Item[1] //выбираем лист
  except
    MessageBox(Application.ActiveFormHandle, 'Ошибка!'+#13#10+'Файл MS Excel пуст или поврежден.', 'Внимание!', MB_ICONWARNING or MB_OK);
    exit;
  end;

  kolStrok:=Sheet.UsedRange.Rows.Count;
  kolKolonok:=Sheet.UsedRange.Columns.Count;
  sqlArray:=Sheet.UsedRange.Value; //прочитали все значения в массив

  StatusProgressBar.Position:=0;
  StatusProgressBar.Visible:=true;
  StatusProgressBar.Max:=kolStrok;

  for i := 1 to kolKolonok do begin //проверяем правильность названия колонок
    j:=0;
    bool:=false;//индикатор совпадения имени

    while (j<form4.CheckListBox1.Items.Count-1) AND (NOT bool) do begin
      if AnsiUpperCase(sqlArray[1,i])=AnsiUpperCase(form4.CheckListBox1.Items.Strings[j]) then begin //если название колонки совпадает с названием колонки в БД
        sqlArray[1,i]:=form1.getAS(sqlArray[1,i], 2);//записали название колонки familia
        bool:=true;
      end;
      j:=j+1;
    end;

    if not bool then begin //если совпадений в названии колонки не найдено
      MessageBox(Application.ActiveFormHandle, pChar('Ошибка! Неверное название '+inttostr(i)+' колонки: "'+string(sqlArray[1,i])+'".'), 'Внимание!', MB_ICONWARNING or MB_OK);
      exit;//прерываем выполнение кода
    end;
  end;

  if  MessageBox(Application.ActiveFormHandle, 'Загрузить данные из указанного файла?', 'Внимание!', MB_ICONWARNING or MB_YESNO) = IDNO then exit;//прерываем выполнение кода

  form1.UniQuery2.SQL.Text:='SELECT MAX(`id`) FROM spisok';//узнали макс id
  form1.UniQuery2.Execute;
  maxID[1]:=form1.UniQuery2.Fields.Fields[0].AsString;

  sql:='PREPARE excelInsert FROM "INSERT INTO `spisok` ('; //подготавливаем sql запрос на ввод данных

  for i:=1 to kolKolonok do begin
    sql:=sql+'`'+sqlArray[1,i]+'`, ';
    sql_1:=sql_1+'@'+sqlArray[1,i]+', ';//для EXECUTE
  end;
  delete(sql, length(sql)-1, 2);
  delete(sql_1, length(sql_1)-1, 2);//для EXECUTE
  sql:=sql+') VALUES (';

  for i:=1 to kolKolonok do begin
    sql:=sql+'?, ';
  end;
  delete(sql, length(sql)-1, 2);
  sql:=sql+')";';           //подготовили запрос на вставку

  for i := 2 to kolStrok do begin //так как первая строка содержит названия колонок
    if i mod 10 = 0 then StatusProgressBar.Position:=i;
    for j := 1 to kolKolonok do begin
      if string(sqlArray[i,j])='' then sql:=sql+'SET @'+string(sqlArray[1,j])+' = NULL;'//проверяем не пуста ли строка
        else sql:=sql+'SET @'+string(sqlArray[1,j])+' = "'+string(sqlArray[i,j])+'";';//формируем значения
    end;
  sql:=sql+'EXECUTE excelInsert USING '+sql_1+';';;
  end;

  StatusProgressBar.Position:=kolStrok;

  form1.UniQuery2.SQL.Text:=sql;
  form1.UniQuery2.Execute; //вставили все значения

  form1.UniQuery2.SQL.Text:='SELECT MAX(`id`) FROM spisok';//узнали макс id
  form1.UniQuery2.Execute;
  maxID[2]:=form1.UniQuery2.Fields.Fields[0].AsString;

  if maxID[1]='' then sql_1:='WHERE id < '+maxID[2] //условие запроса
    else sql_1:='WHERE id BETWEEN '+maxID[1]+' AND '+maxID[2];
  sql:='UPDATE spisok SET data_redaktirovania = "'+FormatDateTime('yyyy:mm:dd',Now())+'" '+sql_1;
  form1.UniQuery2.SQL.Text:=sql;
  form1.UniQuery2.Execute;

 А как сделать чтобы не блокировала?
Пускай sql сформирую в потоке

Код

procedure TPotok.createSQL;
var
  i, j, kolKolonok, kolStrok:integer;
  sql, sql_1: string;
  sqlArray: OLEVariant;
begin
  sql:='PREPARE excelInsert FROM "INSERT INTO `spisok` ('; //подготавливаем sql запрос на ввод данных

  for i:=1 to kolKolonok do begin
    sql:=sql+'`'+sqlArray[1,i]+'`, ';
    sql_1:=sql_1+'@'+sqlArray[1,i]+', ';//для EXECUTE
  end;
  delete(sql, length(sql)-1, 2);
  delete(sql_1, length(sql_1)-1, 2);//для EXECUTE
  sql:=sql+') VALUES (';

  for i:=1 to kolKolonok do begin
    sql:=sql+'?, ';
  end;
  delete(sql, length(sql)-1, 2);
  sql:=sql+')";';           //подготовили запрос на вставку

  for i := 2 to kolStrok do begin //так как первая строка содержит названия колонок
    if i mod 10 = 0 then StatusProgressBar.Position:=i;
    for j := 1 to kolKolonok do begin
      if string(sqlArray[i,j])='' then sql:=sql+'SET @'+string(sqlArray[1,j])+' = NULL;'//проверяем не пуста ли строка
        else sql:=sql+'SET @'+string(sqlArray[1,j])+' = "'+string(sqlArray[i,j])+'";';//формируем значения
    end;
  sql:=sql+'EXECUTE excelInsert USING '+sql_1+';';;
  end;

  StatusProgressBar.Position:=kolStrok;
end;

а как обратно передать значение sql в loaddata и дождаться выполнение TPotok.createSQL, а то пишет что SQL пуст

Автор: ZBugz 29.6.2012, 08:18
Попробуй повтыкать Application.ProcessMessages();

Автор: Чучмек 29.6.2012, 09:55
Посмотри в чем разница
Код

type tmt1=class(tthread)
 procedure m;
 procedure execute;override;
end;


{ tmt1 }
procedure tmt1.execute;
begin
  inherited;
  Synchronize(m);
end;

procedure tmt1.m;
var
 i:integer;
begin
for i:=0 to 99 do
 begin
 form1.Caption:=inttostr(i);
 sleep(100);
 end;
end;



Код

type tmt2=class(tthread )
 s:string;
 procedure m;
 procedure execute;override;
end;

{ tmt2 }

procedure tmt2.execute;
var
 i:integer;
begin
  inherited;
for i:=0 to 99 do
 begin
 s:=inttostr(i);
 Synchronize(m);
 sleep(100);
 end;
end;

procedure tmt2.m;
begin
form1.Caption:=s;
end;



Автор: MetalFan 29.6.2012, 14:00
Цитата(Чучмек @  29.6.2012,  09:55 Найти цитируемый пост)
Посмотри в чем разница

Верно подметил.

Использовать поток только для того, чтобы в нем сразу вызвать Synchronize - бессмысленно.

Автор: northener 29.6.2012, 14:09
Цитата(Чучмек @  28.6.2012,  22:15 Найти цитируемый пост)
Вот Synchronize и блокирует основной поток, наверно. 

Синхронайз ничего не блокирует. Но все что выполняется внутри Synchronize выполняется в основном потоке.

Автор: MetalFan 29.6.2012, 16:49
Цитата(northener @  29.6.2012,  14:09 Найти цитируемый пост)
Синхронайз ничего не блокирует.

Ну здрасти?! а как он тогда работает? Блокируется поток, вызвавший Synchronize, затем когда доходит дело до выполнения кода процедуры, отданной в Synchronize, основной поток занимается ее выполнением... соотв.ничего более в осн.потоке не работает., после того, как код процедуры отрабатывает в основном потоке, доп.поток продолжает работу. Ну и осн.поток продолжает заниматься своими делами.

Автор: northener 29.6.2012, 17:09
Цитата(MetalFan @  29.6.2012,  16:49 Найти цитируемый пост)
Ну здрасти?!

Ну собственно я отвечал на 
Цитата(Чучмек @  28.6.2012,  22:15 Найти цитируемый пост)
Вот Synchronize и блокирует основной поток, наверно. 


Автор: northener 30.6.2012, 01:02
Ну и вдогонку.
Цитата(MetalFan @  29.6.2012,  16:49 Найти цитируемый пост)
Блокируется поток, вызвавший Synchronize

Ну не "блокируется" этот поток! Он продолжает выполняться в соответствии со своим кодом. Но войдя в Synchronize код этого потока выполняется не в нём самом, а в основном потоке приложения.

Автор: XperT 30.6.2012, 13:39
Цитата(northener @ 30.6.2012,  01:02)
Ну и вдогонку.
Цитата(MetalFan @  29.6.2012,  16:49 Найти цитируемый пост)
Блокируется поток, вызвавший Synchronize

Ну не "блокируется" этот поток! Он продолжает выполняться в соответствии со своим кодом. Но войдя в Synchronize код этого потока выполняется не в нём самом, а в основном потоке приложения.

Как раз таки нет: поток переходит в состояние suspend, а управление передаётся основному потоку. Когда нужная функция отработает в основном потоке, вызывающий поток опять получает процессорное время и продолжает свою работу.

Автор: northener 1.7.2012, 00:46
Цитата(MetalFan @  29.6.2012,  16:49 Найти цитируемый пост)
Ну здрасти?!

Цитата(XperT @  30.6.2012,  13:39 Найти цитируемый пост)
Как раз таки нет

Это уже похоже на спор о терминологии. Говорим одно и то же, но предпочитаем использовать разные термины. 
smile


Автор: XperT 1.7.2012, 10:06
Говорим совсем о разном. Попробую объяснить по другому:
При вызове Synchronize, вызывающий поток переходит в состояние suspend, т.е. ему перестает выделятся процессорное время, т.е. он блокируется. 
По вашем описанию похоже, что вы думаете, что на момент выполнения Synchronize этот поток на время становится главным или что-то в этом роде, так как у меня нету предположений как он может не блокироваться и в этот же момент не выполнятся.


Автор: chikistbuch 1.7.2012, 13:05
нихера не получается  smile 

Автор: Чучмек 1.7.2012, 14:23
1 Преременную Excel  в TPotok
2 Основную часть кода из loaddata в Execute 
3 Что такое StatusProgressBar?  ProgressBar на форме?
добавь в TPotok переменные 
   ProgressBar и UniQuery.
 до запуска потока выполни:
Код

potok.ProgressBar:=StatusProgressBar ;
potok.UniQuery:=form1.UniQuery2; 

Добавь в TPotok  также переменные:
   ProgressBarPosition
   ProgressBarVisible
   ProgressBarMax
Все обращения к
   form1.UniQuery2
  StatusProgressBar.Position
  StatusProgressBar.Visible
  StatusProgressBar.Max 
 замени на обращения к
  UniQuery
   ProgressBarPosition
   ProgressBarVisible
   ProgressBarMax
с form4.CheckListBox1 - аналогично: В TPotok  переменную типа tstringlist, в которую, до запуска потока, копируешь содержимое form4.CheckListBox1.Items
в tpotok добавляешь процедуру
Код

procedure tpotok.XXX;
 begin
  StatusProgressBar.Position:=ProgressBarPosition;
  StatusProgressBar.Visible:=ProgressBarVisible;
  StatusProgressBar.Max:= ProgressBarMax;
 end;
  
Везде где нужно обновить вид StatusProgressBar  вызываешь  Synchronize(XXX);
4 MessageBox(Application.ActiveFormHandle,... замени, для начала, на MessageBox(0,...
5 Надеюсь UniQuery потокозащищенный компонент.
P.S. UniQuery  для каждого потока свой
P.P.S В TPotok  переопредели конструктор, в который будешь сразу передавать form1.Opendialog1.FileName;StatusProgressBar;form1.UniQuery2;form4.CheckListBox1.Items

Добавлено через 12 минут и 3 секунды
Цитата(chikistbuch @  28.6.2012,  22:54 Найти цитируемый пост)
form1.getAS
 этого тоже не должно быть в потоке.
 

Автор: Чучмек 1.7.2012, 15:11
И еще. Знаешь, не знаешь ...
Прежде чем вызвать в потоке CreateOleObject необходимо вызвать coinitialize.

Код

procedure Txxx.execute;
 begin
 coinitialize(nil);
 ...
 Excel := CreateOleObject('Excel.Application');
 ...
 excel.quit;
 ...
 couninitialize;
 end;

Автор: Чучмек 1.7.2012, 20:18
Еще...
В твоем случае можно вообще обойтись без  Synchronize.
В TPotok объяви переменную hProgressBar:Cardinal (в место ProgressBar), в которую, при инициализации потока, сохраняй StatusProgressBar.Handle
В потоке можешь смело использовать
  
Код

SetWindowPos(hProgressBar, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW); 
вместо 
Код

StatusProgressBar.visible:=true;


Код

SetWindowPos(hProgressBar, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW);
 вместо 
Код

StatusProgressBar.visible:=false;



Код

PostMessage(hProgressBar, PBM_SETRANGE32, Mix, Max);
 вместо 
Код

StatusProgressBar.Min:=Min;
StatusProgressBar.Max:=Max;


Код

PostMessage(hProgressBar, PBM_SETPOS, position,0);
 вместо 
Код

StatusProgressBar.Position:=position;


Константы из CommCtrl
Код

const
 PBM_SETPOS              = WM_USER+2;
 PBM_SETRANGE32          = WM_USER+6;



Автор: chikistbuch 1.7.2012, 20:32
Охренеть. Чучмек, спасибо конечно, но ....
Оставлю этот вопрос на потом. Еще раз спасибо!!!

Автор: chikistbuch 1.7.2012, 21:21
Всё таки решил попробовать, пишет ошибку:
Код

[DCC Error] Unit1.pas(251): E2003 Undeclared identifier: 'coinitialize'


Код

procedure TPotok.Execute;
var
  WorkBook, Sheet: Variant;
  i, j, kolKolonok, kolStrok:integer;
  sql, sql_1: string;
  maxID: array [1..2] of string;
  sqlArray: OLEVariant;
  bool:boolean;
begin
  coinitialize(nil);
  try
    Excel := CreateOleObject('Excel.Application');//создаем что-то типа excel
  except
    MessageBox(Application.ActiveFormHandle, 'MS Excel не найден!'+#13#10+'Для работы программы необходимо установить MS Excel.', 'Внимание!', MB_ICONWARNING or MB_OK);
    exit;
  end;

  Excel.Application.Enab

Автор: Чучмек 1.7.2012, 21:46
Пропиши в uses activex

Автор: Чучмек 1.7.2012, 22:08
Опять же...
Цитата(chikistbuch @  1.7.2012,  21:21 Найти цитируемый пост)
MessageBox(Application.ActiveFormHandle, 

В execute не должно быть ничего типа Application.xxx... и Form1.xxx...  - такое только через Synchronize.
Переменную Excel  объяви в Execute. В execute  Excel и закроешь.

Автор: chikistbuch 1.7.2012, 22:27
Цитата(Чучмек @ 1.7.2012,  22:08)
Опять же...
Цитата(chikistbuch @  1.7.2012,  21:21 Найти цитируемый пост)
MessageBox(Application.ActiveFormHandle, 

В execute не должно быть ничего типа Application.xxx... и Form1.xxx...  - такое только через Synchronize.
Переменную Excel  объяви в Execute. В execute  Excel и закроешь.

))) а  оно все равно работает ))))))

Добавлено @ 22:32
Намудрил, сам не знаю что, но работает ))))))) (все в одном unit'е):
Код

type
   TPotok = class(TThread)
    private
      hProgressBar:Cardinal;
      list: TStrings;
      filename: string;
      Excel: OleVariant;
      ProgressBar: TProgressBar;
      UniQuery: TUniQuery;
      procedure loaddata;
     { Private declarations }
    protected
      procedure Execute; override;
end;

var
  potok: TPotok;


Код

procedure TPotok.Execute;
var
  WorkBook, Sheet: Variant;
  i, j, kolKolonok, kolStrok:integer;
  sql, sql_1: string;
  maxID: array [1..2] of string;
  sqlArray: OLEVariant;
  bool:boolean;
begin
  coinitialize(nil);
  try
    Excel := CreateOleObject('Excel.Application');//создаем что-то типа excel
  except
    MessageBox(0, 'MS Excel не найден!'+#13#10+'Для работы программы необходимо установить MS Excel.', 'Внимание!', MB_ICONWARNING or MB_OK);
    exit;
  end;

  Excel.Application.EnableEvents := false;// Отключаем реакцию Excel на события, чтобы ускорить вывод информации
  Excel.DisplayAlerts:=False;//отключаем сообщения excel'я

  WorkBook := Excel.WorkBooks.Open(filename);//открываем файл
  PostMessage(0, WM_CloseExcel, 0, 0);//закрываем excel после выполнения данной процедуры

  try
    Sheet := Workbook.Sheets.Item[1] //выбираем лист
  except
    MessageBox(Application.ActiveFormHandle, 'Ошибка!'+#13#10+'Файл MS Excel пуст или поврежден.', 'Внимание!', MB_ICONWARNING or MB_OK);
    exit;
  end;

  kolStrok:=Sheet.UsedRange.Rows.Count;
  kolKolonok:=Sheet.UsedRange.Columns.Count;
  sqlArray:=Sheet.UsedRange.Value; //прочитали все значения в массив

  for i := 1 to kolKolonok do begin //проверяем правильность названия колонок
    j:=0;
    bool:=false;//индикатор совпадения имени

    while (j<list.Count-1) AND (NOT bool) do begin
      if AnsiUpperCase(sqlArray[1,i])=AnsiUpperCase(list.Strings[j]) then begin //если название колонки совпадает с названием колонки в БД
        sqlArray[1,i]:=form1.getAS(sqlArray[1,i], 2);//записали название колонки familia
        bool:=true;
      end;
      j:=j+1;
    end;

    if not bool then begin //если совпадений в названии колонки не найдено
      MessageBox(Application.ActiveFormHandle, pChar('Ошибка! Неверное название '+inttostr(i)+' колонки: "'+string(sqlArray[1,i])+'".'), 'Внимание!', MB_ICONWARNING or MB_OK);
      exit;//прерываем выполнение кода
    end;
  end;

  if  MessageBox(0, 'Загрузить данные из указанного файла?', 'Внимание!', MB_ICONWARNING or MB_YESNO) = IDNO then exit;//прерываем выполнение кода

  ProgressBar.Position:=0;
  ProgressBar.Visible:=true;
  ProgressBar.Max:=kolStrok+round(0.2*kolStrok);


  UniQuery.SQL.Text:='SELECT MAX(`id`) FROM spisok';//узнали макс id
  UniQuery.Execute;
  maxID[1]:=UniQuery.Fields.Fields[0].AsString;

    sql:='PREPARE excelInsert FROM "INSERT INTO `spisok` ('; //подготавливаем sql запрос на ввод данных

  for i:=1 to kolKolonok do begin
    sql:=sql+'`'+sqlArray[1,i]+'`, ';
    sql_1:=sql_1+'@'+sqlArray[1,i]+', ';//для EXECUTE
  end;
  delete(sql, length(sql)-1, 2);
  delete(sql_1, length(sql_1)-1, 2);//для EXECUTE
  sql:=sql+') VALUES (';

  for i:=1 to kolKolonok do begin
    sql:=sql+'?, ';
  end;
  delete(sql, length(sql)-1, 2);
  sql:=sql+')";';           //подготовили запрос на вставку

  for i := 2 to kolStrok do begin //так как первая строка содержит названия колонок
    if i mod 10 = 0 then ProgressBar.Position:=i;
    for j := 1 to kolKolonok do begin
      if string(sqlArray[i,j])='' then sql:=sql+'SET @'+string(sqlArray[1,j])+' = NULL;'//проверяем не пуста ли строка
        else sql:=sql+'SET @'+string(sqlArray[1,j])+' = "'+string(sqlArray[i,j])+'";';//формируем значения
    end;
  sql:=sql+'EXECUTE excelInsert USING '+sql_1+';';;
  end;

  UniQuery.SQL.Text:=sql;
  UniQuery.Execute; //вставили все значения


  UniQuery.SQL.Text:='SELECT MAX(`id`) FROM spisok';//узнали макс id
  UniQuery.Execute;
  maxID[2]:=inttostr(form1.UniQuery2.Fields.Fields[0].AsInteger+1);

  if maxID[1]='' then sql_1:='WHERE id < '+maxID[2] //формируем условие запроса
    else sql_1:='WHERE id BETWEEN '+maxID[1]+' AND '+maxID[2];
  sql:='UPDATE spisok SET data_redaktirovania = "'+FormatDateTime('yyyy:mm:dd',Now())+'" '+sql_1;//выставляем дату редактирования записи
  UniQuery.SQL.Text:=sql;
  UniQuery.Execute;

  ProgressBar.Position:=ProgressBar.Max;

  kolStrok:=kolStrok-1; //так как 1 строка - название колонок
  sql_1:=inttostr(kolStrok)[length(inttostr(kolStrok))];//формируем сообщение
  sql:='Загрузка данных выполнена успешно!'+#13#10+'Загружен';

  if (sql_1='1') and (kolStrok<>11) then sql:=sql+'а'
    else sql:=sql+'о';

  sql:=sql+' '+inttostr(kolStrok);
  if (kolStrok>10) and (kolStrok<21) or (sql_1='0') or (sql_1='5') or (sql_1='6') or (sql_1='7') or (sql_1='8') or (sql_1='9') then sql:=sql+' записей.'
    else if sql_1='1' then sql:=sql+' запись.'
      else sql:=sql+' записи.';

  MessageBox(0, PWideChar(sql), 'Внимание!', MB_ICONWARNING or MB_OK);

  ProgressBar.Visible:=false;

  Excel.Quit;  //якобы мы нажимаем на крестик в excel
  Excel:=unassigned;  //походу это нужно писать в паре с Quit (перевод - неназначенный)

  Synchronize(loaddata); // Вызов метода с синхронизацией
  couninitialize;
end;

procedure TPotok.loaddata();
begin
  getDB();
end;

procedure TForm1.ToolButton7Click(Sender: TObject);
begin
  form1.OpenDialog1.Filter:='Файлы Excel|*.xls; *.xlsx';
  if form1.OpenDialog1.Execute() then begin
    potok := TPotok.Create(true);// true - после создания класса поток автоматически запущен не будет
    potok.FreeOnTerminate := true;//после завершения кода потока он сразу завершится
    potok.ProgressBar:=StatusProgressBar;
    potok.UniQuery:=form1.UniQuery2;
    potok.hProgressBar:=StatusProgressBar.Handle;
    potok.filename := form1.Opendialog1.FileName;
    potok.list:=form4.CheckListBox1.Items;
    potok.Priority := tpNormal;//Устанавливаем приоритет
    potok.Resume;//Запускаем поток
  end;
end;

Автор: Чучмек 1.7.2012, 23:05
22:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
PostMessage(0, WM_CloseExcel, 0, 0);//закрываем excel после выполнения данной процедуры

Это что? Откуда и зачем? 

27:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
 MessageBox(Application.ActiveFormHandle, 


48:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
MessageBox(Application.ActiveFormHandle,


55-57:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
  ProgressBar.Position:=0;
  ProgressBar.Visible:=true;
  ProgressBar.Max:=kolStrok+round(0.2*kolStrok);

Опять-двадцать пять - или через Synchronize или через PostMessage
81:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
 if i mod 10 = 0 then ProgressBar.Position:=i;

Тудаже

95:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
  maxID[2]:=inttostr(form1.UniQuery2.Fields.Fields[0].AsInteger+1);
 Внимательней

103:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
  ProgressBar.Position:=ProgressBar.Max;

119:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
  ProgressBar.Visible:=false;


130:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
  getDB();
 Что это такое и почему через Synchronize

139,141:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
    potok.ProgressBar:=StatusProgressBar;
potok.hProgressBar:=StatusProgressBar.Handle;
 Либо то либо другое, определись ( ProgressBar+Synchronize или hProgressBar + PostMessage)

143:
Цитата(chikistbuch @  1.7.2012,  22:27 Найти цитируемый пост)
potok.list:=form4.CheckListBox1.Items;
 Так не пойдет
Код

potok.list:=TstringList.Create;
potok.list.text:=form4.CheckListBox1.Items.text;


Автор: chikistbuch 1.7.2012, 23:14
Цитата(Чучмек @  1.7.2012,  23:05 Найти цитируемый пост)
Либо то либо другое, определись ( ProgressBar+Synchronize или hProgressBar + PostMessage)

Дык, вроде бы и так работает. И не post и не Synchronize. Может потому что XE2

getDB(); - это процедура в которой формируется запрос на вывод данных из БД в DBGrid

Автор: Чучмек 1.7.2012, 23:20
Цитата(chikistbuch @  1.7.2012,  23:14 Найти цитируемый пост)
Дык, вроде бы и так работает. И не post и не Synchronize. Может потому что XE2

Работает до  поры до времени.
Одна ветка ЖД и два поезда  - без диспетчера рано или поздно поезда столкнутся.

Автор: chikistbuch 1.7.2012, 23:46
Код

type
   TPotok = class(TThread)
    private
      hProgressBar:Cardinal;
      list: TStringList;
      filename: string;
      UniQuery: TUniQuery;
      procedure loaddata;
     { Private declarations }
    protected
      procedure Execute; override;
end;

const
  PBM_SETPOS = WM_USER+2;
  PBM_SETRANGE32 = WM_USER+6;

var
  potok: TPotok;


Код

procedure TPotok.Execute;
var
  Excel: OleVariant;
  WorkBook, Sheet: Variant;
  i, j, kolKolonok, kolStrok:integer;
  sql, sql_1: string;
  maxID: array [1..2] of string;
  sqlArray: OLEVariant;
  bool:boolean;
begin
  coinitialize(nil);
  try
    Excel := CreateOleObject('Excel.Application');//создаем что-то типа excel
  except
    MessageBox(0, 'MS Excel не найден!'+#13#10+'Для работы программы необходимо установить MS Excel.', 'Внимание!', MB_ICONWARNING or MB_OK);
    exit;
  end;

  Excel.Application.EnableEvents := false;// Отключаем реакцию Excel на события, чтобы ускорить вывод информации
  Excel.DisplayAlerts:=False;//отключаем сообщения excel'я

  WorkBook := Excel.WorkBooks.Open(filename);//открываем файл

  try
    Sheet := Workbook.Sheets.Item[1] //выбираем лист
  except
    MessageBox(0, 'Ошибка!'+#13#10+'Файл MS Excel пуст или поврежден.', 'Внимание!', MB_ICONWARNING or MB_OK);
    exit;
  end;

  kolStrok:=Sheet.UsedRange.Rows.Count;
  kolKolonok:=Sheet.UsedRange.Columns.Count;
  sqlArray:=Sheet.UsedRange.Value; //прочитали все значения в массив

  for i := 1 to kolKolonok do begin //проверяем правильность названия колонок
    j:=0;
    bool:=false;//индикатор совпадения имени

    while (j<list.Count-1) AND (NOT bool) do begin
      if AnsiUpperCase(sqlArray[1,i])=AnsiUpperCase(list.Strings[j]) then begin //если название колонки совпадает с названием колонки в БД
        sqlArray[1,i]:=form1.getAS(sqlArray[1,i], 2);//записали название колонки familia
        bool:=true;
      end;
      j:=j+1;
    end;

    if not bool then begin //если совпадений в названии колонки не найдено
      MessageBox(0, pChar('Ошибка! Неверное название '+inttostr(i)+' колонки: "'+string(sqlArray[1,i])+'".'), 'Внимание!', MB_ICONWARNING or MB_OK);
      exit;//прерываем выполнение кода
    end;
  end;

  if  MessageBox(0, 'Загрузить данные из указанного файла?', 'Внимание!', MB_ICONWARNING or MB_YESNO) = IDNO then exit;//прерываем выполнение кода

  PostMessage(hProgressBar, PBM_SETPOS, 0,0);// Position:=0;
  SetWindowPos(hProgressBar, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW); // Visible:=true;
  PostMessage(hProgressBar, PBM_SETRANGE32, 0, kolStrok+round(0.2*kolStrok)); // min max


  UniQuery.SQL.Text:='SELECT MAX(`id`) FROM spisok';//узнали макс id
  UniQuery.Execute;
  maxID[1]:=UniQuery.Fields.Fields[0].AsString;

    sql:='PREPARE excelInsert FROM "INSERT INTO `spisok` ('; //подготавливаем sql запрос на ввод данных

  for i:=1 to kolKolonok do begin
    sql:=sql+'`'+sqlArray[1,i]+'`, ';
    sql_1:=sql_1+'@'+sqlArray[1,i]+', ';//для EXECUTE
  end;
  delete(sql, length(sql)-1, 2);
  delete(sql_1, length(sql_1)-1, 2);//для EXECUTE
  sql:=sql+') VALUES (';

  for i:=1 to kolKolonok do begin
    sql:=sql+'?, ';
  end;
  delete(sql, length(sql)-1, 2);
  sql:=sql+')";';           //подготовили запрос на вставку

  for i := 2 to kolStrok do begin //так как первая строка содержит названия колонок
    if i mod 10 = 0 then PostMessage(hProgressBar, PBM_SETPOS, i,0);// Position:=i;
    for j := 1 to kolKolonok do begin
      if string(sqlArray[i,j])='' then sql:=sql+'SET @'+string(sqlArray[1,j])+' = NULL;'//проверяем не пуста ли строка
        else sql:=sql+'SET @'+string(sqlArray[1,j])+' = "'+string(sqlArray[i,j])+'";';//формируем значения
    end;
  sql:=sql+'EXECUTE excelInsert USING '+sql_1+';';;
  end;

  UniQuery.SQL.Text:=sql;
  UniQuery.Execute; //вставили все значения


  UniQuery.SQL.Text:='SELECT MAX(`id`) FROM spisok';//узнали макс id
  UniQuery.Execute;
  maxID[2]:=inttostr(UniQuery.Fields.Fields[0].AsInteger+1);

  if maxID[1]='' then sql_1:='WHERE id < '+maxID[2] //формируем условие запроса
    else sql_1:='WHERE id BETWEEN '+maxID[1]+' AND '+maxID[2];
  sql:='UPDATE spisok SET data_redaktirovania = "'+FormatDateTime('yyyy:mm:dd',Now())+'" '+sql_1;//выставляем дату редактирования записи
  UniQuery.SQL.Text:=sql;
  UniQuery.Execute;

  PostMessage(hProgressBar, PBM_SETPOS, kolStrok+round(0.2*kolStrok),0);// Position:=0;

  kolStrok:=kolStrok-1; //так как 1 строка - название колонок
  sql_1:=inttostr(kolStrok)[length(inttostr(kolStrok))];//формируем сообщение
  sql:='Загрузка данных выполнена успешно!'+#13#10+'Загружен';

  if (sql_1='1') and (kolStrok<>11) then sql:=sql+'а'
    else sql:=sql+'о';

  sql:=sql+' '+inttostr(kolStrok);
  if (kolStrok>10) and (kolStrok<21) or (sql_1='0') or (sql_1='5') or (sql_1='6') or (sql_1='7') or (sql_1='8') or (sql_1='9') then sql:=sql+' записей.'
    else if sql_1='1' then sql:=sql+' запись.'
      else sql:=sql+' записи.';

  MessageBox(0, PWideChar(sql), 'Внимание!', MB_ICONWARNING or MB_OK);

  SetWindowPos(hProgressBar, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW);// Visible:=false;

  Excel.Quit;  //якобы мы нажимаем на крестик в excel
  Excel:=unassigned;  //походу это нужно писать в паре с Quit (перевод - неназначенный)

  Synchronize(form1.ToolButton1.Click); //хер его знает что (в ToolButton1.Click -> getDB();)
  couninitialize;
end;

procedure TForm1.ToolButton7Click(Sender: TObject);
begin
  form1.OpenDialog1.Filter:='Файлы Excel|*.xls; *.xlsx';
  if form1.OpenDialog1.Execute() then begin
    potok := TPotok.Create(true);// true - после создания класса поток автоматически запущен не будет
    potok.FreeOnTerminate := true;//после завершения кода потока он сразу завершится
    potok.UniQuery:=form1.UniQuery2;
    potok.hProgressBar:=StatusProgressBar.Handle;
    potok.filename := form1.Opendialog1.FileName;

    potok.list:=TstringList.Create;
    potok.list.text:=form4.CheckListBox1.Items.text;

    potok.Priority := tpNormal;//Устанавливаем приоритет
    potok.Resume;//Запускаем поток
  end;
end;


Как-то так

Автор: Чучмек 2.7.2012, 00:23
Ну почти.
Цитата(chikistbuch @  1.7.2012,  23:46 Найти цитируемый пост)
sqlArray[1,i]:=form1.getAS(sqlArray[1,i], 2);//записали название колонки familia

В execute не должно быть обращений к чему либо за пределами класса. Либо копируешь содержимое в переменную класса, либо используешь Synchronize.

UniQuery - исключение, компоненты для работы с БД, обычно, потокозащищенные. Но, все равно, нужно(лучше) использовать для каждого потока свой.

Код

type
   TUniQuery=tobject;

   TPotok = class(TThread)
    private
      hProgressBar:Cardinal;
      list: TStringList;
      filename: string;
      UniQuery: TUniQuery;
      procedure loaddata;
     { Private declarations }
    protected
      procedure Execute; override;
    public
      constructor Create(CreateSuspended: Boolean;ProgressBarHandle:cardinal;
        CheckList:TStringList;DataFileName:string;QueryComponent:TUniQuery);
    end;


constructor TPotok.Create(CreateSuspended: Boolean;
  ProgressBarHandle: cardinal; CheckList: TStringList;
  DataFileName: string; QueryComponent: TUniQuery);
begin
 hProgressBar:=ProgressBarHandle;
 List:=TStringList.Create;
 List.Text:=CheckList.Text;
 filename:=DataFileName;
 UniQuery:=QueryComponent;
 inherited Create(CreateSuspended);
end;


...
...
potok := TPotok.Create(true,StatusProgressBar.Handle,form4.CheckListBox1.Items,form1.Opendialog1.FileName,form1.UniQuery2);
potok.FreeOnTerminate := true;
potok.Priority := tpNormal;
potok.Resume;


  

Автор: northener 2.7.2012, 00:29
Цитата(XperT @  1.7.2012,  10:06 Найти цитируемый пост)
Говорим совсем о разном. Попробую объяснить по другому:
При вызове Synchronize, вызывающий поток переходит в состояние suspend, т.е. ему перестает выделятся процессорное время, т.е. он блокируется. 

Тем не менее разговор об одном и том же.  Но давайте перестанем спорить(почти оффтопить) в чужом топике. smile

Автор: chikistbuch 2.7.2012, 00:30
Спасибо, Чучмек, ты мозг!!!
Просто интересно: где ты работаешь и какая зарплата (заработок)???

Автор: northener 2.7.2012, 00:31
Цитата(Чучмек @  1.7.2012,  23:20 Найти цитируемый пост)
Работает до  поры до времени.

+1
А точнее - если в данный момент работает, то это невезение!

Автор: Чучмек 2.7.2012, 00:33
Цитата(chikistbuch @  2.7.2012,  00:30 Найти цитируемый пост)
интересно: где ты работаешь 

На хим. заводе мастером. Про зарплату лучше не спрашивай.

Автор: chikistbuch 2.7.2012, 00:36
а я в МЧС Беларуси ))))

Автор: MetalFan 2.7.2012, 07:23
Цитата(Чучмек @  1.7.2012,  20:18 Найти цитируемый пост)
В потоке можешь смело использовать
  
Выделить всёкод Pascal/Delphi
1:
    
SetWindowPos(hProgressBar, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW); 
вместо 
Выделить всёкод Pascal/Delphi
1:
    
StatusProgressBar.visible:=true;


Вредный совет, имхо. Без острой необходимости и четкого представления внутренностей VCL-обертки компонента я бы так делать не порекомендовал.
Где гарантия, что у TProgressBar не "сорвет голову" от таких манипуляций?

Модератор: Флуд не по теме заканчиваем, если очень хочется, то это можно обсудить в других разделах или личке  smile 

Добавлено @ 07:25
Цитата(northener @  2.7.2012,  00:29 Найти цитируемый пост)
Но давайте перестанем спорить(почти оффтопить) в чужом топике. 

Почему же оффтопить? Просто не стоит говорить разными терминами "об одном и том же", а то новичка только запутаем.
В http://forum.vingrad.ru/index.php?showtopic=353795&view=findpost&p=2501395 я описал механизм работы Synchronize простыми словами.
А http://forum.vingrad.ru/forum/topic-60076.html (см. Глава 3. Основы синхронизации. Решение для Delphi: TThread.Synchronize.) этот механизм описан более полно, да еще и с картинками.

Автор: Чучмек 2.7.2012, 09:43
Цитата(MetalFan @  2.7.2012,  07:23 Найти цитируемый пост)
Вредный совет, имхо. Без острой необходимости и четкого представления внутренностей VCL-обертки компонента я бы так делать не порекомендовал.
Где гарантия, что у TProgressBar не "сорвет голову" от таких манипуляций?

Да ничего страшного не будет. Просто не желательно, после этого, использовать такой компонент обычным способом. Будет только несоответствие нескольких внутренних переменных TProgressBar.
Самое большое, это FVisible. - желательно восстановить исходную видимость. 
Можно написать потомка с добавлением реакции на какое-нибудь сообщение,и через это сообщение передавать изменение состояния, тогда точно никаких проблем не будет.

Автор: northener 3.7.2012, 01:21
Цитата(MetalFan @  2.7.2012,  07:23 Найти цитируемый пост)
Просто не стоит говорить разными терминами "об одном и том же", а то новичка только запутаем.

В моём понимании это и есть оффтопить. Точнее "устраивать терминологический спор" вокруг простого вопроса новичка. Именно этим спором мы только ему только помешаем. 
А как вы предполагаете "не говорить разными терминами "об одном и том же""?
Это же не азбука и даже не арифметика. Вы изучали данную тему по одной книге/статье и т.п. Я по другой. smile
P.S. Когда я с этим знакомился, не было не только перевода Бориса, но и не было самой той книги.

Автор: MetalFan 3.7.2012, 13:03
Цитата(northener @  3.7.2012,  01:21 Найти цитируемый пост)
Вы изучали данную тему по одной книге/статье и т.п. Я по другой.
Неважно, по какой книге и что мы изучали...
Утверждение 
Цитата(northener @  29.6.2012,  14:09 Найти цитируемый пост)
Синхронайз ничего не блокирует.

неверно - это факт.

Автор: northener 4.7.2012, 00:10
Цитата(MetalFan @  3.7.2012,  13:03 Найти цитируемый пост)
Неважно, по какой книге и что мы изучали...
Утверждение 
Цитата(northener @  29.6.2012,  14:09 Найти цитируемый пост)
Синхронайз ничего не блокирует.

неверно - это факт.

Дабы не допустить холивар в тематической ветке соглашусь, что я был не прав в степени категоричности данного своего утверждения.
Приношу всем свои извинения за это. 

P.S.
Если на Винграде есть специальное место для холиваров и если кто-то захочет продолжить этот спор, то только скажите где и когда. smile

Автор: chikistbuch 4.7.2012, 07:26
Цитата(northener @  4.7.2012,  00:10 Найти цитируемый пост)
Если на Винграде есть специальное место для холиваров и если кто-то захочет продолжить этот спор, то только скажите где и когда. 

)))))))))))))))  smile 

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