[DELPHI] Przewijanie ListView

0

Witam.
Wiem że nie jestem jedyny który ma taki problem (bo pełno takich pytań w necie), kłopot jednak w tym, że nikt nie udzielił sensownej odpowiedzi...

Ukryłem sobie stare scrolle z ListView i mam własne, ładniejsze. Problem jest taki że teraz muszę podpiąc te nowe ScrollBary do Listview.

Mam taki oto kod (w OnScroll ScrollBara):
ListView1.Items[ScrollBar.Position].MakeVisible(True);

Działa prawie jak trzeba. Problem polega na tym że ScrollBar zaczyna robić co do niego należy, dopiero wtedy gdy jego pozycja (Position), jest większa niż index ostatniego elementu jaki jest widoczny w ListView. Przykład:

ListView ma taki rozmiar że widać w nim tylko 4 elemety, a reszta jest schowana. Klikamy raz na ScrollBar, jego pozycja przeskakuje z 0 na 1, wtedy kod sprawia że element ListView o indexie 1 staje się widoczny, co w tym przypadku oznacza brak reakcji, bo element już jest widoczny!... Potem analogicznie pozycja 2,3,4 i dopiero przy tym ostatnim następuje oczekiwana reakcja, bo element listy o indexie 4 nie jest widoczny (przypominam że indexy liczą się od 0).

Moje pytanie, jak temu zaradzić? Jak zrobić żeby każde kliknięcie odsłanało nowy element, bez względu na to ile elementów jest aktualnie widocznych?

Próbowałem dodawać np:

ListView1.Items[ScrollBar.Position+3].MakeVisible(False);

Odnosi to prawidłowy skutek, ale tylko w jedną stronę. Gdy ScrollBar wraca od max do min, należało by liczę odejmować zamiast dodawać. Nie wiem jednak jak rozpoznać czy scrolling jest malejący czy rosnący...

Druga wada jest taka że trzeba wtedy dokładnie wiedzieć ile elementów jest aktualnie widocznych (da się to sprawdzić programowo?).

PS. Dlaczego ten cholerny ListView nie może mieć takiego wygodniego TopIndex jak w ListBox??? ;[

Pozdro.

0

Użycie MakeVisible do scrollowania to chyba nieporozumienie, proponuję zaznajomić się z funkcjami API dotyczącymi scrollowania (rozdział "Scroll Bar Functions"). Tam są takie funkcje jak ScrollWindowEx (do scrollowania zawartości np. ListView), SetScrollInfo (ustawienia scrollbara) lub GetScrollInfo (info o stanie scrollbara). Ta pierwsza funkcja chyba by tu mogła się przydać. ;-)

Pzdr.
Marogo

0

A można jakieś linki? Bo ja w necie nic nie widzę, wrzucenie ScrollWindowEx + Delphi nic nie daje...
Może jakiś kawałek kodu?

0

A ja proponuję wysyłać (SendMessage) następujące komunikaty:
LVM_GETCOUNTPERPAGE - ile pozycji jest widocznych (brane są pod uwagę tylko widoczne w całości)
LVM_GETTOPINDEX - tego Ci brakowało ;)
LVM_ENSUREVISIBLE - tego możesz użyć do przewijania ListView lub MakeVisible jak Ci wygodniej.

0

Zwraca mi błąd, "unknown identyfier" przy którymkolwiek z tych komunikatów...

0

Do uses CommCtrl

0

Witam, odkopuje temat bo wróciłem do dawnego projektu, a nadal nie mogę sobie z tym poradzić :/

Te komunikaty są przedatne, ale w moim przypadku niewiele pomagają (moja lista ma niezmienny rozmiar, więc mogę sobie to i "na oko" wyliczyć). Przydało by mi się raczej coś w stylu SETTOPINDEX, ale nie ma czegoś takiego :(

Kompletnie nie wiem jak to zrobić. Jeżeli ustalę w ScrollBarze Min na pierwszy niewidoczny index (powiedźmy 10, na liście na której widać 9 elementów, a wszystkich jest 20), oraz Max na ilość wszystkich elemntów - to jest dobrze, ale tylko w jedną stronę (co jest oczywiste - w drugą trzeba by zmienić Max na 10 a Min na 0, żeby obsługiwało pierwszą połowę)... Gdybym mógł sprawdzić czy Progress w ScrollBar maleje czy rośnie, lub za pomocą komunikatów, sterować TopIndexem - to był by problem z głowy.

0

Nie wiem czy dobrze rozumiem... ale skoro masz mało pozycji w ListView to po co tracić czas na "poprawne" rozwiązanie problemu jak można to obejść. Spróbuj cos takiego.

procedure TForm1.ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode;
  var ScrollPos: Integer);
var
  max: Integer;
begin
  max:= SendMessage(ListView1.Handle, LVM_GETCOUNTPERPAGE, 0, 0);
  ScrollBar1.Max:= max + 1;
  SendMessage(ListView1.Handle, LVM_ENSUREVISIBLE, 0, 0); //lekarstwo na przewijanie w gore
  SendMessage(ListView1.Handle, LVM_ENSUREVISIBLE, ScrollPos + max - 1, 0);
end;

A jak chcesz sprawdzać czy maleje czy rośnie to proste yworzysz globalną zmienną np. nazwijmy ją LastScrollPos w OnCreate formularza przypisujesz jej 0 a w OnScroll za każdym razem zapisujesz ostania pozycję (oczywiście już po kodzie sprawdzającym czy LastScrollPos > ScrollPos).

0

Teraz już wszystko wiem, działa!

Wielkie dzięki, pozdrawiam, gdybym wpadł na jakieś nowe problemy z tym związane, na pewno dam o sobie znać :)

0

Witam

Odkopuję stary temat, bo mam pytanie związane z omawianym tutaj zagadnieniem, a szkoda "śmiecić" i tworzyć nowe tematy o tym samym.

Jakimi komunikatami można obsłużyć Scrollowanie, ale w poziomie? Potrzebuję kodu który zadziała dla ListView i dla Memo.

0

Przejrzałem wątek tylko pobieżnie i widzę, że trochę "kombinujesz" z komponentem ListView, więc może moja odpowiedź nie do końca będzie przydatna w tym konkretnym przypadku, ale w typowych zastosowaniach powinna zadziałać.

Jeśli chodzi o przewijanie w Memo to zobacz mój post w tym temacie: Przewijanie w Memo

Odnośnie przewijania ListView, to jest dostępna metoda Scroll(DX, DY: Integer), a także procedura ScrollBy(DX, DY: Integer) obsługująca dowolną kontrolkę. Obydwie mogą być pomocne

0

Siemano, czy mogłby ktoś podpowiedzieć jak przewijać w poziomie? Sposoby powyżej nie działają poprawnie. Procedura scroll nie spełnia wystarczającej roli :(

1 użytkowników online, w tym zalogowanych: 0, gości: 1