TFuriousLabel - etykieta formatowana znacznikami HTML

10

Dziś chciałbym Wam zaprezentować efekt moich dwutygodniowych zmagań - komponent TFuriousLabel, przeznaczony dla środowisk Delphi, kompatybilny z Delphi7;


**TFuriousLabel - ** jest to graficzna etykieta (dziedzicząca z klasy TGraphicControl), umożliwiająca formatowanie tekstu (kodu etykiety) na podstawie znaczników HTML; Oprócz samego formatowania kodu, umożliwia także w oknie Inspektora Obiektów ustalić style fontów, osobno dla nagłówków i osobno dla paragrafów; Posiada także kilka innych ustawień, jak automatyczne dostosowywanie wysokości komponentu do zawartości, offset rysowanegog tekstu od góry komponentu, kolor tła komponentu (niestety bez przezroczystości), czy osobnego kursora dla linków;

Dzięki możliwości utalenia stylu fontów dla bloków kodu w oknie Inspektora Obiektów, większość rzeczy można "wyklikać", pozostawiając do zapisania jedynie kod ze znacznikami;

Komponent obsługuje stronę kodową ANSI, jednak przystosowanie źródła do poprawnej obsługi strony kodowej UTF-8 wymaga w kilku miejscach zamiany kilku funkcji, np. Length na UTF8Length, czy Delete na UTF8Delete - sprawdzałem pod Lazarusem i po takich modyfikacjach działa prawidłowo z multibajtowymi znakami;

Zrzut etykiety z przykładową zawartością:

furious-label-preview.png
font nagłówków: Oswald, font paragrafów: Ubuntu

Poniżej umieszczam krótki spis elementów komponentu, do których dorzucam obrazki, aby można łatwiej zrozumieć funkcjonalność labelka; Niektóre linki w poniższym opisie skrywają obrazki z załączników posta;


1. Obsługiwane znaczniki

Komponent obsługuje znaczniki zapisywane dokładnie w taki sam sposób, jak ma to miejsce w języku HTML; Treść znaczników jest w większości taka sama, jak w HTML, z wyjątkiem znacznika do oznaczenia przekreślonego tekstu; Poniżej lista obsługiwanych znaczników:

Bloki kodu
Znacznik Opis Znacznik
---------------- ---------------- ----------------
<h> otwiera zawartość nagłówka </h>
<p> otwiera zawartość paragrafu </p>
Formatowanie zawartości bloków kodu
---------------- ---------------- ----------------
Znacznik Opis Znacznik
---------------- ---------------- ----------------
<b> rozpoczyna pogrubienie tekstu </b>
<i> rozpoczyna pochylenie tekstu </i>
<u> rozpoczyna podkreślenie tekstu </u>
<s> rozpoczyna przekreślenie tekstu </s>
<a> rozpoczyna link </a>
Przykładowy kod komponentu:
<h><u>Lorem <a>ipsum</u></a> dolor sit amat</h>

<p><i>Lorem</i> ipsum dolor sit amet, consectetur adipiscing elit. Nullam condimentum, lacus eu sodales tempor, neque eros posuere eros, vitae tincidunt lacus <b>risus</b> ut mauris. <a>Nam auctor, purus quis sagittis cursus, velit mauris ultrices lacus, non egestas neque leo in odio. Quisque blandit tellus sit amet nunc porta, vel <i>tristique</i> lacus sodales.</a></p>

2. Właściwości komponentu

Komponent posiada sporo dedykowanych właściwości, nie dziedziczonych z bazowej klasy TGraphicControl; Oprócz dziedziczonych właściwości, takich jak Anchors, Hint, Visible itd., komponent wyposażony jest w poniższe pozycje, ustalające wygląd całego komponentu:

Właściwość Typ Opis
ActiveLinkUnderlined Boolean automatyczne podkreślanie całego linku, bez względu na formatowanie jego treści;
AutoFitHeight Boolean automatyczne dostosowywanie wysokości komponentu do jego fizycznej zawartości;
BackgroundColor TColor kolor tła komponentu;
Code TLabelCode łańcuch znaków z treścią (kodem) etykiety;
Cursor TCursor korsor dla zwykłego tekstu etykiety;
LinkCursor TCursor kursor dla wszystkich linków, zawartych w treści etykiety (wspólny dla nagłówków i paragrafów);
TopOffset Integer odstęp zawartości etykiety od górnej krawędzi komponentu (może być ujemny);
Właściwości Header i Paragraph są tej samej klasy bazowej (TLabelBlockFontGroup), więc ich zawartości są identyczne; Zawierają poniższe właściwości:
Właściwość Typ Opis
Align TLabelBlockAlign wyrównanie tekstu danego bloku (lbaLeft - do lewej, lbaRight - do prawej, lbaCenter - wycentrowanie);
LineSpacing Cardinal odstęp linii w pionie, jeżeli tekst pojedynczego bloku jest wieloliniowy;
Font.Name TFontName nazwa fontu dla kodu bloków;
Font.Size Integer rozmiar fontu dla kodu bloków;
Font.Color TColor kolor fontu dla kodu bloków;
LinkColors.Normal TColor kolor nieaktywnych linków w blokach;
LinkColors.Hover TColor kolor aktywnych linków w blokach;
Spacing.Top Cardinal odstęp ponad danym blokiem;
Spacing.Bottom Cardinal odstęp poniżej danego bloku;
Zrzut ekranu z listą wszystkich właściwości w oknie Inspektora Obiektów - oi-properties.png

3. Zdarzenia komponentu

Etykieta nie dziedziczy zbyt wiele zdarzeń z klasy bazowej; Komponent posiada kilka odziedziczonych zdarzeń, takich jak OnClick, OnDblClick, OnMouse* itd., a ponadto posiada trzy dedykowane zdarzenia:

Zdarzenie Opis
OnLinkEnter wywoływane podczas najechania kursorem na powierzchnię linku, przekazuje indeks linku spod kursora w parametrze ALinkIndex typu Integer;
OnLinkLeave wywoływane po zjechaniu kursorem z powierzchi linku, przekazuje indeks linku z którego zabrano kursor w parametrze ALinkIndex typu Integer;
OnLinkClick wywoływane po kliknięciu w dany link, przekazuje indeks klikniętego linku w parametrze ALinkIndex typu Integer;
Zrzut ekranu z listą wszystkich zdarzeń w oknie Inspektora Obiektów - oi-events.png

Podsumowanie

Zalety:

  • umożliwia bogate formatowanie zawartości etykiety, dając możliwość ustalenia stylu fontów osobno dla nagłówków i paragrafów,
  • idealnie nadaje się do prezentowania dłuższych tekstów w aplikacjach, dodając do nich klikalne linki (np. w instalatorach, instrukcjach obsługi itd.),
  • usuwa tekst niebędący wewnątrz znaczników <h></h> lub <p></p> (nie bierze takiego tekstu pod uwagę),
  • automatycznie "domyka" niezamknięte znaczniki, tak aby styl nie wyciekł do kolejnych bloków,
  • umożliwia zawijanie tekstu linków (czyli tworzenia linków wieloliniowych),
  • umożliwia rozróżnianie linków na podstawie ich indeksu,
  • obsługuje dowolne zainstalowane w systemie fonty,
  • posiada dwa własne okna dialogowe, możliwe do wykorzystania podczas projektowania aplikacji (do wygodnej edycji kodu etykiety i do edycji stylu fontów w blokach),
  • automatycznie zawija linie podczas rozciągania komponentu na boki (tak przerysowuje zawartość, aby jak najwięcej słów zmieściło się w poziomie),
  • w odróżnieniu od przeglądarek, nie łączy kilku znaków spacji w jeden, dzięki czemu można ustalać sobie większe odstępy między słowami;

