执行长时间运行的导出任务时如何获得响应式UI(表单)?

美好的一天人们。 首先,我不是以英语为母语的人,我可能会遇到一些语法错误。

我需要一些已经完成了一些东西或者应用程序的人的build议,好的,那就是我使用了delphiforms的TProgressBar,另外一个名为“TExcelApplication”的组件和一个TDBGrid。

当我导出DBGrid的内容时,应用程序“冻结”,所以我基本上把这个ProgressBar放到用户看到进程完成了多less。 我已经意识到,当TDBGrid检索每个行并将其导出到新的Excel工作簿时,您无法移动实际的表单,因此您必须等到该过程完成后才移动该表单。

那么,是否有可能做一些事情(我想过关于线程,但我不确定是否可以帮助),所以用户可以移动窗口,如果他想要的话?

非常感谢你花时间阅读并给我一个build议。 我正在使用Delphi XE。

以下是我用来导出行的代码:

with ZQDetalles do begin First; while not EOF do begin i := i + 1; workSheet.Cells.Item[i,2] := DBGridDetalles.Fields[0].AsString; workSheet.Cells.Item[i,3] := DBGridDetalles.Fields[1].AsString; workSheet.Cells.Item[i,4] := DBGridDetalles.Fields[2].AsString; workSheet.Cells.Item[i,5] := DBGridDetalles.Fields[3].AsString; workSheet.Cells.Item[i,6] := DBGridDetalles.Fields[4].AsString; workSheet.Cells.Item[i,7] := DBGridDetalles.Fields[5].AsString; workSheet.Cells.Item[i,8] := DBGridDetalles.Fields[6].AsString; workSheet.Cells.Item[i,9] := DBGridDetalles.Fields[7].AsString; Next; barraProgreso.StepIt; end; end; 

如果您想查看“导出”button的整个代码,请随时查看此链接: http : //pastebin.com/FFWAPdey

每当你在一个GUI应用程序中花费大量时间的东西,你想把它放在一个单独的线程,所以用户仍然可以操作该表单。 你可以这样声明一个简单的线程:

 TWorkingThread = class(TThread) protected procedure Execute; override; procedure UpdateGui; procedure TerminateNotify(Sender: TObject); end; procedure TWorkingThread.Execute; begin // do whatever you want to do // make sure to use synchronize whenever you want to update gui: Synchronize(UpdateGui); end; procedure TWorkingThread.UpdateGui; begin // eg updating the progress bar end; procedure TWorkingThread.TerminateNotify(Sender: TObject); begin // this gets executed when the work is done // usually you want to give some kind of feedback to the user end; // ... // calling the thread: procedure TSettingsForm.Button1Click(Sender: TObject); var WorkingThread: TWorkingThread; begin WorkingThread := TWorkingThread.Create(true); WorkingThread.OnTerminate := TerminateNotify; WorkingThread.FreeOnTerminate := true; WorkingThread.Start; end; 

这很简单,记得当你想更新一个线程中的可视化元素的时候总是使用Synchronize。 通常情况下,您还要注意,用户无法再次调用线程,因为他现在仍然可以使用GUI。

如果行数很less(你知道有多less),你可以使用不同的variables数组更快地(并且一次)传输数据,如下所示:

 var xls, wb, Range: OLEVariant; arrData: Variant; RowCount, ColCount, i, j: Integer; Bookmark: TBookmark; begin // Create variant array where we'll copy our data // Note that getting RowCount can be slow on large datasets; if // that's the case, it's better to do a separate query first to // ask for COUNT(*) of rows matching your WHERE clause, and use // that instead; then run the query that returns the actual rows, // and use them in the loop itself RowCount := DataSet1.RecordCount; ColCount := DataSet1.FieldCount; arrData := VarArrayCreate([1, RowCount, 1, ColCount], varVariant); // Disconnect from visual controls DataSet1.DisableControls; try // Save starting row so we can come back to it after Bookmark := DataSet1.GetBookmark; try {fill array} i := 1; while not DataSet1.Eof do begin for j := 1 to ColCount do arrData[i, j] := DataSet1.Fields[j-1, i-1].Value; DataSet1.Next; Inc(i); // If we have a lot of rows, we can allow the UI to // refresh every so often (here every 100 rows) if (i mod 100) = 0 then Application.ProcessMessages; end; finally // Reset record pointer to start, and clean up DataSet1.GotoBookmark; DataSet1.FreeBookmark; finally // Reconnect GUI controls DataSet1.EnableControls; end; // Initialize an instance of Excel - if you have one // already, of course the next couple of lines aren't // needed xls := CreateOLEObject('Excel.Application'); // Create workbook - again, not needed if you have it. // Just use ActiveWorkbook instead wb := xls.Workbooks.Add; // Retrieve the range where data must be placed. Again, your // own WorkSheet and start of range instead of using 1,1 when // needed. Range := wb.WorkSheets[1].Range[wb.WorkSheets[1].Cells[1, 1], wb.WorkSheets[1].Cells[RowCount, ColCount]]; // Copy data from allocated variant array to Excel in single shot Range.Value := arrData; // Show Excel with our data} xls.Visible := True; end; 

它仍然需要花费相同的时间循环遍历数据的行和列,但实际上将数据传输到Excel所花费的时间大大减less,特别是在数据量很大的情况下。

Interesting Posts