PORADY

Porady > Programowanie > Delphi > Dowolny komponent akceptujący przeciągnięte na niego pliki

Dowolny komponent akceptujący przeciągnięte na niego pliki

Projektując aplikację programista stara się maksymalnie uprościć współpracę swojego dzieła z użytkownikiem poprzez zapewnienie nie tylko intuicyjnego interfejsu, dostarczeniu skrótów klawiaturowych, ale i czasami kilku sposobów na wykonanie danej akcji. Przykładem takiego zadania jest otwieranie plików, które niejednokrotnie można realizować poprzez wskazanie pozycji w menu, przypisanie jej odpowiedniej kombinacji klawiszy (najlepiej standardowej Ctrl+O); dodatkowo funkcję taką często powiela się na pasku narzędziowym, a niejednokrotnie stosuje dodatkowe dedykowane przyciski otwierające okno wyboru pliku. Wszystkie te metody łączy jednak jedna cecha - często po ich zastosowaniu użytkownik musi dodatkowo przemierzyć zasoby dyskowe w poszukiwaniu pliku, który chce otworzyć w programie.

Tymczasem wraz z nastaniem systemu Windows 95 pojawiła się wręcz rewolucyjna technika przeciągnij i upuść (ang. drag&drop). Czy nie warto i jej wykorzystać w aplikacji? Przeciągnięcie pliku wprost na formatkę lub konkretny komponent często jest najprostszym i najszybszym sposobem na otwarcie pliku niewymagającym wyświetlania okienek dialogowych przeszukiwania dysku. Z techniki tej korzysta cała rzesza programów począwszy od notatnika. Jednakże Delphi nie dostarcza komponentów, na które można by przeciągnąć pliki wprost z systemu.

Często, projektując aplikację, funkcję taką potrzebujemy wyłącznie do jednego lub co najwyżej kilku komponentów. Często także bywają to różne komponenty począwszy od pól edycyjnych na złożonych komponentach wyświetlających dane skończywszy. Nie ma więc sensu rozszerzać wszystkich możliwych komponentów o opisywaną funkcję. Dlatego w poradniku tym zajmiemy się rozszerzeniem pojedynczego komponentu o opcję pozwalającą przeciągnąć na niego plik z systemu operacyjnego. Podana metoda jest na tyle wygodna, że w łatwy sposób pozwala przeprojektować gotowe aplikacje (i tak należy postępować przy jej stosowaniu).

Załóżmy więc, że posiadamy gotową aplikację z pełni oprogramowanym komponentem typu TEdit (przypisane wszystkie zdarzenia i odwołania do niego z innych części programu), który służy do podawania nazwy pliku. Jednak chcemy rozszerzyć jego możliwości o opcję upuszczania na niego plików przeciągniętych z okien Explorera Windows tak, aby po upuszczeniu pokazała się w nim nazwa przeciągniętego pliku.

Pierwszym krokiem będzie stworzenie nowej klasy komponentu w oparciu o klasę bieżącą. Wystarczy zdefiniować nowy typ podobnie, jak ma to miejsce przy tworzeniu typu formatki. Typ ten możemy zdefiniować tuż pod pierwszym słowem kluczowym type w pliku (unit). Definicja będzie miała następującą postać:

TFileAcceptEdit=class(TEdit)

Oczywiście nazwa typu, jaką nadamy jest dowolna. Oznacza to nie mniej, nie więcej jak stworzenie nowej klasy TFileAcceptEdit dziedziczącą z klasy TEdit. Stąd zachowane zostaną wszystkie zmienne, procedury i funkcje klasy nadrzędnej (poza tymi, które zadeklarowane zostały jako chronione (protected)).

W dalszej części zachodzi konieczność stworzenia nagłówka procedury, która będzie reagować na wiadomość z systemu dotyczącą upuszczania przeciągniętego pliku. Jako, że przypisana będzie ona ściśle do komponentu dopisujemy ją w sekcji private. Jej postać jest następująca: procedure DropFileMessage(var Message: TWMDropFiles); message WM_DROPFILES; Istotnym jest właśnie dopisanie wskazania message po nagłówku funkcji, które wskazuje, że jest ona wywoływana w momencie odebrania przez klasę (komponent) wymienionej wiadomości systemowej, która w naszym przypadku nazwana jest WM_DROPFILES.

Zatem kompletna deklaracja naszego komponentu będzie miała następującą postać: TFileAcceptEditEdit=class(TEdit) private procedure DropFileMessage(var Message: TWMDropFiles); message WM_DROPFILES; end; Tworzenie komponentu

Kolejnym krokiem będzie oczywiście napisanie kodu obsługi procedury. W części implementacyjnej tworzymy więc ciało nowej funkcji pamiętając, że jest ona przypisana do klasy TFileAcceptEdit! procedure TFileAcceptEdit.DropFileMessage(var Message: TWMDropFiles); var bufor: array[0..1024] of Char; begin DragQueryFile(Message.Drop, 0, bufor, SizeOf(bufor)); Text:=string(bufor); DragFinish(Message.Drop); Self.Change; end; Nie rozwodząc się zbytecznie nad znaczeniem użytych funkcji (zainteresowanych odsyłam do pomocy Windows SDK) pokrótce nadmienię, że druga linia przypisuje właściwości Text komponentu TEdit nazwę pliku wraz ze ścieżką dostępu. Przypominam, że nie posługujemy się tutaj żadnymi konkretnymi nazwami komponentów, gdyż funkcja ma działać w odniesieniu do każdej kopii komponentu stworzonego w oparciu o naszą nową, rozbudowaną klasę. Polecenie Self.Change z kolei informuje komponent, że zaistniała zmiana jego tekstu, co pozwoli na wyzwolenie procedury przypisanej do zdarzenia OnChange.