Wady:

  • póki co jedynie dla środowisk Delphi (pracuję nad wersją dla Lazarusa),
  • obsługa jedynie kodowania ANSI (ale tak jak wspomniałem - bardzo łatwo i szybko można to zmienić),
  • występuje problem z niektórymi fontami i rysowaniem podkreślonych linków o takich fontach - z tego co wybadałem nie jest to problem kodu komponentu, a metody TCanvas.TextHeight, która czasem źle oblicza wysokość pogrubionego lub podkreślonego tekstu), co negatywnie wpływa na rysowanie słów; W nowszych środowiskach niż Delphi7 być może zostało to poprawione;
    W załączniku tflprevapp.zip podaję aplikację, umożliwiającą pobawienie się komponentem i zobaczenie jak wygląda w praktyce; Po prawej stronie w ListBox można zaobserwować dodające się na bieżąco pozycje - to logi wywoływanych zdarzeń komponentu z niesionymi przez nie informacjami;

Źródeł komponentu nie udostępniam - jeżeli ktoś jest zainteresowany źródłami komponentu, to zapraszam do wątku http://4programmers.net/Forum/Ogłoszenia_drobne/239917-tfuriouslabel_-_etykieta_formatowana_znacznikami_html;

Komponent poddaję Waszej ocenie - proszę o opinie na jego temat :]

0

Przydała by się możliwość zaznaczania tekstu.
Powodzenia w rozwoju komponentu ;)

0

Dwa wątki i wpis na mikroblogu ;)

No i dobrze, dzięki takim ludziom delphi jeszcze żyje, aż zaczyna mi być żal, że się z nim kiedyś rozstałem. Chociaż nie myślałeś o jakiejś wspólnej stronce zamiast stronek dla projektów kolejnych? Coś w rodzaju furious4delphi.net :D

0

Na szybko zrobiłem takie testy. Może coś nie załapałem?

Przykład 1

<p>paragraf 1</p>
<a>link 1</a>
<p>paragraf 2</p>

Wyświetla
przykład1.png
Zgubił się link 1

Przykład 2

<p>paragraf 1
<a>link 1</a>
<p>paragraf 2</p>

Wyświetla
przykład2.png
Myślałem, że pierwszy

się automatycznie domknie.

0
pelsta napisał(a)

Na szybko zrobiłem takie testy. Może coś nie załapałem?

@pelsta - tak, nie załapałeś :]

Znaczniki <h> i <p> służą do oznaczania bloków kodu, więc zawartość bloków musi być pomiędzy znacznikami nagłówka, albo znacznikami paragrafu; Wszystko co nie należy do nagłówków i paragrafów (czyli znajduje się poza znacznikami <h> lub <p>) jest pomijane/ignorowane i usuwane z kodu komponentu (jeżeli kod ustala się w specjalnym oknie dialogowym w inspektorze obiektów); Napisałem o tym w podsumowaniu:

furious programming napisał(a)
  • usuwa tekst niebędący wewnątrz znaczników <h></h> lub <p></p> (nie bierze takiego tekstu pod uwagę),

W Twoim pierwszym przykładzie umieściłeś link pomiędzy blokami, więc jest on pomijany; Natomiast w drugim przykładzie nie zamknąłeś znacznika paragrafu, więc cała zawartość jest traktowana jako jeden paragraf, a drugi znacznik <p> jest traktowany jako zwykły tekst, dlatego że bloków kodu nie można zagnieżdżać;

Zobacz sobie na standardowy kod w aplikacji testowej - tam są powstawiane znaczniki i widać jak się nimi posługiwać; Ale jakby co to poniżej umieszczam przykład kodu:

<h>to jest pierwszy nagłówek</h>

to zostanie pominięte, bo nie należy do żadnego bloku

<p>to jest pierwszy paragraf</p>
<p>to jest drugi paragraf</p>

to też zostanie pominięte

<h>to jest drugi nagłówek</h>

<p>to jest trzeci paragraf</p>

W przykładzie są dwie linijki, które nie należą ani do żadnego nagłówka, ani do żadnego paragrafu, więc one zostaną pominięte; Wyświetlone zostanie jedynie to, co jak wspomniałem znajdować się będzie pomiędzy poprawnie zapisanymi (czyli otwartymi i zamkniętymi) znacznikami <h> lub <p>;

pelsta napisał(a)

Myślałem, że pierwszy <p> się automatycznie domknie.

Nie - domykane automatycznie są znaczniki stylów, a nie znaczniki bloków kodu; Czyli na koniec bloku domykane są automatycznie znaczniki <b>, <i>, <u>, <s> i <a>, tak jak napisałem w pierwszym poście; Także napisałem o tym w podsumowaniu:

furious programming napisał(a)
  • automatycznie "domyka" niezamknięte znaczniki, tak aby styl nie wyciekł do kolejnych bloków,

Nie rozumiem w czym problem - przecież kod etykiety zapisuje się dokładnie tak samo, jak i kod HTML; Tyle tylko że mój label usuwa tekst pomiędzy znacznikami bloków kodu, a przeglądarki mimo wszystko go wyświetlają; Ale po to przygotowałem tester, aby obczaić jak z tego korzystać :]

0

I na co czekasz? Strona, dokumentacja, przykłady, reklama, PayPal / Stripe i jesteś do przodu. 4p to chyba nieodpowiednie miejsce na handlowanie, zwłaszcza takim fajnym komponentem.

0

Czekam aż komponent dla Lazarusa zacznie mnie słuchać :D

Póki co wrzucam tutaj, bo dziś świeżo skończyłem pracę nad nim i testy; Rozreklamuje się lepiej, jak będę miał komponent także dla Lazarusa, a ten dla Delphi sprawdzę na nowszych środowiskach niż Delphi7 z dorobioną obsługą UTF-8; W Lazarusie ona działa, ale Delphi7 nie posiada funkcji do obsługi łańcuchów z multibajtowymi znakami (wspomniałem o nich w opisie);

To dopiero początek mojej przygody z komponentami - na labelku na pewno się nie skończy :]

0

Podziwiam twoje zaparcie do programowania oraz dzielenie się tym z innymi. Też kiedyś napisałem komponenty, które są skinowane, przeźroczyste, przybierające dowolne kształty itp. więc wiem ile trzeba czasem się na męczyć z tym VCL-em. Miałem zamiar kiedyś opublikować je, ale nigdy nie było czasu dopiąć do końca, a wiem jak łatwo wytykane są jakiekolwiek delikatne błędy. Wole więc nie pokazywać niedoróbek. W niedziele chłopak mi się urodził, więc raczej czasu będzie mniej niż więcej. Powodzenia w dalszych pracach.

0

Mi brakuje jednego znacznika do formatowania kodu - font, zarówno dla ustawiania koloru jak i wielkości oraz mordy czcionki. Byłby to duży plus wg mnie.

1

Fajna rzecz, dobra robota! A jak wyglada porownanie z konkurencja? Np http://www.infintuary.org/stlabel.php

1

Dzięki za odpowiedzi; Postaram się pokrótce odpowiedzieć na pytania;

abrakadaber napisał(a)

Mi brakuje jednego znacznika do formatowania kodu - font, zarówno dla ustawiania koloru jak i wielkości oraz mordy czcionki.

