ListBox jak w GG

0

Cześć, od kilku dni szukam komponentu, który będzie miał zachowanie jak ListBox w GG(lista kontaktów).

Do tej pory znalazłem dwa, ale jeden implementował grupy, a drugi "opisy"(poza tym nie mogę uruchomić projektów z nim przez plik design...blabla).

Czy znacie jakiś taki komponent, który ma zaimplementowane zachowanie listy kontaktów z GG?

0

Tak, zwykły ListBox, ta kontrolka posiada ownerdraw - możliwość ręcznego rysowania tak samej kontrolki jak i jej elementów... popatrz w manual zanim zaczniesz komponentów szukać.

0

A jeśli nie to na pewno TVirtualTreeView.

0

Deus, ja wiem dobrze, czym jest ownerDraw. Ale powiedz mi, po co mam się męczyć kilka dni(pracuję, więc nie będę siedział nad tym zbyt często) nad czymś, co już jest? :/

PS. A jeśli nie chcę używać TreeView, tylko czegoś pochodzącego od ListBoxa, to znacie coś?

0

Oblookaj to - może się przyda
http://4programmers.net/Forum/388107

0

Kiedyś coś takiego pisałem z nudy. Do rysowania listy używałem ListBoxa a dane kontaktów (numer, nazwa, opis itp) trzymałem w ListView. Masz tu kod może ci się przyda:

procedure TForm1.LUserDrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
Var
Ico: TIcon;
X,H: Integer;
S,T: String;
I  : Integer;
R  : TRect;
Row: Integer;
Z  : Integer;
begin
Ico := TIcon.Create;
if odSelected in State then begin
R.Left   := Rect.Left+2;
R.Right  := Rect.Right-2;
R.Top    := Rect.Top +2;
R.Bottom := Rect.Bottom-2;
LUser.Canvas.Brush.Color := $009DDEB7;
LUser.Canvas.FillRect(R);
LUser.Canvas.Brush.Color := $00266042;
LUser.Canvas.FrameRect(R);
LUser.Canvas.Brush.Style := bsClear;
Img2.GetIcon(0, Ico);
LUser.Canvas.Draw(Rect.Right-30, Rect.Top + 4, Ico);  
Img3.GetIcon(0, Ico);
LUser.Canvas.Draw(Rect.Left+4, Rect.Top + 4, Ico);
LUser.Canvas.Font.Color  := clBlack;
LUser.Canvas.Font.Style  := [fsBold];
LUser.Canvas.TextOut(Rect.Left + 25, Rect.Top+6,  L1.Items[Index].SubItems[0]);
end else begin
LUser.Canvas.Brush.Color := $00F2FEEC;
LUser.Canvas.FillRect(Rect);
Img2.GetIcon(0, Ico);
LUser.Canvas.Draw(Rect.Right-30, Rect.Top + 4, Ico);
Img3.GetIcon(0, Ico);
LUser.Canvas.Draw(Rect.Left+4, Rect.Top + 4, Ico);
LUser.Canvas.Font.Color  := clBlack;
LUser.Canvas.Font.Style  := [fsBold];
LUser.Canvas.TextOut(Rect.Left + 25, Rect.Top+6,  L1.Items[Index].SubItems[0]);
end;
Ico.Free;
LUser.Canvas.Font.Name   := 'Tahoma';
LUser.Canvas.Font.Height := -10;
LUser.Canvas.Font.Style  := [];
//------------------------------------------------------------------------------

H  := Canvas.TextHeight(LUser.Items[Index]);
S  := L1.Items[Index].SubItems[2];
Row:= (Canvas.TextWidth(S)) div (LUser.Width-20);
if (Row*(LUser.Width-20)) <> Canvas.TextWidth(S) then
Row := Row +1;

for I := 1 to Row do begin
for X := 1 to Length(S) do begin
if X = Length(S) then begin
LUser.Canvas.TextOut(Rect.Left + 10, (Rect.Top + H) + (10*i),  Copy(S, 1, X));
Break;
end;
if S[x] = ' ' then begin
T := Copy(S, 1, X);
if Canvas.TextWidth(T) < LUser.Width-20 then
Z := X
else
break;
end;
end;
LUser.Canvas.TextOut(Rect.Left + 10, (Rect.Top + H) + (10*i),  Copy(S, 1, Z));
Delete(S, 1, Z);
end;
end;

Luser - komponent ListBox
Img2, Img3 - komponent TImageList

procedure TForm1.LUserMeasureItem(Control: TWinControl; Index: Integer;
  var Height: Integer);
