Шаг 7 - Прием файлов Drag'n'Drop [DragAcceptFiles, DragQueryFile]

Хорошо известный и уже довольно поднадоевший прием открытия файлов - через перетаскивание в целевое окно. Для приложения неплохо бы его иметь. В общем, здесь главное делают функции WinAPI под названием DragAcceptFiles() и DragQueryFile(). Функция DragAcceptFiles() сообщает Windows, что окно готово к приему файлов. Его (обращение к функции) обычно засовывают в самый старт программы - в FormCreate(). Впрочем, всяк ищет место по-разному. А DragQueryFile() выдает информацию о поднятых (то есть кинутых) файлах.

Вообще-то здесь есть один узкий момент - чтобы можно было отреагировать на это событие Windows придется сделать таблицу откликов MESSAGE_MAP в стиле Visual C++ или OWL. Но выхода другого нет. Опять немного теории: таблица откликов включается в описание класса. При возникновении какого-либо события, Windows передает управление процедуре-обработчику события. В принципе, для тех, кто программировал под DOS, это должно напоминать таблицу векторов прерываний для BIOS. В таблице указывается имя процедуры, тип события, которое она обрабатывает и тип сообщения, передаваемое обработчику. Общий синтаксис таблицы будет подробно рассмотрен в следующих шагах, а именно для этого примера нужно сделать вот что.

В секцию private класса TMainForm нужно вставить описание функции-обработчика, функции-диспетчера и таблицу откликов:

private:
	void __fastcall CreateMDIChild(const String Name,bool img);
	void __fastcall WmDropFiles(TWMDropFiles& Message);
	void __fastcall ReadFile(AnsiString FileName);
public:
	virtual __fastcall TMainForm(TComponent *Owner);
	BEGIN_MESSAGE_MAP
		MESSAGE_HANDLER(WM_DROPFILES,TWMDropFiles,WmDropFiles)
	END_MESSAGE_MAP(TForm);

Диспетчер ReadFile() нужен, чтобы два раза код не писать. Вообще-то вид у него громоздкий, зато от фильтра диалога не зависит. Вот изменения в главном файле:

#include <dir.h>

__fastcall TMainForm::TMainForm(TComponent *Owner)
	: TForm(Owner)
{
	DragAcceptFiles(Handle,true);
}

void __fastcall TMainForm::WmDropFiles(TWMDropFiles& Message)
{
	HDROP drop_handle=(HDROP)Message.Drop;
	char fName[MAXPATH];
	int filenum=DragQueryFile(drop_handle,-1,NULL,NULL);
	for (int i=0;i<filenum;i++)
	{
		DragQueryFile(drop_handle,i,fName,MAXPATH);
		ReadFile(fName);
	};
	DragFinish(drop_handle);
};

void __fastcall TMainForm::ReadFile(AnsiString FileName)
{
	String str=ExtractFileExt(FileName);
	if((str==".avi")||(str==".wav")||(str==".mid")||(str==".mov"))
	{
		MediaPlayer1->FileName=FileName;
		MediaPlayer1->Open();
		MediaPlayer1->Play();
	}
	else
	if((str==".bmp")||(str==".ico")||(str==".wmf"))
		CreateMDIChild(FileName,true);
	else
		CreateMDIChild(FileName,false);
};

void __fastcall TMainForm::FileOpen1Execute(TObject *Sender)
{
	if (OpenDialog->Execute())
		ReadFile(OpenDialog->FileName);
}

Тут, по-моему, легко разобраться. Обратите внимание, как сократился код FileOpen1Execute() - вот что создатель языка Алгол называл структурным программированием! Функцию DragAcceptFiles() я поместил в объектный конструктор, что допустимо, хотя все-таки лучше использовать FormCreate() (если забыли, для автосоздания этого метода достаточно два раза щелкнуть кнопкой по форме). Параметр Handle - свойство, отражающее "window handle", как же это по-русски будет, что-то вроде объектного указателя на windowed control. Второй параметр - разрешить или запретить бросание файлов. Еще о DragQueryFile(). Message.Drop - это handle для параметров, переданных Windows. Он указывается в качестве первого аргумента. Если второй параметр unsigned int равен 0xFFFFFFFF или -1 (что проще записать), то функция возвращает число файлов, иначе имя соответствующее номеру файла. В первом случае два вторых параметра NULL, во втором строка как char str[n] и размер массива (unsigned int). MAXPATH - наибольший размер имени файла, определен в файле <dir.h>. DragFinish() - освобождает ресурсы.

Функция ExtractFileExt() возвращает расширение файла из пути к файлу (легче сделать, чем сказать). Например, для "C:\Мои документы\super.jpg" результат будет ".jpg".

Вот вроде бы и все. Как-нибудь надо будет еще рассмотреть String [AnsiString], но я Шаг с ним случайно стер, так что в следующий раз.


Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Аванесов Самвел - 29.10.2001