Nie ma tego znacznika, dlatego że przyjąłem, że wszelkie style fontów ustawiane będą w oknie Inspektora Obiektów; Oczywiście osobno dla nagłówków i osobno dla paragrafów;

mca64 napisał(a)

A jak wyglada porownanie z konkurencja?

Jeżeli porównując z tym komkretnie komponentem, do którego podałeś link, to TFuriousLabel nie wypada najgorzej;

Z tego co widzę w aplikacji testowej, komponent TMDLabel nie umożliwia zawijania linków - a mój to potrafi i to bardzo dobrze, co widać np. na zrzucie z pierwszego posta;

Po drugie, TMDLabel pozwala na automatyczne dostosowywanie szerokości komponentu, zaś mój umożliwia dopasowanie wysokości, które automatycznie zmienia się wraz z rozciąganiem komponentu na boki; Dzięki temu zawartość zawsze dopasowuje się do szerokości komponentu, a wysokość może (ale nie musi) dopasowywać się do widocznej zawartości;

Po trzecie, nie widzę możliwości w aplikacji testowej na wybranie odstępów pomiędzy liniami tekstu etykiety; TFuriousLabel umożliwia ustalenie wielu różnych odstępów:

  • odstęp od górnej krawędzi komponentu górnej krawędzi tekstu - przydatne, jeśli pierwszym blokiem etykiety jest nagłówek z dużym fontem, którego wysokość to np. 50px, ale góra liter zaczyna się np. od 10px od góry, pozostawiając 10px przerwy od góry komponentu; Dzięki ustawieniu tej właściwości można dosunąć górę liter do góry komponentu;
  • odstęp pomiędzy liniami tekstu w pojedynczym bloku - linie tekstu np. w paragrafie domyślnie posiadają odstęp 0px, ale można go dowolnie zwiększyć, aby rozsunąć linie tekstu;
  • odstępy pomiędzy blokami tekstu - blokom można nadać odstęp od góry i od dołu (coś jak w CSS styl padding-top i padding-bottom dla np. znacznika <p>);

Po czwarte sprawdziłem źródła tego komponentu i tokeny słów, spacji i znaczników to dość duże klasy, zawierające dość dużo informacji:

TWordInfo = class
protected
  FText: WideString;
  FRect: TRect;
  FFontStyle: TFontStyles;
  FLinkID: Integer;
  FFontColor: TColor;
  FBackColor: TColor;
  FSize: Integer;
  FWordHeight: Integer;
  FWordWidth: Integer;
public
  constructor Create(AText: WideString; AFontStyle: TFontStyles; AFontColor: TColor; AFontSize: Integer; ABackColor: TColor; ALinkID: Integer);
  procedure SetWidth(XPos: Integer; TextRC: TRect);
  procedure AdjustWidth(XPos: Integer);
  procedure SetLineHeight(LineTop, LineHeight: Integer);
  procedure SetXOffset(Offset: Integer);
  procedure Add(ws: WideString);
end;

Klasy spacji, formatu (znaczników), przerw (break), tabów i DSP (cokolwiek to jest) dziedziczą z powyższej klasy, więc zawierają stosunkowo dużo informacji; W komponencie TFuriousLabel budowana jest statyczna mapa tokenów (budowana tylko w przypadku zmiany szerokości komponentu), składająca się nie z klas, a z pointerów na poniższe rekordy:

type
  PLabelCodeWordToken = ^TLabelCodeWordToken;
  TLabelCodeWordToken = record
    Word: AnsiString;
    Position: TPoint;
    Dimensions: TPoint;
  end;

type
  PLabelCodeSpaceToken = ^TLabelCodeSpaceToken;
  TLabelCodeSpaceToken = record
    Position: TPoint;
    Count: Integer;
    WidthInPixels: Integer;
  end;

type
  PLabelCodeMarkerToken = ^TLabelCodeMarkerToken;
  TLabelCodeMarkerToken = record
    Style: TLabelCodeFontStyle;  //enum
    Operation: TLabelCodeFontStyleOperation;  // enum
    PreviousStyle: PFontStyles;
  end;

type
  PLabelCodeToken = ^TLabelCodeToken;
  TLabelCodeToken = record
    Kind: TLabelCodeTokenKind;  //enum
    Content: Pointer;  // tu zostaje wpisany pointer na jeden z trzech powyższych rekordów
  end;

Tak - i to wszystko; Cała mapa tokenów budowana jest z dynamicznie tworzonych i alokowanych rekordów, dzięki czemu mapa zajmuje mało pamięci i budowana jest bardzo szybko; Zrzut labelka z pierwszego posta zawiera treść, która tokenizowana jest w około 350 cykli (na moim sprzęcie jest to około 0.01ms); Następnie na bazie mapy tokenów budowana jest mapa linków - także jako lista dynamicznie alokowanych rekordów; Z tej mapy linków korzysta zdarzenie OnMouseMove aby sprawdzić, czy kursor znajduje się nad obszarem linku; Działa to wyjątkowo szybko, bo mapa linków posiada jedynie rekordy odpowiadające ilości linków, a każdy z rekordu linku posiada listę obszarów (areas typu TRect) - sprawdzane jest czy kursor znajduje się wewnątrz któregoś z obszaru linku i jeśli tak - zwracany jest indeks linku;

Z racji tej, że cały mechanizm tokenizowania treści labelka opiera się na dynamicznie alokowanych danych, sprawdzałem kod komponentu za pomocą FastMM - brak jakichkolwiek wycieków; Dzięki tak zbudowanym mapom tokenów i linków, rysowanie zawartości jest bardzo szybkie i krótkie w implementacji;

Z innych rzeczy, które można porównać pomiędzy tymi komponentami (najpierw TMDLabel):

  • TMDLabel posiada więcej znaczników, służących do formatowania tekstu

  • TMDLabel posiada specjalne sekwencje do wstawiania specjalnych znaków, np. &euro,

  • TMDLabel posiada obsługę wypunktowania, w TFuriousLabel brak takiej funkcji,

  • TMDLabel posiada możliwość nadania koloru tekstu i tła dla pojedynczych słów,
    Plusy komponentu TFuriousLabel w porównaniu do TMDLabel:

  • TFuriousLabel jest kompatybilny z Delphi7, zaś TMDLabel wymaga modyfikacji, bo nie daję się w tym IDE skompilować,

  • TFuriousLabel obsługuje UTF-8 (ale nie w Delphi7), więc wstawiać można dowolne znaki (również < i >, bez zabawy w sekwencje jak &euro),

  • TFuriousLabel umożliwia wyklikanie stylu fontów i kilku innych ważnych właściwości w oknie Inspektora Obiektów,

  • TFuriousLabel umożliwia aranżację bloków tekstu przez wybranie wyrównania tekstu (do lewej, prawej lub środka) osobno dla nagłówków i paragrafów,

  • TFuriousLabel umożliwia ustalenie odstępów pomiędzy zarówno kolejnymi blokami kodu, jak i pomiędzy pojedynczymi liniami w danym bloku kodu,

  • TFuriousLabel umożliwia ustalenie offsetu od góry komponentu przy rysowaniu tekstu,

  • TFuriousLabel umożliwia automatyczne dostosowywanie wysokości komponentu do jego zawartości,

  • TFuriousLabel z racji bogatego zbioru właściwości zwiększa czytelność kodu (dla tekstu) - w kodzie wpisywane są jedynie znaczniki, które współpracują z właściwościami komponentu, więc nie zaciemniają kodu,

  • TFuriousLabel umożliwia zawijanie linków i ogólnie tekstu, czego (z tego co zobaczyłem w aplikacji testowej) komponent TMDLabel nie obsługuje,

  • TFuriousLabel pozwala na wybranie stylu efektu aktywacji linków - albo podkreśla cały link, albo wykorzystuje formatowanie tekstu linku,

  • TFuriousLabel posiada dwa dedykowane okna dialogowe, umożliwiające wygodne wprowadzenie kodu komponentu oraz wygodne ustalenie stylu fontu dla bloków nagłówków (Header.Font) i paragrafów (Paragraph.Font),

  • TFuriousLabel posiada trzy właściwości, pozwalające na obsługę linków (najechanie kursorem, zdjęcie kursora i kliknięcie w link),

  • kilka innych rzeczy, które opisałem w pierwszym poście;
    Jak widać te dwa komponenty mają zupełnie różną funkcjonalność; Swój komponent zaprogramowałem tak, aby spełniałem moje oczekiwania - stworzyłem go aby samemu z niego skorzystać w nowym projekcie; Całość dobrze przemyślałem i zaprojektowałem TFuriousLabel tak, aby móc wprowadzić czytelny kod (z prostymi znacznikami), a resztę wyklikać w oknie Inspektora Obiektów; Czyli chciałem uzyskać coś na kształt rozdzielania HTML i CSS na stronach WWW, gdzie kod komponentu to odpowiednik HTML, a właściwości komponentu w oknie OI to odpowiednik CSS - wyszło dla mnie idealnie;