procedura obsługi wiadomości WM_DROPFILES

Etap tworzenia klasy komponentu został zakończony. Teraz należy podmienić interesujący nas komponent. Jednak nie wystarczy zmienić jego klasę w kodzie - w takim przypadku, choć poprawnym, kompilator zacznie generować ostrzeżenia (wynika to z automatyzacji kodu w Delphi, w którą ciężko ingerować). Dlatego konieczne okaże się usunięcie komponentu i wstawienie go do programu w sposób dynamiczny (już w trakcie działania aplikacji). Jednak zanim usuniemy komponent, pobierzmy jego właściwości. Otwórzmy więc w dowolnym edytorze tekstowym plik dfm, który zawiera właściwości wszystkich komponentów stworzonych w środowisku Delphi i odnajdźmy interesujący nas komponent (nazwa pliku jest analogiczna do nazwy pliku z kodem).
właściwości komponentu w pliku dfm
Skopiujmy wszystkie właściwości komponentu do schowka.

Teraz możemy wrócić do Delphi i usunąć komponent z formatki. Przygotujmy teraz zmienną, która będzie identyfikować nasz komponent. Można umieścić ją w sekcji publicznej komponentu okna. Pamiętajmy o nadaniu jej nazwy identycznej, jaką posiadał usuwany komponent (zapewni nam to, że nie będziemy musieli ingerować w pozostały kod).

zmienna dynamicznego komponentu

Czas na dynamiczne stworzenie komponentu. Najlepszym rozwiązaniem będzie stworzeniem go w procedurze obsługi zdarzenia OnCreate okna. Przejdźmy więc do tej procedury i utwórzmy komponent: NameEdit:=TFileAcceptEdit.Create(MainForm); Pamiętajmy, że parametrem funkcji Create musi być nazwa komponentu rodzica (na którym umieszczony jest komponent). Jeśli umieszczony jest bezpośrednio w oknie - jest to nazwa okna; jeśli umieszczamy go np. w komponencie typu TGroupBox - nazwa tego komponentu.

Stworzonemu komponentowi czas przypisać skopiowane z pliku dfm właściwości. Stwórzmy więc dla wygody blok with i wklejmy skopiowany tekst: with NameEdit do begin Left = 256 Top = 4 Width = 169 Height = 21 TabOrder = 2 OnEnter = NameEditEnter End; Oczywiście zapis ten nie jest zgodny z systematyką języka Pascal. Stąd zamieńmy wszystkie znaki równości na przypisanie (:=), zaś na końcu każdej linii dodajmy znak średnika. Wśród właściwości brakuje jeszcze jednej bardzo istotnej - określenie rodzica komponentu. Stąd na początku przypiszmy jeszcze rodzica: Parent:=MainForm;

Teraz mamy stworzony komponent ze wszystkimi właściwościami, jakie przypisaliśmy podczas tworzenia aplikacji. Pozostaje jeszcze jedno - „powiedzieć” systemowi, że dany komponent akceptuje przeciągnięte pliki. Dokonamy tego przy użyciu funkcji Windows API DragAcceptFiles: DragAcceptFiles(ListView.Handle,true); Pierwszym parametrem tej funkcji jest uchwyt do obiektu, zaś drugi określa, że na komponent możemy upuszczać pliki.

Cały kod tworzenia naszego komponentu przedstawiono na rysunku:

dynamiczne tworzenie komponentu

Program gotowy jest do użycia. Ale pozostaje jeszcze jeden krok: W myśl zasady, że to co ręcznie tworzymy musimy ręcznie usuwać, pozostaje po zakończeniu programu usunąć z pamięci nasz komponent i powiedzieć systemowi, że przestaje on przyjmować pliki. Przejdźmy zatem do procedury obsługi zdarzenia OnDestroy okna aplikacji i dopiszmy stosowny kod: DragAcceptFiles(ListView.Handle,false); ListView.Free;

Oczywiście należy pamiętać o właściwej kolejności - najpierw informujemy system, następnie usuwamy komponent.

usuwanie dynamicznie stworzonego komponentu

To wszystko - aplikacja jest gotowa do działania, a na nasze pole tekstowe możemy przeciągać pliki!


Jeśli często wykorzystujesz standardowe komponenty w roli punktów docelowych dla przeciąganych plików - skorzystaj z paczki DragFilesAccept Components!

Informacje o poradzie
Powiązane linki:Wróć
[Komentarze] | Share Podziel się
Poradę czytano:1 682 razy
Ocena porady:
5,50 (6 oceniających)
(Kliknij właściwą gwiazdkę, by oddać głos)

Uwaga! Wszystkie porady na tej stronie są mojego autorstwa i objęte są prawami autorskimi! Kopiowanie, publikowanie lub cytowanie całego tekstu bez wiedzy autora - ZABRONIONE! [Dowiedz się więcej o prawach autorskich]

Strona istnieje od 25.01.2001
Ta strona używa plików Cookie
 
archive To tylko kopia strony wykonana przez robota internetowego! Aby wyświetlić aktualną zawartość przejdź do strony.
Ładowanie...

Optymalizowane dla przeglądarki Firefox
© Copyright 2001-2017 Dawid Najgiebauer. Wszelkie prawa zastrzeżone.
Ostatnia aktualizacja podstrony: 22.09.2014 11:28
Wszystkie czasy dla strefy czasowej: Europe/Warsaw