Var
S  : String;
Row: Integer;
I,H: Integer;
begin
S := L1.Items[Index].SubItems[2];
Row:= (Canvas.TextWidth(S)) div (LUser.Width-20);
if (Row*(LUser.Width-20)) <> Canvas.TextWidth(S) then
Row := Row +1;
if Row > 0 then
Height := (28 + 6) + (10*Row)
else
Height := 28;
end;

Krótkie objaśnienie:
Do komponentu L1 (TListView) ładowane są dane [Numer, Nazwa, Adres, Opis]
Następnie wyświetlane są na LUser (ListBox). Wielkość zaznaczenia zależy od długości opisu. Potestuj, zmodyfikuj może coś ci z tego wyjdzie. U mnie całość wyglądała mniej więcej tak:

user image

Powodzenia. Pozdro!!!

0
Juhas napisał(a)

Deus, ja wiem dobrze, czym jest ownerDraw. Ale powiedz mi, po co mam się męczyć kilka dni(pracuję, więc nie będę siedział nad tym zbyt często) nad czymś, co już jest? :/

PS. A jeśli nie chcę używać TreeView, tylko czegoś pochodzącego od ListBoxa, to znacie coś?

nie przesadzaj, nie od razu kilka dni...
nie ma to jak samemu sobie napisac, wszystko bedzie dokladnie tak jak bys tego chcial a nie tak jak ktos tam kiedys napisal...

niech ktos Ci tylko powie jak dodac do listboxa pryciski przy kazdym itemie (bo ja nie pamietam jak sie to robilo) ;]

pozdr
cimak.

0

Zobacz Część 1, jakby co
Virtual Treeview

//edit: ajj, nie zauważyłem, że suchar. ale moze sie komus przyda, wiec nie usuwam.

0
puchi napisał(a)

Kiedyś coś takiego pisałem z nudy. Do rysowania listy używałem ListBoxa a dane kontaktów (numer, nazwa, opis itp) trzymałem w ListView

Jak możesz wyślij źródła: [email protected] bo nie mogę tego poprawnie skompilować, wyrzuca mi błąd "ListIndex out of bounds (2)".

0

@up - dodaj jakieś itemy do listbox

0

bejo sprawa jest prosta masz złe dane w L1 (ListView) Musisz mieć na formularzu komponent ListView nazwij go L1. To w nim są przechowywane dane u urzytkowniku. Teraz stwórz 4 kolumny. Teraz dodaj jakieś pozycje do L1 i bedzie śmigać.
U mnie to wyglądało tak:

L1.Caption := '7836762'; //numer gg
L1.SubItems.Add('Nazwa urzytkownika');
L1.SubItems.Add('adres ip');
L1.SubItems.Add('opis na liście');

Tobie się wywala bo nie może znaleźć pola z opisem. Musisz zrobić tak jak ci napisałem albo przerób sobie na swoje potrzeby. Pozdro

0

Już naprawiłem.

Tak, chodziło o ilość wpisów w ListView.
ListBox odnosi się do tego samego nr Itema, co w ListView. Ja mając 5 pozycji w ListBox i 2 w ListView, klikając w ListBox na pozycje > 2, miałem wspomniany błąd.

0

puchi a moglbys umiescic tu albo wyslac mi na emaila ten kod wykorzystany w programie?? nie udaje mi sie zrobyc taki efekt jak Ty masz....moj email to [email protected] z gory dzieki

ok, dzieki wielkie, wszystko dziala, ale jest anstepny problem,jak zrobic zeby jak klikne na dana pozycje to pojawial mi sie komunikat z jej zawaroscia(w przykladzie puchiego np User1 a jak klikne na user2 to zeby wyswietlal sie kompunikat "user2") dzieki i pozdrawiam

0

w zdarzeniu OnClick listBoxa daj coś takiego:

ShowMessage(LUser.Items[LUser.ItemIndex]);

Spowoduje wyświetlenie komunikatu z nazwą usera

0

tak robie i pokazuje mi nazwe ale tylko pierwszej pozycji na liscie, dlatego pytam o to...

przepraszam ze nie napisalem w jednym... jak daje polecenie w przycisku

showmessage(inttostr(luser.Count));

to wyswietla prawidlowa ilosc elementow, czyli 5, a jak daje to co napisales to wyswietla mi sie User1, nie wiem czy o nie przez ten opis np. bo jak wyciagnac z takiego itema opis osobno a nazwe osobno?;>

0
michalvvv napisał(a)

przepraszam ze nie napisalem w jednym... jak daje polecenie w przycisku

showmessage(inttostr(luser.Count));