A z racji tej, że w swoim projekcie bloki tekstu będą tego samego fontu - brak znaczników do ustalania fontu dla poszczególnych słów w danym bloku kodu; Dodanie wypunktowania wcale nie stanowiłoby problemu, jednak to co jest obecnie mnie wystarczy;


To w sumie tyle, jeśli chodzi o wytłumaczenie kształtu i funkcjonalność komponentu TFuriousLabel - mam nadzieję, że teraz wszystko jest jasne; A jeżeli ktoś nadal nie widzi jakichś dużych róznic w tych dwóch komponentach (TDMLabel i TFuriousLabel), to najlepszym wyjściem będzie pobranie dwóch aplikacji testowych i pobawienie się nimi - różnice będą widoczne.

0

@furious programming Widząc teraz to http://4programmers.net/Forum/Og%C5%82oszenia_drobne/239946-odsprzedam_tfuriouslabel zastanawia mnie jedno - jak stoisz z licencjonowaniem?

2

Wątku już nie ma - założył go ten sam anonim, którego post usunąłem z tego wątku - to zwykły hejter i troll, myśli że mi na złość zrobi umieszczając kłamliwe posty, z wyimaginowaną rzeczywistością;


Komponent nie jest opatrzony jakąś szczególną licencją - można używać komponentu w dowolnych zamkniętych aplikacjach, zarówno darmowych jak i komercyjnych (oprócz projektów otwartych); Źródła można dowolnie modyfikować, ale używać we własnych, zamkniętych produkcjach; Wystarczą mi prawa autorskie i kilka punktów dotyczących wykorzystania komponentu;

Tu muszę zaznaczyć - podobnie jak z projektem TreeStructInfo, komponent TFuriousLabel powstał z potrzeby; Potrzebowałem takiego komponentu do własnej, nowej aplikacji, więc go stworzyłem; TreeStructInfo pochłonął dużo więcej czasu (14 miesięcy) a mimo to go rozdałem za darmo; Ale ten komponent targetowany jest dla Delphi, nie Lazarusa (choć postaram się wersję dla niego skończyć), więc i grono zainteresowanych teoretycznie powinno być większe.

1

Gratuluje zacięcia i doprowadzenia projektu do użyteczności - a to wcale nie jest takie proste ;-)
Ale mam kilka uwag, mało znaczących oczywiście.

furious programming napisał(a):

Dzięki za odpowiedzi; Postaram się pokrótce odpowiedzieć na pytania;

abrakadaber napisał(a)

Mi brakuje jednego znacznika do formatowania kodu - font, zarówno dla ustawiania koloru jak i wielkości oraz mordy czcionki.

Nie ma tego znacznika, dlatego że przyjąłem, że wszelkie style fontów ustawiane będą w oknie Inspektora Obiektów; Oczywiście osobno dla nagłówków i osobno dla paragrafów;

Zgadzam się z przedmówca - ten znacznik to must have. Jeśli można, to sugeruje abyś jeszcze raz przemyślał te kwestie. Zawsze możesz zostawić sterowania z OI jako domyślny styl, ale to co napisane w HTML powinni mieć pierwszeństwo.
Mam własną opinie na temat OI, ale zostawmy to ;-)

mca64 napisał(a)

A jak wyglada porownanie z konkurencja?

Jeżeli porównując z tym komkretnie komponentem, do którego podałeś link, to TFuriousLabel nie wypada najgorzej;

Z tego co widzę w aplikacji testowej, komponent TMDLabel nie umożliwia zawijania linków - a mój to potrafi i to bardzo dobrze, co widać np. na zrzucie z pierwszego posta;

Eeee... muszę Cie sprostować; potrafi zawijać linki i tekst sformatowany - tylko domyślnie label jest ustawiony w tryb AutoSize i wtedy automatycznie zwiększa swoja szerokość, a nie łamie linie.
Masz u siebie AutoSize?

Po drugie, TMDLabel pozwala na automatyczne dostosowywanie szerokości komponentu, zaś mój umożliwia dopasowanie wysokości, które automatycznie zmienia się wraz z rozciąganiem komponentu na boki; Dzięki temu zawartość zawsze dopasowuje się do szerokości komponentu, a wysokość może (ale nie musi) dopasowywać się do widocznej zawartości;

W MDLabel jest identycznie - musisz odznaczyć AutoSize i już.

Po trzecie, nie widzę możliwości w aplikacji testowej na wybranie odstępów pomiędzy liniami tekstu etykiety; TFuriousLabel umożliwia ustalenie wielu różnych odstępów:

  • odstęp od górnej krawędzi komponentu górnej krawędzi tekstu - przydatne, jeśli pierwszym blokiem etykiety jest nagłówek z dużym fontem, którego wysokość to np. 50px, ale góra liter zaczyna się np. od 10px od góry, pozostawiając 10px przerwy od góry komponentu; Dzięki ustawieniu tej właściwości można dosunąć górę liter do góry komponentu;
  • odstęp pomiędzy liniami tekstu w pojedynczym bloku - linie tekstu np. w paragrafie domyślnie posiadają odstęp 0px, ale można go dowolnie zwiększyć, aby rozsunąć linie tekstu;
  • odstępy pomiędzy blokami tekstu - blokom można nadać odstęp od góry i od dołu (coś jak w CSS styl padding-top i padding-bottom dla np. znacznika <p>);

Można polemizować, osobiście uważam ze w takim przypadku lepiej użyć THTMLViewer

Po czwarte sprawdziłem źródła tego komponentu i tokeny słów, spacji i znaczników to dość duże klasy, zawierające dość dużo informacji:

TWordInfo = class
protected
  FText: WideString;
  FRect: TRect;
  FFontStyle: TFontStyles;
  FLinkID: Integer;
  FFontColor: TColor;
  FBackColor: TColor;
  FSize: Integer;
  FWordHeight: Integer;
  FWordWidth: Integer;
