ListBox Drag and Drop

problemy z funkcjonowaniem bibliotek, komponentów itp.

ListBox Drag and Drop

Nowy postprzez sawcioo » czwartek, 1 kwietnia 2010, 12:40

Nie mogę sobie poradzić z obsługa drag and drop w listbox. Konkretniej chodzi mi o to aby mógł elementy z lIstBox1 przeciągać do ListBox2, a także przesuwać elementy wewnątrz ListBox.
Avatar użytkownika
sawcioo
Bladawiec
Bladawiec
 
Posty: 8
Dołączył(a): piątek, 16 października 2009, 18:42
PodziÄ™kowaÅ‚ : 0
OtrzymaÅ‚ podziÄ™kowaÅ„: 0
    Windows 7Firefox

Re: ListBox Drag and Drop

Nowy postprzez Cyfrowy Baron » piÄ…tek, 2 kwietnia 2010, 08:35

Drag and Drop dla ListBox.

Przykład dla dwóch obiektów ListBox1 i ListBox2. Przez określenie dla obydwu obiektów ListBox rozumiem dla ListBox 1 i ListBox2

Dla obydwu obiektów ListBox ustawiasz w Object Inspector właściwość DragMode na dmAutomatic. Następnie w pliku nagłówkowym np. Unit1.h w sekcji private umieszczasz deklarację funkcji:

plik nagłówkowy:
Kod: Zaznacz cały
private:
     void __fastcall Drag_and_Drop(TObject *Source, TListBox *ListBox); // nazwa funkcji dowolna
 


Teraz w pliku źródłowym np. Unit1.cpp definiujesz tą funkcję:

plik źródłowy:
Kod: Zaznacz cały

void __fastcall TForm1
::Drag_and_Drop(TObject *Source, TListBox *ListBox)
{
  int index = dynamic_cast<TListBox *>(Source)->ItemIndex;
  ListBox->Items->Add(dynamic_cast<TListBox *>(Source)->Items->Strings[index]);
}
 


Następnie dla obydwu obiektów ListBox tworzysz zdarzenie OnDragOver i w każdym zdarzeniu umieszczasz dokładnie ten sam kod:

Kod: Zaznacz cały

