joynter |
Отправлено: 04.11.2004, 14:21 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 137
|
моя прога копирует файлы и при этом на форме нельзя нажать какую-либо кнопку, передвинуть саму форму и тд.
как от этого можно избавится? |
|
Doga |
Отправлено: 04.11.2004, 14:32 |
|
Мастер участка
Группа: Участник
Сообщений: 575
|
Либо создать отдельный поток (TThread), либо использовать ProcessMessages()
|
|
joynter |
Отправлено: 04.11.2004, 15:20 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 137
|
спасибо за подсказку, но с Application->ProcessMessages()
все равно есть некоторые тормоза во время копирования.
Не могли бы уважаемые господа программисты
просветить меня на тему:
а что есть TThread ( у меня в хелпе вылезло link not found) и как его использовать? |
|
Doga |
Отправлено: 04.11.2004, 16:31 |
|
Мастер участка
Группа: Участник
Сообщений: 575
|
QUOTE |
TThread is an abstract class that enables creation of separate threads of execution in an application.
Unit
Classes
Description
Create a descendant of TThread to represent an execution thread in a multi-threaded application. Each new instance of a TThread descendant is a new thread of execution. Multiple instances of a TThread derived class make a C++Builder application multi-threaded.
When an application is run, it is loaded into memory ready for execution. At this point it becomes a process containing one or more threads that contain the data, code and other system resources for the program. A thread executes one part of an application and is allocated CPU time by the operating system. All threads of a process share the same address space and can access the process’s global variables.
Use threads to improve application performance by
Managing input from several communication devices.
Distinguishing among tasks of varying priority. For example, a high priority thread handles time critical tasks, and a low priority thread performs other tasks.
Following are issues and recommendations to be aware of when using threads:
Keeping track of too many threads consumes CPU time; the recommended limit is 16 active threads per process on single processor systems.
When multiple threads update the same resources, they must be synchronized to avoid conflicts.
Most methods that access a VCL object and update a form must only be called from within the main VCL thread or use a synchronization object such as TMultiReadExclusiveWriteSynchronizer.
To create and use a new thread object:
Choose File | New | Other | Thread Object to create a new unit that contains an object derived from the TThread class.
Define the new thread object’s constructor.
Define the thread object’s Execute method by inserting the code that should execute when the thread is executed.
Note: See the Threads demo for multi-threading program samples.
Warning: Exceptions that are raised but not caught in the TThread descendant’s Execute method may cause access violations when you run the application outside of the IDE. You can guard against this access violation by providing the Execute method with a try.._finally block that includes the body of that method. |
Если Help не находит ключевое слово "TThread" — значит у Вас неполный хелп . Где его найти — см. тему "Полный английский Хелп". Примеры как с ним (TThread) работать есть в каталоге $(BCB)\Examples
А ещё можно здесь посмотреть:
https://rxlib.ru/forums/index.php?ac...c77fc54ef2fc148
https://rxlib.ru/forums/index.php?ac...c77fc54ef2fc148
Или сами можете поискать побольше...
Отредактировано Doga — 04/11/2004, 17:49
|
|
joynter |
Отправлено: 04.11.2004, 18:32 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 137
|
извините за назойливость, но не могли бы Вы меня поправить:
к своему приложению я присовокупил такой Тhread Object
Unit1.cpp
CODE |
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "VCDUnit1.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall ThreadCopyDir::UpdateCaption()
// {
// Form1->Caption = "Updated in a thread";
// }
//---------------------------------------------------------------------------
__fastcall ThreadCopyDir::ThreadCopyDir(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//---------------------------------------------------------------------------
void __fastcall ThreadCopyDir::Execute()
{
//---- Place thread code here ----
Synchronize(newStream(sFrom,sTo));
}
//---------------------------------------------------------------------------
void __fastcall ThreadCopyDir::newStream(AnsiString dirFrom, AnsiString dirTo)
{
dirFrom += "\";
dirTo += "\";
TSearchRec sr;
if(!FindFirst(dirFrom + "*.*",faAnyFile | faDirectory, sr));
do
{
if((sr.Name != ".")&&(sr.Name != ".."))
if((sr.Attr&faDirectory) || (sr.Attr == faDirectory))
{
if(!CreateDir(dirTo + sr.Name))
ShowMessage("Не могу создать директорию " + dirTo + sr.Name);
newStream(dirFrom + sr.Name,dirTo + sr.Name);
}
else
{
if(!CopyFile((dirFrom + sr.Name).c_str(),(dirTo + sr.Name).c_str(),0))
ShowMessage("Не могу скопировать " + dirTo + sr.Name);
else
Form1->ListBox2->Items->Add(dirTo + sr.Name);
//Application->ProcessMessages();
}
}
while(!FindNext(sr));
FindClose(sr);
}
|
Unit1.h
CODE |
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
//---------------------------------------------------------------------------
class ThreadCopyDir : public TThread
{
private:
void __fastcall newStream(AnsiString sFrom, AnsiString sTo);
protected:
void __fastcall Execute();
public:
__fastcall ThreadCopyDir(bool CreateSuspended);
AnsiString sFrom,sTo;
};
//---------------------------------------------------------------------------
#endif
|
в файле VCDUniy1.cpp вызов происходит так
CODE |
...
#include "VCDUnit1.h"
#include "Unit1.h"
...
String sFrom = ComboBox1->Text,
sTo = diskFullName;
//CopyDir(sFrom,sTo);
ThreadCopyDir *newProcess = new ThreadCopyDir(true);
|
но при компиляции появляются такие ошибки:
CODE |
[C++ Error] Unit1.cpp(32): E2468 Value of type void is not allowed
[C++ Error] Unit1.cpp(32): E2342 Type mismatch in parameter 'Method' (wanted 'void (_fastcall * (_closure )())()', got 'void')
|
что я делаю не так?
Отредактировано joynter — 05/11/2004, 10:52 |
|
Doga |
Отправлено: 04.11.2004, 19:23 |
|
Мастер участка
Группа: Участник
Сообщений: 575
|
Параметром метода Synchronize может быть только метод типа:
void __fastcall ThreadCopyDir::newStream(void)
Данные необходимые для метода newStream следует передавать через члены класса ThreadCopyDir. Т.е. AnsiString sFrom и AnsiString sTo должны быть обьявлены в этом классе, а инициализировать их можно например в конструкторе ThreadCopyDir.
Вызов для вашего случая должен выглядеть так:
Synchronize(newStream);
Вобще Synchronize можно и не использовать, если поток работает втихую и ничего на экран не выводит
Еще мне кажется что вы изобретаете очередной велосипед (заранее извиняюсь, если это не так ) В WinAPI есть универсальная процедура для таких случаев :
SHFileOperation
Позволяет перемещать(и переименовывать), копировать, удалять любые файлы и каталоги независимо от их раположения (т.е. по списку). При этом она уже работает отдельным процессом, и также позволяет визуализировать этот процесс на экране (анимированные иконки , прогрессбар и тд)
Надо только её правильно настроить
Если не разберётесь — могу выложить примерчики
Есть ещё в библиотеке RXLib есть функция CopyFile. с подключением
в качестве индикатора копирования TGauge или TProgressBar
procedure CopyFile(const FileName, DestName: string; ProgressControl: TControl);
Тут на форуме эта тема (про копирование, удаление...) поднималась много раз — можете Сами поискать ежели что...
Удачи
|
|
joynter |
Отправлено: 05.11.2004, 10:25 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 137
|
спасибо. со многопоточностью я разобрался. конечно удобнее пользоваться РХ-компонентами, но мне хотелось все-таки узнать как оно работает. а по поводу SHFileOperation — это первое, что я пробовал, но там есть одна неувязочка — удалять директории можно, а копировать не получается, тк pFrom должен быть файлом, а pTo — директорией (по крайней мере так в хелпе).
|
|
pagan |
Отправлено: 05.11.2004, 12:15 |
|
Ученик-кочегар
Группа: Участник
Сообщений: 22
|
QUOTE | void __fastcall ThreadCopyDir::Execute()
{
//---- Place thread code here ----
Synchronize(newStream(sFrom,sTo));
}
//--------------------------------------------------------------------------- |
Честно говоря в методе Execute() как раз таки должен содержаться код, который будет выполняться потоком. Метод Syncronize же синхронизирует ваш поток с основным. Т.е как такового потока здесь у вас не получается. |
|
Gedeon |
Отправлено: 05.11.2004, 12:31 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
QUOTE (joynter @ 05/11/2004, 11:27) | а по поводу SHFileOperation — это первое, что я пробовал, но там есть одна неувязочка — удалять директории можно, а копировать не получается, тк pFrom должен быть файлом, а pTo — директорией (по крайней мере так в хелпе). |
Вот Вам пример
CODE |
bool CopyDir(const char *From, const char *To, bool ShowErrorOnFail)
{
char *IFrom; //строка пути должна заканчиваться
IFrom = (char*)malloc(lstrlen(From)+2); //двумя нулями, что и делается в
strcpy(IFrom,From); //первых четырех строках т.е.
IFrom[lstrlen(IFrom)+1]='\0'; //добавляется еще 1 '\0'
char *ITo; //строка пути должна заканчиваться
ITo = (char*)malloc(lstrlen(To)+2); //двумя нулями, что и делается в
strcpy(ITo,To); //первых четырех строках т.е.
ITo[lstrlen(ITo)+1]='\0'; //добавляется еще 1 '\0'
if(!IsDir(To)){ //если папка назначения не
SECURITY_ATTRIBUTES sa; //существует, создаем ее
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = false;
CreateDirectory(To,&sa);
}
SHFILEOPSTRUCT strFileOp; //заполняем параметры структуры
strFileOp.hwnd = NULL;
strFileOp.wFunc = FO_COPY;
strFileOp.pFrom = IFrom;
strFileOp.pTo = ITo;
if(!ShowErrorOnFail) strFileOp.fFlags = FOF_NOCONFIRMATION|FOF_NOERRORUI;
else strFileOp.fFlags = FOF_NOCONFIRMATION;
if(!SHFileOperation(&strFileOp)) return false;
free(IFrom);
free(ITo);
return true;
}
//----------------------------------------------------------------------------
|
IsDir — моя функция для проверки существования папки.
Можете вместо входных char* использовать AnsiString тогда попроще будет.
|
|
joynter |
Отправлено: 05.11.2004, 13:44 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 137
|
спасибо за пример.
теперь другой естественный вопрос вскакивает:
если имеется многопоточное приложение, то как запретить юзеру его закрыть во время выполнения вторичного потока? |
|
Doga |
Отправлено: 05.11.2004, 14:23 |
|
Мастер участка
Группа: Участник
Сообщений: 575
|
Я думаю что вопрос поставлен некорректно.
Что если юзер хочет закрыть приложение по причине нежелания дальнейшей работы вторичного потока? Т.е. он просто желает завершить работу вторичного потока?
Не стоит запрещать пользователю делать то что он хочет. Ему это не понравится. Однозначно
Но если без этого нельзя — проблема решается написанием обработчика события OnCloseQuery
|
|