public
  constructor Create(AText: WideString; AFontStyle: TFontStyles; AFontColor: TColor; AFontSize: Integer; ABackColor: TColor; ALinkID: Integer);
  procedure SetWidth(XPos: Integer; TextRC: TRect);
  procedure AdjustWidth(XPos: Integer);
  procedure SetLineHeight(LineTop, LineHeight: Integer);
  procedure SetXOffset(Offset: Integer);
  procedure Add(ws: WideString);
end;

Klasy spacji, formatu (znaczników), przerw (break), tabów i DSP (cokolwiek to jest) dziedziczą z powyższej klasy, więc zawierają stosunkowo dużo informacji; W komponencie TFuriousLabel budowana jest statyczna mapa tokenów (budowana tylko w przypadku zmiany szerokości komponentu), składająca się nie z klas, a z pointerów na poniższe rekordy:

type
  PLabelCodeWordToken = ^TLabelCodeWordToken;
  TLabelCodeWordToken = record
    Word: AnsiString;
    Position: TPoint;
    Dimensions: TPoint;
  end;

type
  PLabelCodeSpaceToken = ^TLabelCodeSpaceToken;
  TLabelCodeSpaceToken = record
    Position: TPoint;
    Count: Integer;
    WidthInPixels: Integer;
  end;

type
  PLabelCodeMarkerToken = ^TLabelCodeMarkerToken;
  TLabelCodeMarkerToken = record
    Style: TLabelCodeFontStyle;  //enum
    Operation: TLabelCodeFontStyleOperation;  // enum
    PreviousStyle: PFontStyles;
  end;

type
  PLabelCodeToken = ^TLabelCodeToken;
  TLabelCodeToken = record
    Kind: TLabelCodeTokenKind;  //enum
    Content: Pointer;  // tu zostaje wpisany pointer na jeden z trzech powyższych rekordów
  end;

No dobrze, ale ja np. znacznie bardziej wole klasy niż wskaźniki na rekordy :).
A zużycie pamięci? W końcu to label a nie silnik renderujący dla przeglądarki - ergo, to naprawdę pomijalna sprawa na dziś...

Tak - i to wszystko; Cała mapa tokenów budowana jest z dynamicznie tworzonych i alokowanych rekordów, dzięki czemu mapa zajmuje mało pamięci i budowana jest bardzo szybko; Zrzut labelka z pierwszego posta zawiera treść, która tokenizowana jest w około 350 cykli (na moim sprzęcie jest to około 0.01ms); Następnie na bazie mapy tokenów budowana jest mapa linków - także jako lista dynamicznie alokowanych rekordów; Z tej mapy linków korzysta zdarzenie OnMouseMove aby sprawdzić, czy kursor znajduje się nad obszarem linku; Działa to wyjątkowo szybko, bo mapa linków posiada jedynie rekordy odpowiadające ilości linków, a każdy z rekordu linku posiada listę obszarów (areas typu TRect) - sprawdzane jest czy kursor znajduje się wewnątrz któregoś z obszaru linku i jeśli tak - zwracany jest indeks linku;

Z racji tej, że cały mechanizm tokenizowania treści labelka opiera się na dynamicznie alokowanych danych, sprawdzałem kod komponentu za pomocą FastMM - brak jakichkolwiek wycieków; Dzięki tak zbudowanym mapom tokenów i linków, rysowanie zawartości jest bardzo szybkie i krótkie w implementacji;

Z innych rzeczy, które można porównać pomiędzy tymi komponentami (najpierw TMDLabel):

  • TMDLabel posiada więcej znaczników, służących do formatowania tekstu

  • TMDLabel posiada specjalne sekwencje do wstawiania specjalnych znaków, np. &euro,

  • TMDLabel posiada obsługę wypunktowania, w TFuriousLabel brak takiej funkcji,

  • TMDLabel posiada możliwość nadania koloru tekstu i tła dla pojedynczych słów,
    Plusy komponentu TFuriousLabel w porównaniu do TMDLabel:

  • TFuriousLabel jest kompatybilny z Delphi7, zaś TMDLabel wymaga modyfikacji, bo nie daję się w tym IDE skompilować,

  • TFuriousLabel obsługuje UTF-8 (ale nie w Delphi7), więc wstawiać można dowolne znaki (również < i >, bez zabawy w sekwencje jak &euro),

MDLabel tez obsługuje Unicode. Obrazek:
http://snap.ashampoo.com/c3GK3ERX

  • TFuriousLabel umożliwia wyklikanie stylu fontów i kilku innych ważnych właściwości w oknie Inspektora Obiektów,
  • TFuriousLabel umożliwia aranżację bloków tekstu przez wybranie wyrównania tekstu (do lewej, prawej lub środka) osobno dla nagłówków i paragrafów,
  • TFuriousLabel umożliwia ustalenie odstępów pomiędzy zarówno kolejnymi blokami kodu, jak i pomiędzy pojedynczymi liniami w danym bloku kodu,
  • TFuriousLabel umożliwia ustalenie offsetu od góry komponentu przy rysowaniu tekstu,
  • TFuriousLabel umożliwia automatyczne dostosowywanie wysokości komponentu do jego zawartości,
  • TFuriousLabel z racji bogatego zbioru właściwości zwiększa czytelność kodu (dla tekstu) - w kodzie wpisywane są jedynie znaczniki, które współpracują z właściwościami komponentu, więc nie zaciemniają kodu,
  • TFuriousLabel umożliwia zawijanie linków i ogólnie tekstu, czego (z tego co zobaczyłem w aplikacji testowej) komponent TMDLabel nie obsługuje,

No, nieprawda niestety...

  • TFuriousLabel pozwala na wybranie stylu efektu aktywacji linków - albo podkreśla cały link, albo wykorzystuje formatowanie tekstu linku,
  • TFuriousLabel posiada dwa dedykowane okna dialogowe, umożliwiające wygodne wprowadzenie kodu komponentu oraz wygodne ustalenie stylu fontu dla bloków nagłówków (Header.Font) i paragrafów (Paragraph.Font),

Ale MDLAbel wspiera znacznik FONT i po ptasiach...

  • TFuriousLabel posiada trzy właściwości, pozwalające na obsługę linków (najechanie kursorem, zdjęcie kursora i kliknięcie w link),

A to fajne jest.

  • kilka innych rzeczy, które opisałem w pierwszym poście;
    Jak widać te dwa komponenty mają zupełnie różną funkcjonalność; Swój komponent zaprogramowałem tak, aby spełniałem moje oczekiwania - stworzyłem go aby samemu z niego skorzystać w nowym projekcie; Całość dobrze przemyślałem i zaprojektowałem TFuriousLabel tak, aby móc wprowadzić czytelny kod (z prostymi znacznikami), a resztę wyklikać w oknie Inspektora Obiektów; Czyli chciałem uzyskać coś na kształt rozdzielania HTML i CSS na stronach WWW, gdzie kod komponentu to odpowiednik HTML, a właściwości komponentu w oknie OI to odpowiednik CSS - wyszło dla mnie idealnie;

OK, ale sam przyznasz po zastanowieniu ze brak znacznika font jest ciut sztywne.

A z racji tej, że w swoim projekcie bloki tekstu będą tego samego fontu - brak znaczników do ustalania fontu dla poszczególnych słów w danym bloku kodu; Dodanie wypunktowania wcale nie stanowiłoby problemu, jednak to co jest obecnie mnie wystarczy;


To w sumie tyle, jeśli chodzi o wytłumaczenie kształtu i funkcjonalność komponentu TFuriousLabel - mam nadzieję, że teraz wszystko jest jasne; A jeżeli ktoś nadal nie widzi jakichś dużych róznic w tych dwóch komponentach (TDMLabel i TFuriousLabel), to najlepszym wyjściem będzie pobranie dwóch aplikacji testowych i pobawienie się nimi - różnice będą widoczne.

