Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Drag and Drop файлов на форму/компоненту

16K
10 сентября 2007 года
AntidotE
45 / / 26.09.2006
Привет. Думаю, данный код можно добавить в ЧаВо...

В дебрях сети нарыл код принятия списка файлов формой при drag&drop'е. После этого ещё почитал, и ещё, порассматривал его и хочу предложить некий "шаблон" для добавления в проект.

Код:
добавляем в [Unit1.h] в секции несколько строчек
class TForm1 : public TForm
{
private:    // User declarations
    void virtual __fastcall WMDropFiles(TWMDropFiles &message);
public:     // User declarations
    BEGIN_MESSAGE_MAP
        MESSAGE_HANDLER(WM_DROPFILES,TWMDropFiles,WMDropFiles)
    END_MESSAGE_MAP(TForm);
};

[Unit1.cpp]
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    DragAcceptFiles(Form1->Handle, true);
//вместо Form1 может быть любой компонент, например, ListBox или Memo, тогда файлы будут дропаться только над этим компонентом
//это я выяснил как раз во время написания данного поста, который изначально был вопросом, как это делать :)
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WMDropFiles(TWMDropFiles &message)
{
    int filecount, length, i;
    filecount = DragQueryFile ((HDROP) message.Drop, 0xFFFFFFFF/*-1*/, NULL, 0); //получаем количество файлов
    //подробнее о параметрах и возвращаемых значениях DragQueryFile можно узнать тут или в хелпе Билдера
    AnsiString filename;
    for (i = 0; i < filecount; ++i)  {
        filename.SetLength(MAX_PATH);
        length = DragQueryFile((HDROP)message.Drop, i, filename.c_str(), filename.Length());
        filename.SetLength(length);
        //тут можно с файлами творить что угодно, например, имена добавить в StringList или открывать по очереди в Memo
    }
    DragFinish ((HDROP) message.Drop);
}
//---------------------------------------------------------------------------


Комментируйте. Поправляйте...
И, кстати, назрел вопрос, который я ещё не рассматривал...
Если у меня 2 компонента, которые требуют разных вариантов принятия файлов... например, ЛистБокс, который добавляет в себя имена файлов, и Мемо, которое подгружает текст файла, на неё сброшенного... Как организовать разделение труда?
246
10 сентября 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: AntidotE
Привет. Думаю, данный код можно добавить в ЧаВо...
В дебрях сети нарыл код принятия списка файлов формой при drag&drop'е. После этого ещё почитал, и ещё,


тут читал?

