
Опытный
 
Профиль
Группа: Участник
Сообщений: 393
Регистрация: 13.5.2010
Репутация: 2 Всего: 5
|
Доброго времени суток, уважаемые программеры. Сделал у себя в проге копирование (файлы немаленькие). Столкнулся с некоторыми проблемами, в частности отсутствие перерисовки главной формы при копировании. У меня на главной форме много визуальных компонентов, которые при наведении курсора на них должны перерисовываться. Читал про потоки ( http://forum.vingrad.ru/topic-60076.html ), пытался сделать, но ничего не получилось... Так как я в этом деле некомпетентен, то рассчитываю на Вашу помощь. Как было до "внедрения" потока: | Код | unit copyr;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, acPNG, eff_button, StdCtrls, ExtCtrls, PDirSelected, ComCtrls, Gauges, CommCtrl;
type TCopyForm = class(TForm) DestPathEdit: TEdit; DestPathChangeBtn: TButton; InfoLabel: TLabel; CancelBtn: TEffectButton; CopyBtn: TEffectButton; CopyBGImage: TImage; DirDialog: TDirDialog; ProgressLabel: TLabel; PercentLabel: TLabel; ProgressBar: TProgressBar; procedure DestPathChangeBtnClick(Sender: TObject); procedure CancelBtnClick(Sender: TObject); procedure CopyBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); private procedure WMNCHITTEST(var Msg: TMessage); message WM_NCHITTEST; { Private declarations } public { Public declarations } end;
var CopyForm: TCopyForm;
implementation
uses main;
{$R *.dfm}
procedure TCopyForm.DestPathChangeBtnClick(Sender: TObject); begin
// указать папку, куда будем копировать if DirDialog.Execute then begin DestPathEdit.Text:=DirDialog.DirPath; end;
end;
procedure TCopyForm.CancelBtnClick(Sender: TObject); begin
CopyForm.Hide; MainForm.Enabled:=true; copying:=false;
end;
function GetFileSize64(const FileName: String): Int64; var myFile: THandle; myFindData: TWin32FindData; begin // set default value Result := 0; // get the file handle. myFile := FindFirstFile(PChar(FileName), myFindData); if (myFile <> INVALID_HANDLE_VALUE) then begin Windows.FindClose(myFile); Int64Rec(Result).Lo := myFindData.nFileSizeLow; Int64Rec(Result).Hi := myFindData.nFileSizeHigh; end; end;
function Triade(source: string): string; var i,j: integer; temp: string; begin j:=1; temp:=''; result:=''; for i:=length(source) downto 1 do begin if j mod 3 = 0 then temp:=temp+source[i]+' ' else temp:=temp+source[i]; inc(j); end; for i:=length(temp) downto 1 do result:=result+temp[i]; end;
procedure CopyFile(const sSourceName, sDestinationName: String; ProgressControl: TProgressBar); const nChunkSize = 8192; var uCopyBuffer: Pointer; FSource, FDestination: Integer; nFileSize, nBytesCopied, nTotalCopied: Int64; sTotalCopied, sFileSize: string; begin
GetMem(uCopyBuffer, nChunkSize); try nFileSize := GetFileSize64(sSourceName); nTotalCopied := 0; FSource := FileOpen(sSourceName, fmShareDenyNone); try if (ProgressControl <> nil) then begin with ProgressControl do begin Max := Round(nFileSize/10); Min := 0; Position := 0; end; end; ForceDirectories(ExtractFilePath(sDestinationName)); FDestination := FileCreate(sDestinationName); try repeat Application.ProcessMessages; sTotalCopied:=Triade(inttostr(Round(nTotalCopied/1000))); sFileSize:=Triade(inttostr(Round(nFileSize/1000))); CopyForm.ProgressLabel.Caption:=sTotalCopied+' / '+sFileSize+' Kb'; CopyForm.PercentLabel.Caption:=inttostr(Round(nTotalCopied/nFileSize*100))+'%'; nBytesCopied := FileRead(FSource, uCopyBuffer^, nChunkSize); nTotalCopied := nTotalCopied + nBytesCopied; FileWrite(FDestination, uCopyBuffer^, nBytesCopied); if (ProgressControl <> nil) then ProgressControl.Position := Round(nTotalCopied/10); until (nBytesCopied < nChunkSize); FileSetDate(FDestination, FileGetDate(FSource)); finally FileClose(FDestination); end; finally FileClose(FSource); end; finally FreeMem(uCopyBuffer, nChunkSize); if (ProgressControl <> nil) then ProgressControl.Position := 0; end;
end;
procedure TCopyForm.CopyBtnClick(Sender: TObject); var i: integer; // счетчик цикла dest: string; // папка FreeBytesAvailableToCaller: TLargeInteger; FreeSize: TLargeInteger; TotalSize: TLargeInteger; dlgRes: integer; begin
// проверить существование папки dest:=DestPathEdit.Text; if not(DirectoryExists(dest)) then showmessage('Указанной папки не существует!') else begin // смещаем окно, отдаем фокус главному MainForm.Enabled:=true; CopyForm.Left:=5; CopyForm.Top:=5; MainForm.SetFocus; // прячем ненужные компоненты DestPathEdit.Hide; DestPathChangeBtn.Hide; CancelBtn.Hide; CopyBtn.Hide; PercentLabel.Show; ProgressLabel.Show; ProgressBar.Show; Progressbar.Brush.Color := clBlack; SendMessage( ProgressBar.Handle, PBM_SETBARCOLOR, 0, clBlue ); // копирование for i:=0 to copylist.Count-1 do begin // проверка свободного места GetDiskFreeSpaceEx(PAnsiChar(dest),FreeBytesAvailableToCaller,Totalsize,@FreeSize); if GetFileSize64(copylist.Strings[i]) >= FreeBytesAvailableToCaller then repeat // показывать мессагу пока не будет достаточно места или нажата кнопка отмены GetDiskFreeSpaceEx(PAnsiChar(dest),FreeBytesAvailableToCaller,Totalsize,@FreeSize); dlgres:=MessageBox(Application.Handle, 'Недостаточно места на диске!', 'CineFil', MB_RETRYCANCEL); if dlgres=idCancel then begin // отмена CancelBtnClick(Self); exit; end; until GetFileSize64(copylist.Strings[i]) <= FreeBytesAvailableToCaller; // копирование InfoLabel.Caption:='Копируется '+inttostr(i+1)+'-й из '+inttostr(copylist.Count)+' ('+ExtractFileName(copylist.Strings[i])+')'; CopyFile(copylist.Strings[i], dest+ExtractFileName(copylist.Strings[i]), ProgressBar); ProgressLabel.Caption:=''; PercentLabel.Caption:=''; end; // финиш CancelBtnClick(Self); end;
end;
procedure TCopyForm.FormCreate(Sender: TObject); begin
// разрешить таскать форму SetWindowLong(Handle, GWL_STYLE, GETWINDOWLONG(Handle, GWL_STYLE) and (not WS_CAPTION)); Height := ClientHeight;
end;
procedure TCopyForm.WMNCHITTEST(var Msg: TMessage); begin inherited; Msg.Result := HTCAPTION; end;
end.
|
Как я пытался сделать и не получил желаемого результата | Код | unit copyr;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, acPNG, eff_button, StdCtrls, ExtCtrls, PDirSelected, ComCtrls, Gauges, CommCtrl;
type TCopyForm = class(TForm) DestPathEdit: TEdit; DestPathChangeBtn: TButton; InfoLabel: TLabel; CancelBtn: TEffectButton; CopyBtn: TEffectButton; CopyBGImage: TImage; DirDialog: TDirDialog; ProgressLabel: TLabel; PercentLabel: TLabel; ProgressBar: TProgressBar; procedure DestPathChangeBtnClick(Sender: TObject); procedure CancelBtnClick(Sender: TObject); procedure CopyBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); private procedure WMNCHITTEST(var Msg: TMessage); message WM_NCHITTEST; { Private declarations } public { Public declarations } end;
type TCopyThread = class(TThread) private function GetFileSize64(const FileName: String): Int64; function Triade(source: string): string; procedure CopyFile(const sSourceName, sDestinationName: String; ProgressControl: TProgressBar); protected procedure DoCopy; procedure Execute; override; end;
var CopyForm: TCopyForm; CT: TCopyThread;
implementation
uses main;
{$R *.dfm}
procedure TCopyThread.Execute; begin
Synchronize(DoCopy); end;
procedure TCopyForm.DestPathChangeBtnClick(Sender: TObject); begin
// указать папку, куда будем копировать if DirDialog.Execute then begin DestPathEdit.Text:=DirDialog.DirPath; end;
end;
procedure TCopyForm.CancelBtnClick(Sender: TObject); begin
CopyForm.Hide; MainForm.Enabled:=true; copying:=false;
end;
function TCopyThread.GetFileSize64(const FileName: String): Int64; var myFile: THandle; myFindData: TWin32FindData; begin // set default value Result := 0; // get the file handle. myFile := FindFirstFile(PChar(FileName), myFindData); if (myFile <> INVALID_HANDLE_VALUE) then begin Windows.FindClose(myFile); Int64Rec(Result).Lo := myFindData.nFileSizeLow; Int64Rec(Result).Hi := myFindData.nFileSizeHigh; end; end;
function TCopyThread.Triade(source: string): string; var i,j: integer; temp: string; begin j:=1; temp:=''; result:=''; for i:=length(source) downto 1 do begin if j mod 3 = 0 then temp:=temp+source[i]+' ' else temp:=temp+source[i]; inc(j); end; for i:=length(temp) downto 1 do result:=result+temp[i]; end;
procedure TCopyThread.CopyFile(const sSourceName, sDestinationName: String; ProgressControl: TProgressBar); const nChunkSize = 8192; var uCopyBuffer: Pointer; FSource, FDestination: Integer; nFileSize, nBytesCopied, nTotalCopied: Int64; sTotalCopied, sFileSize: string; begin
GetMem(uCopyBuffer, nChunkSize); try nFileSize := GetFileSize64(sSourceName); nTotalCopied := 0; FSource := FileOpen(sSourceName, fmShareDenyNone); try if (ProgressControl <> nil) then begin with ProgressControl do begin Max := Round(nFileSize/10); Min := 0; Position := 0; end; end; ForceDirectories(ExtractFilePath(sDestinationName)); FDestination := FileCreate(sDestinationName); try repeat Application.ProcessMessages; sTotalCopied:=Triade(inttostr(Round(nTotalCopied/1000))); sFileSize:=Triade(inttostr(Round(nFileSize/1000))); CopyForm.ProgressLabel.Caption:=sTotalCopied+' / '+sFileSize+' Kb'; CopyForm.PercentLabel.Caption:=inttostr(Round(nTotalCopied/nFileSize*100))+'%'; nBytesCopied := FileRead(FSource, uCopyBuffer^, nChunkSize); nTotalCopied := nTotalCopied + nBytesCopied; FileWrite(FDestination, uCopyBuffer^, nBytesCopied); if (ProgressControl <> nil) then ProgressControl.Position := Round(nTotalCopied/10); until (nBytesCopied < nChunkSize); FileSetDate(FDestination, FileGetDate(FSource)); finally FileClose(FDestination); end; finally FileClose(FSource); end; finally FreeMem(uCopyBuffer, nChunkSize); if (ProgressControl <> nil) then ProgressControl.Position := 0; end;
end;
procedure TCopyThread.DoCopy; var i: integer; // счетчик цикла dest: string; // папка FreeBytesAvailableToCaller: TLargeInteger; FreeSize: TLargeInteger; TotalSize: TLargeInteger; dlgRes: integer; begin
// проверить существование папки dest:=CopyForm.DestPathEdit.Text; if not(DirectoryExists(dest)) then showmessage('Указанной папки не существует!') else begin // смещаем окно, отдаем фокус главному MainForm.Enabled:=true; CopyForm.Left:=5; CopyForm.Top:=5; MainForm.SetFocus; // прячем ненужные компоненты CopyForm.DestPathEdit.Hide; CopyForm.DestPathChangeBtn.Hide; CopyForm.CancelBtn.Hide; CopyForm.CopyBtn.Hide; CopyForm.PercentLabel.Show; CopyForm.ProgressLabel.Show; CopyForm.ProgressBar.Show; CopyForm.Progressbar.Brush.Color := clBlack; SendMessage( CopyForm.ProgressBar.Handle, PBM_SETBARCOLOR, 0, clBlue ); // копирование for i:=0 to copylist.Count-1 do begin // проверка свободного места GetDiskFreeSpaceEx(PAnsiChar(dest),FreeBytesAvailableToCaller,Totalsize,@FreeSize); if GetFileSize64(copylist.Strings[i]) >= FreeBytesAvailableToCaller then repeat // показывать мессагу пока не будет достаточно места или нажата кнопка отмены GetDiskFreeSpaceEx(PAnsiChar(dest),FreeBytesAvailableToCaller,Totalsize,@FreeSize); dlgres:=MessageBox(Application.Handle, 'Недостаточно места на диске!', 'CineFil', MB_RETRYCANCEL); if dlgres=idCancel then begin // отмена CopyForm.CancelBtnClick(Self); exit; end; until GetFileSize64(copylist.Strings[i]) <= FreeBytesAvailableToCaller; // копирование CopyForm.InfoLabel.Caption:='Копируется '+inttostr(i+1)+'-й из '+inttostr(copylist.Count)+' ('+ExtractFileName(copylist.Strings[i])+')'; // проверка, есть ли уже такой файл, предложение замены если есть if FileExists(dest+ExtractFileName(copylist.Strings[i])) then begin dlgres:=MessageBox(Application.Handle, 'Такой файл уже существует! Заменить?', 'CineFil', MB_YESNO); if dlgres=idYes then CopyFile(copylist.Strings[i], dest+ExtractFileName(copylist.Strings[i]), CopyForm.ProgressBar); end else CopyFile(copylist.Strings[i], dest+ExtractFileName(copylist.Strings[i]), CopyForm.ProgressBar); CopyForm.ProgressLabel.Caption:=''; CopyForm.PercentLabel.Caption:=''; end; // финиш CopyForm.CancelBtnClick(Self); end;
end;
procedure TCopyForm.CopyBtnClick(Sender: TObject); begin
// создаем поток CT:=TCopyThread.Create(false); CT.FreeOnTerminate:=true; CT.Priority:=tpHighest;
end;
procedure TCopyForm.FormCreate(Sender: TObject); begin
// разрешить таскать форму SetWindowLong(Handle, GWL_STYLE, GETWINDOWLONG(Handle, GWL_STYLE) and (not WS_CAPTION)); Height := ClientHeight;
end;
procedure TCopyForm.WMNCHITTEST(var Msg: TMessage); begin
inherited; Msg.Result := HTCAPTION; end;
end.
|
Желаемой перерисовки главной формы не достиг. Видимо, я в корне неверно организовал поток. Помогите загнать копирование в поток так, чтобы компоненты на главной форме адекватно реагировали на курсор мыши.
|