void __fastcall TForm1
::ListBox1DragOver(TObject *Sender, TObject *Source, int X,
          int Y, TDragState State, bool &Accept)
{
 Accept = Source->ClassNameIs("TListBox");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListBox2DragOver(TObject *Sender, TObject *Source, int X,
          int Y, TDragState State, bool &Accept)
{
 Accept = Source->ClassNameIs("TListBox");
}
 


Potem dla obydwu obiektów ListBox tworzysz zdarzenie OnDragDrop i umieszczasz w nich podobny kod:

Kod: Zaznacz cały

void __fastcall TForm1
::ListBox1DragDrop(TObject *Sender, TObject *Source, int X,
          int Y)
{
 Drag_and_Drop(Source, ListBox1);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListBox2DragDrop(TObject *Sender, TObject *Source, int X,
          int Y)
{
 Drag_and_Drop(Source, ListBox2);
}
 


To wszystko. Teraz można przenosić wiersze z jednej listy do drugiej. W podanym przykładzie przeniesienie np. wiersza z ListBox1 do ListBox2 nie powoduje usunięcia tego wiersza z ListBox1, a tylko dodanie go do ListBox2. Jeżeli chcesz, żeby podczas przesuwania np. z ListBox1 wiersza do ListBox2 był on jednocześnie usuwany z ListBox1 to trzeba trochę zmodyfikować funkcję do takiej postaci:

Kod: Zaznacz cały

void __fastcall TForm1
::Drag_and_Drop(TObject *Source, TListBox *ListBox)
{
 int index = dynamic_cast<TListBox *>(Source)->ItemIndex;
 ListBox->Items->Add(dynamic_cast<TListBox *>(Source)->Items->Strings[index]);

 dynamic_cast<TListBox *>(Source)->Items->Delete(index);
}
 




W powyższym przykładzie widać powtarzające się elementy kodu, można to zoptymalizować wykorzystując polimorfizm, który jest zresztą wykorzystywany w funkcji Drag_and_Drop. Optymalizacji podlegają tylko zdarzenia. Tworzymy zdarzenie OnDragOver tylko dla jednego obiektu, np. tylko dla ListBox1 i podłączamy je do ListBox2 na zakładce Events w Object Inspector. Jeżeli nie wiesz o co chodzi z tym podłączaniem, to przykład podobnego podłączania znajdziesz w serwisie Cyfrowy Baron w dziele: teoria -> rzutowanie typów, przypisanie polimorficzne.
Kod w zdarzeniu OnDragOver dla ListBox1 należy nieco zmodyfikować:

Kod: Zaznacz cały

void __fastcall TForm1
::ListBox1DragOver(TObject *Sender, TObject *Source, int X,
          int Y, TDragState State, bool &Accept)
{
 String nameClass = dynamic_cast<TListBox *>(Sender)->ClassName();
 Accept = Source->ClassNameIs(nameClass);
}
 


Teraz postępujemy podobnie ze zdarzeniem OnDragDrop, czyli tworzymy tylko jedno zdarzenie, tylko dla ListBox1 i podłączamy je tak samo jak wyżej pod ListBox2. To zdarzenie również wymaga drobnej modyfikacji:

Kod: Zaznacz cały

void __fastcall TForm1
::ListBox1DragDrop(TObject *Sender, TObject *Source, int X,
          int Y)
{
 Drag_and_Drop(Source, dynamic_cast<TListBox *>(Sender));
}
 




Co się zaś tyczy przesuwania elementów listy myszką, to niestety przy DragMode ustawionym na dmAutomatic nie można pobrać numeru wiersza na który wskazuje myszka i dlatego przesuwanie nie będzie działać prawidłowo. Czyli możesz mieć jedno lub drugie.

Rozwiązanie problemu może polegać na tym, że elementy wewnątrz ListBox są przesuwane za pomocą prawego lub środkowego przycisku myszy, wtedy możliwe będzie stosowanie metody przeciągnij-upuść za pomocą lewego przycisku myszy i przesuwania elementów wewnątrz listy np. za pomocą prawego przycisku myszy.


Jeżeli to rozwiązanie Ciebie zadowala, to w pliku nagłówkowym w sekcji private deklarujemy dwie zmienne typu int:

Kod: Zaznacz cały
private:
    int nrRow, index;
 


Następnie tworzymy dla ListBox1 trzy zdarzenia OnMouseDown, OnMouseMove i OnMouseUp:

Kod: Zaznacz cały
// PRZESUWANIE MYSZKĄ ELEMENTÓW LISTY
void __fastcall TForm1::ListBox1MouseDown(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
{
 if(Button == mbRight)
 {
  dynamic_cast<TListBox *>(Sender)->DragMode = dmManual;
  
  POINT pt
;
  pt.x = X;
  pt.y = Y;

  nrRow = dynamic_cast<TListBox *>(Sender)->ItemAtPos(pt, true);
  dynamic_cast<TListBox *>(Sender)->ItemIndex = nrRow;
 }
 else dynamic_cast<TListBox *>(Sender)->DragMode = dmAutomatic;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListBox1MouseMove(TObject *Sender, TShiftState Shift,
          int X, int Y)
{
  POINT pt;
  pt.x = X;
  pt.y = Y;

  index = dynamic_cast<TListBox *>(Sender)->ItemAtPos(pt, true);
  dynamic_cast<TListBox *>(Sender)->ItemIndex = index;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListBox1MouseUp(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y)
{
 if(Button == mbRight)
 {
  if(dynamic_cast<TListBox *>(Sender)->ItemIndex > -1)
  dynamic_cast<TListBox *>(Sender)->Items->Move(nrRow, index);
  dynamic_cast<TListBox *>(Sender)->ItemIndex = index;
 }

 
 dynamic_cast
<TListBox *>(Sender)->DragMode = dmAutomatic;
}
 


Jak widać w przykładzie stosowałem polimorfizm by można było podłączyć zdarzenia do ListBox2 bez tworzenia dla tego obiektu dodatkowego kodu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
PodziÄ™kowaÅ‚ : 12
OtrzymaÅ‚ podziÄ™kowaÅ„: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: ListBox Drag and Drop

Nowy postprzez sawcioo » poniedziaÅ‚ek, 5 kwietnia 2010, 17:09

Dziękuje. W 100% wyczerpałeś temat;)
Avatar użytkownika
sawcioo
Bladawiec
Bladawiec
 
Posty: 8
Dołączył(a): piątek, 16 października 2009, 18:42
PodziÄ™kowaÅ‚ : 0
OtrzymaÅ‚ podziÄ™kowaÅ„: 0
    Windows 7Firefox


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Biblioteki i komponenty

Kto przeglÄ…da forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 2 gości