16K
10 сентября 2007 года
AntidotE
45 / / 26.09.2006
почитал... ничего конкретного по теме... или мне показалось?
16K
10 сентября 2007 года
AntidotE
45 / / 26.09.2006
попробовал принимать всей формой, и в функции приёма дропа проверять координаты...
Код:
void __fastcall TForm1::WMDropFiles(TWMDropFiles &message)
{
        bool overlistbox = false, overmemo = false;
    int filecount, length, i = 0;
    AnsiString filename;
        LPPOINT p;
        GetCursorPos(p);
        if (p->x >= Form1->Left + ListBox1->Left &&
            p->x <= Form1->Left + ListBox1->Left + ListBox1->Width &&
            p->y >= Form1->Top + ListBox1->Top &&
            p->y <= Form1->Top + ListBox1->Top + ListBox1->Height)
                overlistbox = true;
       
        if (p->x >= Form1->Left + Memo1->Left &&
            p->x <= Form1->Left + Memo1->Left + Memo1->Width &&
            p->y >= Form1->Top + Memo1->Top &&
            p->y <= Form1->Top + Memo1->Top + Memo1->Height)
                overmemo = true;

        if (overlistbox) {
            filecount = DragQueryFile ((HDROP) message.Drop, 0xFFFFFFFF, NULL, 0);
            for (i = 0; i < filecount; ++i)  {
                filename.SetLength(MAX_PATH);
                length = DragQueryFile((HDROP)message.Drop, i, filename.c_str(), filename.Length());
                filename.SetLength(length);
                ListBox1->Items->Add(filename);
            }
        }
        if (overmemo) {
            filename.SetLength(MAX_PATH);
            length = DragQueryFile((HDROP)message.Drop, i, filename.c_str(), filename.Length());
            filename.SetLength(length);
                //тут может быть проверка например на валидность файла
                Memo1->Lines->LoadFromFile(filename);
        }


и тут заковыка... когда бросаю файлы на мемо - ничего не проиходит :(
а на листбокс - ошибка:
Цитата:
First chance exception at 0x7C81EB33. Exception class EAccessViolation with message 'Access violation at address 00401BDA in module 'Project1.exe'. Read of address 00000000'. Process Project1.exe (0x444)



останавливается на строке после
GetCursorPos(p);

что делать? :(

кстати, ещё нашёл на codenet.ru чуток по теме... но всёравно нету о нескольких вариантах приёма файлов...

16K
11 сентября 2007 года
AntidotE
45 / / 26.09.2006
использование DragQueryPoint((HDROP) message.Drop, p); вместо GetCursorPos(p); даёт почти тот же результат... теперь при дропе уже над всей формой получаю:
Цитата:
First chance exception at 0x7C81EB33. Exception class EAccessViolation with message 'Access violation at address 7CA73F7B in module 'SHELL32.dll'. Write of address 00000000'. Process Project1.exe (0xAB4)


останавливается на DragQueryPoint((HDROP) message.Drop, p);

Пора, наверное, поспать наконец... :)

309
11 сентября 2007 года
el scorpio
1.1K / / 19.09.2006
Комментирую:
Цитата:
DragAcceptFiles(Form1->Handle, true);


Типичный таракан - использование глобального имени экземпляра класса внутри класса. Правильнее писать this->Handle

16K
11 сентября 2007 года
AntidotE
45 / / 26.09.2006
Цитата: el scorpio
Комментирую:

Типичный таракан - использование глобального имени экземпляра класса внутри класса. Правильнее писать this->Handle



ну да... а конкретнее по вопросу, если можно?

Цитата:
Если у меня 2 компонента, которые требуют разных вариантов принятия файлов... например, ЛистБокс, который добавляет в себя имена файлов, и Мемо, которое подгружает текст файла, на неё сброшенного... Как организовать разделение труда?

246
11 сентября 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: AntidotE
почитал... ничего конкретного по теме... или мне показалось?


картинку видел?
это - "шаблон",
а у твой вариант "копи-пасте" называется

P.S.
но в FAQ я его добавил

309
12 сентября 2007 года
el scorpio
1.1K / / 19.09.2006
AntidotE
Объясняю. Представь, что в программа является "многооконной". Вполне вероятно, создаётся несколько объектов данного класса и вызывается для одного из них данный метод. Что происходит?
- правильно: обращение к полям, методам и свойствам этого объекта.
- не правильно: обращение к полям и свойствам объекта Form1
246
12 сентября 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: AntidotE
... но всёравно нету о нескольких вариантах приёма файлов...



::DragAcceptFiles(ListBox1->Handle,true);

16K
13 сентября 2007 года
AntidotE
45 / / 26.09.2006
Цитата: GIZMO
 
Код:
::DragAcceptFiles(ListBox1->Handle,true);


Пробовал... Действительно, возможность приёма осуществляется только над теми объектами, чьи хендлы будут указаны при вызове этой функции.
Например,

 
Код:
::DragAcceptFiles(ListBox1->Handle,true);
::DragAcceptFiles(Memo1->Handle,true);

Дропать можно только над Мемо и Листбоксом, над остальными объектами будет запрет.
Но как определить, над каким из объектов дропнули? Этого я не могу сделать без вашей помощи... :(

Цитата: GIZMO
картинку видел?
это - "шаблон",
а у твой вариант "копи-пасте" называется

P.S.
но в FAQ я его добавил


К сожалению и стыду признаю, что шаблонами ещё пользоваться не умею, создавать классы-наследники тоже... Объектно-ориентированное программирование для меня пока почти филькина грамота...
Покажите мне, что, где (и как?) сделать, чтобы определить, какой объект должен обработать событие дропа на нём...

Цитата: el scorpio
AntidotE
Объясняю. Представь, что в программа является "многооконной". Вполне вероятно, создаётся несколько объектов данного класса и вызывается для одного из них данный метод. Что происходит?
- правильно: обращение к полям, методам и свойствам этого объекта.
- не правильно: обращение к полям и свойствам объекта Form1


А можно частный случай привести как пример? Я из него попробую вычленить нужное... ;)
ИМХО, Вы слишком ударяетесь в теорию, а эта часть мне никогда не давалась легко... :o

З.Ы. Извините, что такой непонятливый...

309
14 сентября 2007 года
el scorpio
1.1K / / 19.09.2006
AntidotE
Значит так. Программа создаёт несколько объектов (в данном случае - окон), но данное действие будет выполняться только для конкретного экземпляра (в данном случае Form1).
Но если указатель Form1 не будет содержать адрес реально существующего объекта, то программа пойдёт на Access Violation :(
Конкретный пример - фрагмент функции WinMain
 
Код:
Application->Initialize();
// Отключаем создание объекта для указателя Form1
// Application->CreateForm (__classid(TForm1), &Form1);
// Создаём окно без присвоения адреса указателю Form1
new TForm1 (Application);
Application->Run();

Объект формы будет удалён объектом приложения (указатель Application), поэтому потеря результата команды new не вызовет "утечку памяти". Но если в методах класса TForm1 где-то будет написано Form1, программа пойдёт лёсом, потому что Form1 указывает в никуда :)
16K
14 сентября 2007 года
AntidotE
45 / / 26.09.2006
Это всё очень хорошо, что Вы объясняете...
Но я не понимаю, как это объяснит мне, что делать с двумя компонентами, которые могут принимать дроп - как различить на какой компонент дропается?
10
14 сентября 2007 года
Freeman
3.2K / / 06.03.2004
Цитата: AntidotE
Но я не понимаю, как это объяснит мне, что делать с двумя компонентами, которые могут принимать дроп - как различить на какой компонент дропается?


Сначала прикинь, как будет реализовываться drop для компонентов, положенных на форму - их методы нельзя перекрыть. Скорее всего, придётся задавать WndProc. Чей WndProc задашь - тот и обрабатывать будет. Вопрос снят?

16K
14 сентября 2007 года
AntidotE
45 / / 26.09.2006
код в студию, если не трудно... сам не справлюсь... :(
246
16 сентября 2007 года
GIZMO
1.8K / / 30.07.2004
Цитата: AntidotE
код в студию, если не трудно... сам не справлюсь... :(



да куда ты денешся:)
см. 27. Как научить DBGrid слушаться колесико мышки?
http://forum.codenet.ru/showthread.php?t=26390&page=2
там пример сабклассинга оконной процедуры

841
17 сентября 2009 года
_nic
199 / / 29.07.2006
Я так и непонял как пользоватся этим способом для чего то кроме формы :( Обьясните плз как вкрутить WMDropFiles в компоненту типа листбокс? Ведь в отличии от главной формы классы компонент расписаны хз в каком месте,и я немогу понять куда пихать WMDropFiles что бы при сбрасывание файла на компонент гарантированно эта ф-ция вызывалась.
14
17 сентября 2009 года
Phodopus
3.3K / / 19.06.2008
Цитата: _nic
как вкрутить WMDropFiles в компоненту типа листбокс?


1. Создать потомка листбокс
2. Перехватить оконную функцию листбокс.

841
17 сентября 2009 года
_nic
199 / / 29.07.2006
Цитата: Phodopus
1. Создать потомка листбокс
2. Перехватить оконную функцию листбокс.


А можно пример?

246
18 сентября 2009 года
GIZMO
1.8K / / 30.07.2004
Цитата: _nic
А можно пример?


в ФАк-е это есть, надо только немного по-копипастить...

Код:
// in hpp
    TWndMethod oldProc;
    void __fastcall newProc(TMessage& message);
   
// in cpp
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    oldProc = ListBox1->WindowProc;
    ListBox1->WindowProc = newProc;
    ::DragAcceptFiles(ListBox1->Handle, true);
}


void __fastcall TForm1::newProc(TMessage& message)
{
    if(message.Msg == WM_DROPFILES) {
// cut form FAQ        
int filecount, length, i;
    filecount = DragQueryFile ((HDROP) message.Drop, 0xFFFFFFFF/*-1*/, NULL, 0); //получаем количество файлов
    //подробнее о параметрах и возвращаемых значениях DragQueryFile можно узнать тут или в хелпе Билдера
    AnsiString filename;
    for (i = 0; i < filecount; ++i)  {
        filename.SetLength(MAX_PATH);
        length = DragQueryFile((HDROP)message.Drop, i, filename.c_str(), filename.Length());
        filename.SetLength(length);
        //тут можно с файлами творить что угодно, например, имена добавить в StringList или открывать по очереди в Memo
    }
    DragFinish ((HDROP) message.Drop);

    }
    oldProc(message);
}
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог