Lista kontaktów html/css [WebBrowser]

0

Witam.

Tworzę komunikator internetowy i chcę oprzeć listę kontaktów o komponent Webbrowser ze względu na większe możliwości niż np. Listbox (i pochodne). Kilka dni szukałem informacji jak można to zrealizować w Delphi w miarę optymalnie. Na początku wzorowałem się na komunikatorze AQQ, ponieważ całe okno główne ( i rozmowy) jest oparte o kod html/css któremu mogę się przyjrzeć.

Udało mi się w miarę sprawnie odizolować samą listę kontaktów i stworzyć na tej podstawie własną, by móc wyświetlić to w WebBrowser. W AQQ lista kontaktów składa się z kilku głównych plików (Body.htm -> całe ciało okna głównego zawierającego listę kontaktów, Item.htm -> zawiera zwykłą tabelę z itemem nie zaznaczonym, Selected.htm, to samo co item.htm, tylko że kontakt jest zaznaczony)

Dla testów stworzyłem sobie plik Body.htm z powieloną zawartością Item.htm i Selected.htm by zobaczyć jak to wygląda w Webbrowser. Wszystko chodzi ładnie pięknie, ale pojawiają się problemy:

Problemy:

a) Jak pobrać nazwę kontaktu po kliku/dwukliku na dany numer?
b) Jak zaznaczać dany kontakt? (czyli zamiast item.htm wyświetlić selected.htm)
c) Jak dodać/usuwać kontakty

Możliwe rozwiązania:

odnośnie a)

Nagłówek tabeli np. z pliku Item.htm wygląda tak:

<table onmousedown="window.status='_EDTR_ITEM_NORMAL_'" class="finito_out" cellpadding="0" cellspacing="0" onmousemove="window.status='CC_OVERITEM'" onmouseover="this.className='finito_in'" onmouseout="this.className='finito_out'; window.status='CC_NONE';" ondblclick="window.status='CC_EXECUTE'" onClick="window.status='CC_SELECTED'">

.....
Tutaj ciało itema
....
</table>
 

na razie wykrywam stan itemu przez zdarzenie:

procedure TForm1.WebBrowser1StatusTextChange(ASender: TObject;
 const Text: WideString);

dzięki temu mogę wykryć, czy kliknięto raz: onClick="window.status='CC_SELECTED' , czy dwa : ondblclick="window.status='CC_EXECUTE', ponieważ zmienna Text zwraca mi wartości jakie siedzą w window.status, ale jak wykryć, na jaki item kliknięto i jak pobrać nazwę użytkownika?

if Text='CC_EXECUTE' then
ShowMessage('Execute');

Myślałem, żeby zastosować funkcję Pos, która by szukała w zmiennej Text wystąpienia słowa np. _EXECUTE a zamiast CC trzymać numer kontaktu (123456_EXECUTE, zmieniać wartość CC_EXECUTE za pomocą StringReplace, przy dodawaniu itemów do listy) ale czy istnieje jakieś bardziej optymalne rozwiązanie? Ma ktoś lepszy pomysł?

odnośnie b)

nazwę kontaktu w pliku item.htm trzymam tak:

<span class="buddy">CAPTION</span>

Tu zaczynają się schody, prostackim rozwiązaniem byłoby robić to za pomocą StringReplace, wyszukiwać w Body.htm zawartość pliku item.htm, pobrać caption kontaktu w sposób np. z punktu a)
i zamienić StringReplacem występowanie tabelki z item.htm i odpowiednią nazwą na zawartość pliku selected.htm(Przy zmianie trzeba zmieniać CAPTION z pliku selected.htm na caption pobrany z punktu a) ) i odświeżenie WebBrowsera.

Odnośnie c)

Nie wiem jak jest to zrobione w AQQ, ale ja mam plan taki, by trzymać listę kontaktów np w tablicy rekordów, przyjmijmy:

type
TUsers=record
Nazwa:String;
Numer:Integer;
Selected:Boolean;
HTML:String;  //tu trzymałbym zawartość pliku item.htm (wiem, strasznie pamięciożerne)
end;

Items:Array of TUsers;

Następnie pętlą dodawałbym do pliku Body.htm zawartość items[i].HTML, a do tablicy dodawał/usuwał usera

Pytanie:

Powiem szczerze, że moje zaproponowane możliwości nie są zbyt dobrym rozwiązaniem, pewnie strasznie by obciążały komputer i jadły pamieć. Zwracam się do Was, może ktoś miał podobny problem, albo ma jakiś pomysł jakbym mógł to lepiej zrobić. Nie chodzi mi już nawet o te pliki Body.htm itd. ale ogółem jak zrealizować taką listę kontaktów w CSS/HTML na kontrolce Webbrowser z zaznaczaniem/dodawaniem/usuwaniem/pobieraniem informacji z danych itemów.

Proszę o jakieś pomysły.

Zależy mi na optymalnym i dość szybko działającym rozwiązaniu. Z tego co zauważyłem, to AQQ wczytuje wszystkie pliki html przy starcie do pamięci i na tym operuje, ponieważ podczas pracy programu gdy zmienie zawartość plików html, to AQQ reaguje dopiero po zmianie skina/restarcie

Pozdrawiam.

p.s Oczywiście pliki od AQQ wziąłem tylko dla testów i żeby się czegoś nauczyć, nie zamierzam ich wykorzystać w żadnym wypadku w swoim programie, jedynie chcę zaczerpnąć pomysł i przy tworzeniu własnego kodu html/css móc się na czymś wzorować.

0
Szymonss napisał(a)

[...] chcę oprzeć listę kontaktów o komponent Webbrowser ze względu na większe możliwości niż np. Listbox (i pochodne). [...]

jak dla mnie to komplikowanie sobie zycia... chociaz kazdy ma swoje zdanie.
na Twoim miejscu zrobil bym to w ten sposob: wlasny komponent! ;]
napisz cos pochodnego po np TPanel z jakimis przyciskami, labelami, menu, ogolnie co tylko chcesz, a potem ustawiaj im Align na alTop i kladz na panel ktory ma autosize=true.
w ten sposob bedziesz tworzyl kolejne "itemy".

0

przeciez <ort>wykozystujac </ort>listbox jak sie go samemu pomaluje mozna zrobic bardzo ciekawe rzeczy liste kontaktow tez nawet bylo to na forum opisane i moim zdaniem jest <ort>prostrze </ort>w wykonaniu niz opieranie sie na webbrowser

0

Dziękuję za odpowiedzi :)

Swego czasu oparłem listę o komponent Listview, itemy malowałem na jego Canvasie, i nawet ładnie to wyglądało, ale wolałbym mieć większe możliwości (+zawijane opisów -> Każdy item dostosowuje swoją wysokość do opisu). Wiem, że jeżeli chodzi o WebBrowsera, to pomysł ten ma wiele wad (np. pamięciożerność, reagowanie na zdarzenia ), ale można by ciekawe rzeczy dzięki niemu osiągnąć.

Jeżeli chodzi o pomysł z dynamicznymi panelami, to już jakiś czas temu wziąłem go pod uwagę, ale wolałbym, by użytkownik miał większą możliwość customizacji programu. (np. odpada pomysł z tłem na liście, bo panele go przysłonią). Na webbrowser(albo pochodnym) wystarczyła by zmiana jednego/dwóch plików, by użytkownik mógł dostosować wygląd aplikacji do swoich potrzeb :)

Mam znajomego, który listę maluje na canvasie Paintboxa, pomysł wydaje się strasznie trudny do realizacji, ale bardzo ładnie mu to wyszło.

Na chwilę obecną trzymam się nadal przy Webbrowserze, ale jestem otwarty na jakieś inne pomysły.
Jeżeli chodzi o Panele, to dość długo trwa tworzenie np. 200 Paneli (itemów) dynamicznie w pętli, więc ten pomysł wymagałby udoskonalenia. (Ale pomyślę jeszcze nad tym)

Proszę o jakieś propozycje odnośnie listy, albo wskazówki przy tworzeniu jej na Webbrowser :)

Pozdrawiam

p.s Wolę się trochę bardziej pomęczyć, ale żeby efekt w 100% mnie zadowalał :)

0
Szymonss napisał(a)

Jeżeli chodzi o Panele, to dość długo trwa tworzenie np. 200 Paneli (itemów) dynamicznie w pętli, więc ten pomysł wymagałby udoskonalenia.

no fakt, u mnie utworzenie 200 paneli bezposrednio na formie trwa troche ponad sekunde.
ale juz utworzenie ich na ukrytym panelu a nastepnie jego pokazanie - juz tylko ok 230ms.

co do listboxa i wysokosci itemow...
jest przeciez MeasureItem i tam mozna ustawic dowonla wysokosc dla danego item'a.
mozna tez przez:

sendMessage(listbox1.Handle,LB_SETITEMHEIGHT,index,height);
0

dokladnie jak mowi cimak w listboxie mozna dopasowywac wielkosc itemów do zawartości bylo nawet opisane na forum razem z kodem jak zrobic kompletna liste kontaktow na listboxie.
ja tam bym polecał ten sposób chociaż pomysł z malowaniem po paintboxie tez jest dobry. kiedys zrobiłem na paintboxie playliste do odtwarzacza mp3 z malowaniem zaznaczonych i odtwarzanych elementów. trzeba sie troche wiecej napisac ale efekt mozna osiągnąć bardzo fajny i przede wszystkim działa szybko.

0

Witam.

Dziękuję za odpowiedzi. Przekonaliście mnie, zrezygnowałem z WebBrowsera.

Zastosowałem pomysł podany przez użytkownika o nicku cimak, ale zamiast dynamicznie tworzonych komponentów TPanel użyłem TPaintbox i maluję poszczególne itemy.

Pozdrawiam.

0

Witam.

Przepraszam, że pozwoliłem sobię napisać post pod postem, ale myślę, że mój problem jest bliski zagadnieniu tu omawianym, a nie chcę tworzyć niepotrzebnie nowego tematu.

Otóż.. Interesuje mnie sposób usprawnienia pewnego procesu.

Przyjmijmy, tworzę dynamicznie 1000 Paintboxów w ten sposób:

for i := 0 to 1000 do
begin
   Paint:=TItems.Create(self);
   Paint.Parent:=ScrollBox1;
   //Paint.Align:=altop;

....

end;

Proces ten trwa bardzo szybko, ale gdy tylko odkomentuję linijkę:

//Paint.Align:=altop;

proces wydłuża się nawet o pół minuty. Jest to bardzo irytujące.
Nie chcę zbytnio kombinować z ustawianiem Width i Top ręcznie, ponieważ od Align na Altop jest już dużo rzeczy uzależnionych.
Proszę o pomoc.
Dziękuję :)

0

najwyrazniej uzycie align wymaga wielu obliczen i watpie zeby sie dalo to przyspieszyc.
u mnie na kompie (laptop 1,86GHz) samo utworzenie paintboxow (z alTop) trwa ok 10 sekund.
jesli na czas tworzenia paneli ukryje sie ScrollBoxa to mozna zaoszczedzic jakeis 4sec. zawsze cos.

ale chyba najlepiej nie korzystac w ogole z align i "recznie" poustawiac paintboxy.
chyba ze potem chcesz zeby ich rozmiar (lub ilosc) sie zmienial w trakcie dzialania programu ale i tak moze sie okazac ze procedurka ustawiajaca w petli wszystkie paintboxy bedzie szybsza niz align.

P.S. prawde mowiac to sie dziwie ze nie "postawiles" tego na zwylkym listboxie. tak czy inaczej wszystko recznie rysujesz a w listboxie byloby latwiej i szybciej.

//EDIT
zobacz:

ScrollBox1.Hide;
{..}
for i := 0 to 1000 do
   begin
     Paint[i]:=TPaintBox.Create(self);
     Paint[i].Parent:=ScrollBox1;
     Paint[i].Height:=50;
     Paint[i].Left:=0;
   end;
{u mnie utworzy to w  344ms}
{teraz ustawiamy...}
h:=0;
for i := 1 to 1000 do
   begin
     Paint[i].Width:=ScrollBox1.Width;
     Paint[i].Top:=h;
     h:=h+Paint[i].Height;
   end;
{samo ustawienie trwa przy ukrytym scrollbarze 406ms, przy widocznym: 2469ms}
0

a ja zapytam tak: Po co tworzyc tyle komponentów jak wystarczy wstawić jeden i odpowiednio go pomalować i problem z oczekiwaniem z głowy

0
puchi napisał(a)

a ja zapytam tak: Po co tworzyc tyle komponentów jak wystarczy wstawić jeden i odpowiednio go pomalować i problem z oczekiwaniem z głowy

Tutaj poszedłem trochę na łatwiznę, ponieważ wszystko mam już gotowe (zdarzenia OnClick onDblClick, wszelakie OnMousy mogę zastosować do odpowiedniego itema, i nie muszę się zbytnio martwić odnośnie zdarzeń jednego paintboxa np. który item zaznaczyć, pod jakim jest myszka, ustawiać wysokość itemów do tekstu w nim zawartego).

Dziękuję za odpowiedź. U mnie tyle to trwa, ponieważ oprócz tworzenia komponentu są jeszcze wykonywane inne polecenia (ustalanie Height odnośnie tekstu w nim zawiniętego, malowanie w onPaint itp.) Racja, pętla szybciej się wykonuje gdy ukryję na ten czas Scrollboxa. Pomyślę nad ręcznym ustawianiem pozycji i wielkości paintboxów. Na chwilę obecną zostawiam to jak jest teraz, ponieważ raczej mało kto będzie miał listę większą niż 1000 osób, ba nawet 300 osób. Dziękuję.

0
Szymonss napisał(a)

Tutaj poszedłem trochę na łatwiznę, ponieważ wszystko mam już gotowe (zdarzenia OnClick onDblClick, wszelakie OnMousy mogę zastosować do odpowiedniego itema, i nie muszę się zbytnio martwić odnośnie zdarzeń jednego paintboxa np. który item zaznaczyć, pod jakim jest myszka, ustawiać wysokość itemów do tekstu w nim zawartego).

z pozoru tylko trudne... mozesz zrobic tablice obiektow - itemow. potem tylko funcja w stylu itemAtPoint(x,y) i tyle.
ale z drugiej strony racja... wedlug mnie male prawdopodobienstwo ze ktos bedzie mial 1000osob. 100 to juz sporo.

0

Jeżeli już rozmawiamy o tych Paintboxach, to chciałbym prosić o pewną radę.

Wyświetlanie wiadomości swego czasu robiłem na komponencie THTMLViewer, lecz chciałbym to stworzyć na paintboxach (przezroczyste tło itp. na emotach tak bardzo mi nie zależy :), lecz mam już w głowie pomysł, jak ten problem rozwiązać). Na początku planowałem oprzeć to o tą samą zasadę co lista kontaktów, tzn tyle ile wiadomości, tyle utworzonych paintboxów, lecz jak wiadomo, nie jest to zbyt dobry pomysł. Przykładem może być np. historia rozmów, jak również inna potrzeba wczytania w trybie nagłym n paintboxów, gdzie n może być już spore (Nawet kilka, kilkanaście setek, bądź tysiąc dla dłuższych rozmów).

Myślę, żeby zastosować pomysł z jednym paintboxem.
Stworzyłbym sobie np. tablicę rekordów, w którym przechowywałbym ważne informacje, takie jak numer gg, jak i treść wiadomości. Problemem może być długa pętla w OnPaint, malująca poszczególne wiadomości (powtarzana przy każdym odmalowaniu okna...). Zależy mi na optymalnym i dość szybkim rozwiązaniu. Może ktoś robił coś podobnego, albo ma jakiś pomysł?

Pozdrawiam.

P.s Może trochę przesadzam z tym, że długa pętla w OnPaint by muliła, ale proszę o wypowiedź kogoś bardziej doświadczonego :)

0

w sumie nie musisz rysowac tyle rekordow ile wiadomosci i przesuwac paintboxa.
paintbox moze byc stalej wielkosci (w sensie ze nie zmienia sie w zaleznosci od ilosci rekordow) i rysujesz tylko te rekordy ktore beda w nim widoczne. rysowac 1000 rekordow jak widoczne bedzie 5 - bez sensu. a skoro juz rysujesz te, ktore beda widoczne w paintboxie to latwo to powiazac ze scrollbarem;]

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