0

Gratuluje zacięcia i doprowadzenia projektu do użyteczności - a to wcale nie jest takie proste ;-)

Dziękuję, choć nie żebym zadzierał nosa, ale jakoś szczególnie trudne w implementacji to nie było :]

Ale mam kilka uwag, mało znaczących oczywiście.

Wszystkie uwagi są znaczące - dają mi wiele do myślenia;

Zgadzam się z przedmówca - ten znacznik to must have. Jeśli można, to sugeruje abyś jeszcze raz przemyślał te kwestie. Zawsze możesz zostawić sterowania z OI jako domyślny styl, ale to co napisane w HTML powinni mieć pierwszeństwo.
Mam własną opinie na temat OI, ale zostawmy to

Oczywiście zgadzam się - nie ma wątpliwości, że możliwość formatowania poszczególnych słów do ważna funkcja; Jednak tak jak pisałem wcześniej - komponent zaprogramowałem tak, aby spełniał moje wymagania;

Tyle że tu jest problem - ja potrzebuję skromnej funkcjonalności (choć może i nie jest taka skromna), ale znowu do uniwersalizmu ma się to nijak; Różne mogą być wymagania w różnych projektach, więc to co jest obecnie zaimplementowane może się okazać zbyt małą funkcjonalnością; Mnie wystarczą proste znaczniki (choć ze znacznika <s> do przekreślenia tekstu pewnie i tak nie skorzystam), ale innym to będzie za mało; Trudno tu pogodzić te dwie kwestie - uznałem więc, że nie ma sensu tworzyć komponentu z dużo większą funkcjonalnością, niż jest mi to osobiście potrzebne;

Eeee... muszę Cie sprostować; potrafi zawijać linki i tekst sformatowany - tylko domyślnie label jest ustawiony w tryb AutoSize i wtedy automatycznie zwiększa swoja szerokość, a nie łamie linie.
Masz u siebie AutoSize?

A to przepraszam - sprawdziłem aplikację testową na szybko i widać nie przetestowałem solidnie TMDLabel; Gdzieś mi zawijanie linii umknęło;

Mam u siebie właściwość AutoFitHeight, która automatycznie dostosowuje wysokość komponentu; Dodatkowo są kotwice (dziedziczone Anchors), dzięki którym label może dostosowywać swoją szerokość do okna rodzica (formularza, panelu) i odpowiednio dopasowywać tekst do szerokości komponentu; Jeśli przez rozciąganie komponentu zmniejszy się ilość linii, to jego wysokość zostanie dopasowana; Tak samo w drugą stronę; Ale tu działa to odwrotnie - w TMDLabel automatycznie dostosowywana jest szerokość, a w TFuriousLabel wysokość;

Można polemizować, osobiście uważam ze w takim przypadku lepiej użyć THTMLViewer

Nie bawiłem się THTMLViewer, ale domyślam się do czego służy; Mój komponent jest celowany w zwykłe etykiety, gdzie styl fontów dla bloków ma być z założenia możliwy do wyklikania, a treść etykiety ma być formatowana tylko za pomocą krótkich, jednoliterowych znaczników, np. <b> czy <a>; Po prostu moje oczekiwania wobec tego komponentu są inne, niż oczekiwania ogółu, jeśli ogół ma na myśli komponent uniwersalny;

Co do różnych odstępów - to jest mnie potrzebne, aby dobrze móc wypozycjonować rysowany tekst labelka; Jeśli wszystkie odstępy ustawi się na 0px - komponent będzie rysował tekst tak, jakby w ogólnie nie było takich opcji (ustalania odstępów);

No dobrze, ale ja np. znacznie bardziej wole klasy niż wskaźniki na rekordy :).

No nie mów, że nie lubisz zabawy ze wskaźnikami :D

Nie żebym był jakimś fanboy'em wskaźników, ale jakoś pasowało mi w tym wypadku się nimi pobawić; Oczywiście nic się nie straci, jeśli zamieni się rekordy na klasy - zmieni się trochę ich obsługa i to w sumie tyle;

A zużycie pamięci? W końcu to label a nie silnik renderujący dla przeglądarki - ergo, to naprawdę pomijalna sprawa na dziś...

Nie badałem dokładnie zużycia pamięci - bardziej interesowała mnie szybkość rysowania zawartości komponentu, dlatego że zbyt powolne malowanie tekstu zepsułoby końcowy efekt, już w aplikacji;

Ale nie trudno to sobie policzyć, tym bardziej widząc w moim poprzednim poście deklaracje rekordów tokenów; Każdy token jest typu PLabelCodeToken i może zawierać wskazanie na jeden z trzech konkretnych rekordów (słowa, odstępu lub znacznika); Każde słowo to PLabelCodeWordToken, każdy odstęp (kilkuznakowy też) to PLabelCodeSpaceToken, a każdy znacznik (oprócz <h> i <p>) to PLabelCodeMarkerToken; Znając ilość słów i odstępów łatwo można policzyć; Mapa linków budowana jest w podobny sposób - także z rekordów;

Jak znajdę chwilę to podam konkretne liczby dla danej zawartości - rozmiar mapy tokenów i rozmiar mapy linków;

Ale MDLAbel wspiera znacznik FONT i po ptasiach...

Tak, bo został do tego przygotowany; TFuriousLabel nie obsługuje tego znacznika, bo takiej funkcji nie potrzebowałem; W sumie to co potrzebowałem to jest - a co do reszty to... będzie można dodać, jak ktoś będzie go chciał rozwijać :D

A to fajne jest.

Inna obsługa linków raczej nie przyszła mi do głowy; W sumie to nie wiem jak mogło by to wyglądać inaczej; Do zmiany koloru i stylu tekstu linków i tak konieczne jest pobieranie indeksu linku; Dodatkowo ta funkcja udostępniona jest przez zdarzenia - można ją wykorzystać np. do zmiany hintu komponentu według danego linku; Sprawdziłem to - nawet fajny efekt wychodzi;

OK, ale sam przyznasz po zastanowieniu ze brak znacznika font jest ciut sztywne.

Tak, sztywne i kurczące funkcjonalność; Ale cóż - mnie tyle wystarczy, więc i brak takiego znacznika.

1

Gratki ukończenia kolejnego ciekawego projektu. Przyznam, że nie udało mi się wykoleić parsera, choć na początku wtf'em było IMHO pomijanie tekstu bez żadnego znacznika, ale skoro to nie bug tylko ficzer to już tak musi być :P. Z rzeczy, które życzył bym sobie jeszcze znaleźć w tym komponencie jest dodanie jakiegoś znaku do escape'owania tak aby móc np. umieścić czysty znacznik HTML bez wstawiania spacji. Mogła by to być opcjonalna właściwość - czy taki specjalny znak honorować czy nie. Wydaje mi się, że nie było by to trudne w implementacji.

0

Przyznam, że nie udało mi się wykoleić parsera [...]

Tokenizer dość sprawnie radzi sobie z różnymi tekstami, nawet tymi najbardziej zagmatwanymi; Radzi sobie z łamaniem linii, radzi sobie także z sytuacją, gdy komponent zostaje ściśnięty nawet do szerokości 0px; Oczywiście jeśli szerokość wynosi 0px, to tokenizer nic nie robi - w ogóle nie buduje mapy tokenów, bo i tak nie ma co wyświetlić; Jeśli szerokość komponentu jest mniejsza niż szerokość pojedynczego znaku, to wszystkie tokeny słów zawierają po jednej literce; To takie zabezpieczenie, żeby nie zawiesić tokenizera;

Na samym końcu prac nad tym komponentem znalazłem jedno uchybienie - jeżeli link był wieloliniowy, to na końcu każdej linii zostawał odstęp i znaki takiego odstępu były uwzględniane w obszarach w mapie linków, więc i były także podkreślane po najechaniu na nie kursorem; Ale pomijanie odstępów w budowaniu mapy linków i rysowaniu takich linków jako aktywnych oznaczało wprowadzenie tylko dodatkowej pętli, więc łatwo to było zaimplementować;

[...] choć na początku wtf'em było IMHO pomijanie tekstu bez żadnego znacznika, ale skoro to nie bug tylko ficzer to już tak musi być :P.

Heh, nie sądziłem, że to akurat będzie dziwne dla innych :]

Tak, to nie jest bug, tylko celowe działanie; Tokenizer w pierwszej fazie budowania mapy dzieli kod komponentu (z właściwości Code) na bloki, według znaczników <h> i <p>; Działa w ten sposób:

  • najpierw szuka otwierającego znacznika <h> lub <p>,
  • jeżeli go znajdzie, zapamiętany zostaje indeks tego znacznika,
  • następnie szukany jest znacznik zamykający, o tej samej literce co otwierający,
  • jeżeli zostaje znaleziony, to zostaje wyodrębniona treść pomiędzy tymi znacznikami i wracamy do punktu pierwszego, i tak aż do końca kodu etykiety;
    Pomijanie tekstu poza znacznikami bloków wykonywane jest za każdym razem w pierwszym punkcie; Takie było założenie i tak być musi, aby móc określić czym jest dany kawałek kodu, aby powiązać go z odpowienim węzłem właściwości - TFuriousLabel.Header lub TFuriousLabel.Paragraph - i nadać mu odpowiedni styl fonta; Jeżeli tekst pomiędzy znacznikami bloków miałby być mimo wszystko wyświetlany, to jaki styl mu nadać? No właśnie, dlatego tak po prostu musi być i jeżeli zrozumie się sens funkcjonalności komponentu, to pomijanie tekstu poza blokami stanie się oczywiste i nieodzowne;

Z rzeczy, które życzył bym sobie jeszcze znaleźć w tym komponencie jest dodanie jakiegoś znaku do escape'owania tak aby móc np. umieścić czysty znacznik HTML bez wstawiania spacji. Mogła by to być opcjonalna właściwość - czy taki specjalny znak honorować czy nie. Wydaje mi się, że nie było by to trudne w implementacji.

Nie implementowałem takiej funkcji, dlatego że w swoim projekcie nie będę w etykietach umieszczał znaczników HTML;

Dodanie takiej opcji nie było by trudne - trzeba by wprowadzić nowy znacznik i w drugiej fazie tokenizowania, po napotkaniu tego znacznika wykonać pętlę szukającą takiego samego znacznika zamykającego, bez względu na zawartość; Można by też dodać nową właściwość, jeśli taka funkcja miałaby być opcjonalna i na niej polegałby tokenizer;

Ale tak jak mówię - zaimplementowałem to co było mi potrzebne, a dodać do tego komponentu można znacznie, znacznie więcej.

0

Komponent jak zwykły, prosty komponent. Nie wiem czym się tak zachwycacie.

Już lepsza jest kontrolka RichEdit.

1
Fioletowa Mrówka napisał(a):

Komponent jak zwykły, prosty komponent. Nie wiem czym się tak zachwycacie.
Już lepsza jest kontrolka RichEdit.

Nie masz pojęcia o czym piszesz... Jak można porównywać Label do RichEdit??

0
wloochacz napisał(a):
Fioletowa Mrówka napisał(a):

Komponent jak zwykły, prosty komponent. Nie wiem czym się tak zachwycacie.
Już lepsza jest kontrolka RichEdit.

Nie masz pojęcia o czym piszesz... Jak można porównywać Label do RichEdit??

Jedyne do czego może się przydać to FuriousLabel to chyba tekst w oknie About.

Do wyświetlania formatowanego tekstu używa się RichEdit. Można w nim nawet ustawić, że tylko do odczytu.

1
Czerwona Żaba napisał(a):
wloochacz napisał(a):
Fioletowa Mrówka napisał(a):

Komponent jak zwykły, prosty komponent. Nie wiem czym się tak zachwycacie.
Już lepsza jest kontrolka RichEdit.

Nie masz pojęcia o czym piszesz... Jak można porównywać Label do RichEdit??

Jedyne do czego może się przydać to FuriousLabel to chyba tekst w oknie About.

Do wyświetlania formatowanego tekstu używa się RichEdit. Można w nim nawet ustawić, że tylko do odczytu.

Jasne... zobacz:
df_html_label.png
Rozumiem, że wg Ciebie lepiej aby tam był RichEdit? A co z obsługa linków?

0
wloochacz napisał(a):

Rozumiem, że wg Ciebie lepiej aby tam był RichEdit? A co z obsługa linków?

Zwykłe labele. Jeden czarny, drugi czerwony, trzeci niebieski. Jaki problem?

Obsługa linków to też osobny label, który w zdarzeniu OnClick uruchamia stronę internetową.

1
Złoty Kormoran napisał(a):
wloochacz napisał(a):

Rozumiem, że wg Ciebie lepiej aby tam był RichEdit? A co z obsługa linków?

Zwykłe labele. Jeden czarny, drugi czerwony, trzeci niebieski. Jaki problem?

Jasne :D I będę je dynamicznie tworzył w locie w zależności od wymaganego kontekstu (chodzi o to, że ten tekst jest dynamiczny a nie statyczny) - bo tak właśnie jest tworzony ów napis. Bardzo proszę, możesz się tak pałować - ja nie mam na to czasu.

Obsługa linków to też osobny label, który w zdarzeniu OnClick uruchamia stronę internetową.

Tu nie chodzi o linki, które otwierają stronę internetową, tylko są obsługiwane w obrębie aplikacji i aplikacja robi z nimi co chce.

0

@wloochacz - zapewne użytkownicy @fioletowa Mrówka i @złoty Kormoran (zresztą to jeden i ten sam użytkownik) to ci, którzy do trzymania listy łańcuchów używają ukrytego TMemo, więc szkoda czasu na dyskusję;

Ja nie mam zamiaru odwracać przeznaczenia komponentów, jak robienia etykiety z TRichEdit czy TEdit - już wolę dorobić funkcję zaznaczania w labelku; Ale tego nie potrzebuję, więc komponent póki co tej i innych zbędnych mi funkcji nie posiada;
____Jeśli chodzi o zastosowanie, to jedyne co ogranicza to wyobraźnia;