to wyswietla prawidlowa ilosc elementow, czyli 5, a jak daje to co napisales to wyswietla mi sie User1, nie wiem czy o nie przez ten opis np. bo jak wyciagnac z takiego itema opis osobno a nazwe osobno?;>

w moim przykładzie wszystkie informacje (nazwa, opis, numer itp.) sa zapisane w komponencie ListView, jeśli chcesz zobaczyć opis to wystarczy że napiszesz tak:

ShowMessage(L1.Items[LUser.ItemIndex].SubItems[x]);

gdzie x ustaw w zależności co chcesz wyświetlić.

Jeśli zamias danych zaznaczonego itema chcesz uzyskać informacje np. o pozycji numer 5 to musisz napisać:

ShowMessage(L1.Items[5].SubItems[x]);
0
Juhas napisał(a)

PS. A jeśli nie chcę używać TreeView, tylko czegoś pochodzącego od ListBoxa, to znacie coś?

No VirtualTreeView tylko w nazwie jest Tree, do robienia wszelkiej maści list nadaje się idealnie. :) Sam swego czasu zrobiłem w nim listę kontaktów i pomimo naprawdę wielu operacji malowania, śmigała. :) (Oczywiście kod był jak najbardziej optymalny, przynajmniej wtedy tak myślałem. :P)

0

dodawanie do L1 zrobiłem tak


procedure TForm1.Button1Click(Sender: TObject);
var
 Li: TListItem;
begin
 Li := L1.Items.Add;
Li.Caption := Edit1.Text; //numer gg
Li.SubItems.Add(Edit2.Text);
Li.SubItems.Add(Edit3.Text);
Li.SubItems.Add(Edit4.Text);
end;

ale jak zrobić by rysowało się to w Luser bo gdy dodaję pozycje do L1 to Luser pozostaje bez zmian i w ogóle nie zmienił się jego wygląd z oryginalnego na proponowany przez puchi
dodałem zdarzenie DrawItem oraz MeasureItem coś jeszcze mam zrobić wszystko się ładnie rysowało samo ?

0

Odśwież canvas.

0

Jak to zrobić ? próbowałem już tak :

Luser.Repaint;
Luser.Refresh;
Luser.Canvas.Refresh;
0
wątły napisał(a)

Jak to zrobić ? próbowałem już tak :

Luser.Repaint;
Luser.Refresh;
Luser.Canvas.Refresh;

A Invalidate?

0

też nie działa , no chyba że robie coś źle .
A więc tak: uruchamiam program dodaje wartości do L1 potem do Luser i klikam na button w celu odświeżenia i nic się nie dzieje ,

wrzucił by tu ktoś całe źródła ?

Ok już działa

Luser.Style:=lbOwnerDrawVariable;

:-D

<ort>Witam zrobiłem również tą listę kontaktów , lecz zastanawiam się jak dołączyć do tego wyświetlanie dostępności użytkownika . mam komponent gglite w Listview potrafię to zrobić lecz nie potrafię tego zrobić w naszym listoboxie który tak ładnie się dzięki panu Puchi się prezetuje

w gglite sprawdzanie dostępności realizowane jest dzięki tej procedurze :
gdzie L1 to listview:

procedure TForm1.GGRecvUserNotify(Sender: TObject; UserId: Integer;
  UserStatus: TGGUserStatusExt; UserDesc: String; UserReturnTime: Double;
  UserMaxImageSize: Byte; UserIP: Integer);
var
i: integer;
begin
for i:=0 to L1.Items.Count -1 do
begin
If StrToInt(L1.Items[i].SubItems.Strings[0])= UserId then
case UserStatus of
      usNotAvailable: L1.Items[i].ImageIndex := 2;
      usNotAvailableDesc: L1.Items[i].ImageIndex := 2;
      usAvailable: L1.Items[i].ImageIndex := 0;
      usAvailableDesc: L1.Items[i].ImageIndex := 0;
      usBusy: L1.Items[i].ImageIndex := 1;
      usBusyDesc: L1.Items[i].ImageIndex := 1;
    end;
end;
end; 

czy ktoś mógłby coś ciekawego w tym temacie powiedzieć ?

Pozdrawiam.</ort>

0

Witam kozystajac z mojego kodu musisz zmienić:

Img3.GetIcon(0, Ico);
LUser.Canvas.Draw(Rect.Left+4, Rect.Top + 4, Ico);

musisz to zamienic na cos takiego

if L1.Items[Index].ImageIndex = 0 then begin //usAvailable
Img3.GetIcon(0, Ico);
LUser.Canvas.Draw(Rect.Left+4, Rect.Top + 4, Ico);
end;

if L1.Items[Index].ImageIndex = 1 then begin //usBusy
Img3.GetIcon(1, Ico);
LUser.Canvas.Draw(Rect.Left+4, Rect.Top + 4, Ico);
end;