Przede wszystkim tego typu komponent można zastosować w różnych formularzach, gdzie trzeba umieścić jakichś tip (np. z linkiem do pomocy), można go użyć jako standardowy About, można także wykorzystać go w przeróżnego rodzaju oknach informacyjnych, w hintach (antywirusy pokazują małe popupy z tray'a w których jest formatowna treść i linki aby przejść np. do okna wyników skanowania), w kreatorach prowadzących krok po kroku do jakiegoś działania, w instalatorach i deinstalatorach, w formularzach do prezentacji jakichś danych (np. wykresów), można taki komponent także wykorzystać do budowy bardziej złożonych komponentów, jako ich fragmenty, i tak dalej, i tak dalej - wymieniać i podawać przykłady można bez końca;

Lepiej by było przeglądnąć sobie zainstalowane na dysku aplikacje z zadbanym interfejsem i samemu zobaczyć gdzie i w jaki sposób można taki komponent wykorzystać; Ale do tego trzeba mieć wyobraźnię i najpierw się zastanowić, a dopiero później smarować posty na forum;

Ja taki komponent wykorzystam osobno, jako zwykłe i luźne etykiety, a także jako fragmenty innych komponentów (np. ich tytuły lub składowe wykresów, pól edycyjnych itd.) oraz w tytułach formularzy; Tak więc ja widzę obszerny wachlarz zastosowań, i nie tylko ja.

0

Kończę już powoli przystosowywanie kodu komponentu dla Lazarusa;

Udało mi się poprawić kod tak, aby podczas manipulowania szerokością komponentu, jego zawartość dopasowywała się do nowej szerokości; Czyli poprawiłem to co wcześniej opisywałem w swoim wątku dotyczącym metody SetBounds; W Lazarusie ta metoda, choć przedefiniowana poprawnie, nie wywoływała tokenizera, przez co zawartość się nie odświeżała; Ponowne wywołanie tokenizera umieściłem w innej przedefiniowanej metodzie i teraz śmiga jak tamta lala;

Sprawdziłem też czy tokenizer poprawnie obsługuje UTF-8 - wszystko gra (sprawdziłem na językach arabskim, greckim, rosyjskim i innych z multibajtowymi znakami);
____Teraz pozostało jeszcze rozgryźć to, dlaczego linki tuż po uruchomieniu programu nie chcą się przemalowywać, po najechaniu nań kursorem; Zdarzenia są wywoływane, metoda przerysowująca treść linku także, a mimo to nie widać graficznych zmian; Dopiero po porozciąganiu komponentu (w trybie runtime), kanwa nagle się odblokowuje i już wszystko przerysowuje się poprawnie; Nie wiem jeszcze dlaczego tak jest, ale się dowiem.

0
babubabu napisał(a)

proponuje wcisnąć gdzieś invalidate. Zazwyczaj w wątkach na tym forum jak ktoś pytał o odrysowanie to invalidate pomagało.

Nawet jeśli to miałoby pomóc, to metodą Invalidate albo zapętlę rysowanie, albo otrzymam to samo co jest teraz;

Rysowanie odbywa się w metodzie Paint, w której rysowane są wszystkie słowa z zachowaniem kolorów i stylów; W tej samej metodzie, linki malowane są jako nieaktywne; Teraz każdorazowo po otrzymaniu komunikatu LM_MOUSEMOVE sprawdzane jest, czy kursor znajduje się nad linkiem lub czy zabrano kursor z linku; Jeżeli stan linku zmienił się (czyli najechano kursorem na link lub zabrano z niego kursor) zostaje wywołana metoda, która przerysowuje tylko słowa linku, według jego stanu (podświetlony albo nie);

Dlatego też nie mogę wywoływać Invalidate, bo to spowoduje przemalowanie całego komponentu, co oznaczać będzie namalowanie linków jako nieaktywnych; Poza tym nie ma sensu przemalowywać całości, jeśli zmienił się jedynie jego mały fragment; Dzięki temu uniknie się migania etykiety zawierającej dłuższy tekst;

Podświetlanie linków działa bezproblemowo, ale tylko po drugim wywołaniu tokenizera; Jeżeli program uruchomię, to tokenizer poprawnie zbuduje listę tokenów, następnie na podstawie listy tokenów zostanie zbudowana mapa linków i ich obszarów; Te dwie listy budowane są poprawnie, a poznać to można po tym, że po najechaniu na link zmienia się kursor na ustalony dla linków; Czyli obie mapy są zbudowane, zdarzenie przerysowujące linki według ich stanu także zostaje wywołane, ale kanwa się nie aktualizuje; Jeżeli rozciągnę komponent, a tym samym ponownie wywołam tokenizer i builder mapy linków - kanwa zaczyna działać jak należy i już przerysowywanie linków jest widoczne;

Tak że Invalidate mi nie pomoże, więc muszę szukać przyczyny blokowania się kanwy; Tyle że póki co nie znalazłem przyczyny takiego zachowania; W Delphi ten sam schemat działa idealnie, ale Lazarus coś knoci.

2

Trafiłem do tego wątku przez przypadek i przypomniałem sobie o swoim małym dziele; A skoro ten komponent leży na dysku i w sumie marnuje się, postanowiłem upublicznić jego kod; Żeby nie było, że syc ze mnie :]

Komponent ten pisałem na starej wersji środowiska; Mimo wszystko nie wymagał poprawek, aby można go było skompilować w aktualnej wersji Lazarusa (z nowym silnikiem dla unikodu), więc to dla mnie sukces; Ale i tak co nieco poprawiłem; Gdyby ktoś zapomniał jak się on prezentuje to poniżej mały zrzut ekranu:

flabelwnd.png

Możliwości ma skromne, więc "szału nima"; No i niechęć może budzić w nim fakt oddzielenia warstwy tekstu etykiety od ustawień wyglądu (fontu, odstępów itd.); Ale tak sobie na początku przyjąłem, więc tak jest nadal; Zdziwienie może też powodować drzewiasta struktura właściwości (co można zaobserwować w oknie Inspektora Obiektów), jednak tak sobie wymyśliłem i tak pozostało;

Nadal denerwuje mnie w nim jedna rzecz; Jest nią błąd związany z podświetlaniem linków po najechaniu kursorem; Nie wiem do dziś co jest tego przyczyną (najłatwiej zwalić na bug w LCL, co niniejszym czynię), jednak po pokazaniu się okna aplikacji, podświetlanie nie jest wizualnie widocznie; Kod przemalowujący link zostaje wykonany, ale mimo wszystko link pozostaje w zwykłym kolorze i nie jest podkreślany; Linki poprawnie są podświetlane dopiero po zmianie rozmiaru komponentu w czasie działania programu; Jak ktoś jest chętny to stawiam czteropak za znalezienie błędu i pozbycie się go; Poza tym raczej wszystko działa;

Pewne rzeczy można dodać, w razie gdyby komuś było mało; Albo kompletnie przebudować kod, jak ktoś potrzebuje;

Do dyspozycji jest możliwość edycji tekstu etykiety w osobnym, dedykowanym okienku; Jest to o tyle wygodniejsze, że tekst edytuje się w polu typu memo, z możliwością zawijania wierszy; Wielosekcyjny kod przy otwieraniu okienka jest formatowany (każda sekcja zostaje rozdzielona pustą linią), a po zapisaniu zmian (przycisk Update w tymże oknie), tekst zostaje zamieniony na jednoliniowy ciąg znaków;

Komponent instaluje się na palecie w zakładce Furious Controls i nosi nazwę TFuriousLabel; Jego instalacja jest bardzo prosta - wystarczy otworzyć plik paczki o nazwie furctrls.lpk, w okienku kliknąć guzik Use >> i wybrać opcję Install; Jak trzeba potwierdzić to trzeba potwierdzić - tyle, środowisko się przekompiluje i uruchomi ponownie, z nowym komponentem na palecie;

W załączniku tfuriouslabel source.zip dorzucam pełne źródła; Kod udostępniam na licencji LGPL3, więc można używać do woli, w dowolnych projektach; Miło mi będzie, jak ktoś z tego komponentu skorzysta, więc kto chce niech się częstuje :]

0

Swietna sprawa, na pewno wykorzystam i dam znac jak sie sprawdza:)

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