if L1.Items[Index].ImageIndex = 2 then begin //usNotAvailable
Img3.GetIcon(2, Ico);
LUser.Canvas.Draw(Rect.Left+4, Rect.Top + 4, Ico);
end;

Teraz ikonka będzie ustawiana w zależności od stanu usera. Pisałem z głowy i nie sprawdzałem ale powinno być ok, a nawet jeśli coś nie działa to myśle że cie naprowadziłem na rozwiązanie.
Pamiętaj żeby w ImageList (Img3) poustawiać ikonki w odpowiedniej kolejności.
Pozdro

0

Puchi tu skubańcu , wielki dzięki tego mi było trzeba wszystko działa fantastycznie
Pomogłeś mi i pewnie wielu ludziom oczekującym odpowiedzi [soczek]

0

wątły, jak wróce do domu z budy to postaram Ci napisać jak to u mnie jest rozwiązane bo teraz trudno mi powiedzieć, ale z tego co pamiętam to jak dodawalem elementy do L1 to dodaje je bez problemu, tyle ze muszą być wszystkie dostępne kolumny wypełnione:) A pomijajac problem ten przykład jest naprawde swietny, troche go dopracować i lisbox wygląda naprawde bardzo ładnie, ja osobiście polecam:)

0

michalvvv , No to czekam ;-)

* ok, nie było sprawy, posprzątałem trochę temat. * deus

0

Wątly, nie wiem czy dobrze zrozumialem ale dodawanie elementow do listboxa(luser) z poziomu aplikacji w moim wypadku musialo wygladac tak że przy starcie programu wczytywalem dane z pliku ini do osobnego listboxa z niego pozycje zostaly dodane do l1 i pozniej juz do luser. A jak chce dodać pozycje w czasie działania programu, to najpierw zapisuje ja do pliku ini, pozniej czyszcze tego listboxa, l1 i luser, pozniej nastepnie za pomoca petli dodaje wszystkie pozycje tak jak na poczatku programu, czyli listbox>l1>luser.
Staralem sie to w miare jasne napisac ale...jak co to pisz na gg: 7218015 to wytlumacze Ci dokladnie jak ja to zrobilem. Kodu na razie tu niestety nie umieszcze bo nie jest przystosowany do publikacji;)a moj styl programow pozostawia duzo do zyczenia...pozdrawiam

0

siemano, a jak zrobic zeby ta ikonka po prawej stronie mogla byc zmieniona, powiedzmy ze w imaglist mam 2 ikonki i teraz np chce zeby jesli pierwsza i trzecia pozycja w L1 ma w kolumnie o nazwie "wartosc" wpisane "jeden" to zeby obok tych wartosci wyswietala sie ikonka nr 1 a jesli wartosc druga i czwarta w tej samej kolumnie ma wpisane "dwa" to zeby obok tego wyswietlla sie ikonka nr dwa, udalo mi sie to zrobic ale dziala tylko wtedy kiedy klikne na dana pozycje to zmienia sie ta ikonka..

// kolejny?!
// ten post: (83.29.101.34 (brh34.neoplus.adsl.tpnet.pl, ) Opera/9.26 (Windows NT 5.1; U; pl)...)
// poprzedni: (83.29.101.34 (brh34.neoplus.adsl.tpnet.pl, ) Opera/9.26 (Windows NT 5.1; U; pl)...)
// już druga osoba w tym temacie ma rozdwojenie jaźni... skończycie się wydurniać albo się temat zamknie itd.

0

Deus teraz to to już nie ja :-)

* tak, wiem. * deus

0

fadsf to dlatego że kod odpowiedzialny za zmiane musiałeś umieścić pod warunkiem:

if odSelected in State then begin
//TU PODAJESZ KOD KTÓRY MA SIĘ WYKONAĆ PODCZAS ZAZNACZENIA i PEWNIE TU SIE ZNAJDUJE U CIEBIE KOD ODPOWIEDZIALNY ZA ZMIANE TEJ IKONKI 
end else begin
//TU PODAJESZ KOD KTÓRY MA SIĘ WYKONAĆ DLA WSZYSTKICH NIEZAZNACZONYCH
end;

//A TU PODAJESZ KOD KTÓRY MA SIĘ WYKONAĆ NIE ZALEŻNIE CZY ZAZNACZONY CZY NIE I TO TU MUSISZ UMIEŚCIĆ KOD ZMIENIAJĄCY IKONKE W ZALEŻNOŚCI OD WARTOŚCI W KOLUMNIE "WARTOŚĆ"

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