[Delphi] Tekst afbreken in een TreeView

Pagina: 1
Acties:

  • Bergen
  • Registratie: Maart 2001
  • Laatst online: 18-08 10:58

Bergen

Spellingscontroleur

Topicstarter
Doag,

Ik heb een treeview vol tekst, maar als de tekst buiten de treeview komt, verschijnt er een scrollbar. Is er een instelling om de tekst af te breken met bijvoorbeeld 3 puntjes, net zoals er korte metten wordt gemaakt met lange namen in de MSN Messenger?

Ik heb de hele propertielijst doorgespit, maar OF hij staat er niet bij OF ik zie 'm over het hoofd. Ra ra?

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:40
Zelf programmeren.....

Programmeren is niet altijd gewoon wat properties instellen hoor. ;)

https://fgheysels.github.io/


  • Bergen
  • Registratie: Maart 2001
  • Laatst online: 18-08 10:58

Bergen

Spellingscontroleur

Topicstarter
I know, I know, ik code al langer dan vandaag en gisteren, kvraag me alleen af of ik iets over het hoofd zie. Zo niet, dan code ik 't inderdaad gewoon zelf.

Ik ben een messenger aan het schrijven... (jaja, NOG EEN) Dit staat gewoon niet mooi vind ik:

Afbeeldingslocatie: http://www.gerbs.net/talx.png

Daar is 't dus voor.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

OnCustomDraw, en de wondere wereld van DrawText met DT_ENDELLIPSIS dus :) Ben je alsnog in een paar regels klaar overigens.

Professionele website nodig?


  • Bergen
  • Registratie: Maart 2001
  • Laatst online: 18-08 10:58

Bergen

Spellingscontroleur

Topicstarter
Nou, kben even aan de slag gegaan met OnCustomDrawItem en DrawText met DT_END_ELLIPSIS want daar zal het inderdaad allemaal mee moeten! :)

Dit is m'n code nu met commentaar zelfs!:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
procedure TMainForm.UsertreeCustomDrawItem(Sender: TCustomTreeView;
        Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
var
        rect: TRect;
        name: PChar;
        icon: TBitmap;
begin
        // We slaan rootnodes maar ff over, die hebben namelijk geen data-
        // object en die hebben we nodig voor de tekst.
        if Node.Parent = nil then exit;

        // Haal de tekst op die in de treeview moet komen.
        name := PChar(TUser(Node.Data).Get_treeviewname);

        // Haal de rect op van de hele breedte van de regel.
        rect := Node.DisplayRect(false);

        // Stel de linkerkant in op het begin van de tekst van de node.
        rect.Left := Node.DisplayRect(true).Left + 4;

        // Gooi de tekst op het canvas!
        DrawText(Sender.Canvas.Handle, name, Length(name), rect, DT_END_ELLIPSIS);

        // Plaatje erbij...
        icon := TBitmap.Create;
        try
                with icon do
                begin
                        PixelFormat := pf24bit;
                        Width := 16;
                        Height := 16;
                end;
                icons_16_white.GetBitmap(node.ImageIndex, icon);
                Sender.Canvas.Draw(rect.Left - 20, rect.Top, icon);
        finally
                icon.Free;
        end;

        // Teken de originele tekst niet, anders krijgen we alsnog scrollbars.
        DefaultDraw := false;
end;
Mooi he... :z Anyway, dat levert het volgende op:

Afbeeldingslocatie: http://www.gerbs.net/talx2.png

De DT_END_ELLIPSIS doet z'n werk goed! :* Er gaan nog een paar dingen mis:

1. De scrollbar langs de rechterkant levert trails op bij het resizen, terwijl ik na een OnResize (van 't form) een Repaint aanroep voor de TreeView en voor de 't Panel waar hij op staat.

2. De tekst die getekend is door DrawText kan alleen maar geselecteerd worden door aan de linkerkant er vlak naast te klikken, omdat de originele TreeView-tekenfunctie een paar pixels brede selecteerbare ruimte tekent (terwijl ik overigens geen tekst laat zetten; Node.Text := ''; )

Enfin, we prutsen verder... ;)

Verwijderd

waarom niet gewoon die node.text gebruiken? Je kunt met .canvas.textwidt(text) de breedte van je tekst opvragen in pixels. Dan even truncen op de juiste lengte en zetten in node.text..

  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 17:28

alienfruit

the alien you never expected

We hebben natuurlijk ook nog altijd TCustomDrawState en dan:

code:
1
2
3
4
5
6
7
if ( cdsSelected in State ) then 
begin
  // code hier als de item is geselecteerd
end 
else begin
  // code hier als de item niet geselecteerd is
end;


Overigens er is ook een MeasureItem-event als het goed is, dit wordt getriggerd als de treeview de rectangle wilt weten; hier zou je dus de hoogte van je item kun vergroten om groter selecteer vak te krijgen.

[ Voor 31% gewijzigd door alienfruit op 25-06-2003 16:17 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Doe eens niet bij OnResize handmatig Repaints forceren, daarmee verneuk je het Paint-systeem van Windows.

En TTreeView heeft als ik me niet vergis een OnGetHitTest (zo niet ben ik in de war met DevExpress treelist component).

Professionele website nodig?


  • OZ-Gump
  • Registratie: November 2002
  • Laatst online: 26-06 10:37

OZ-Gump

terug van weggeweest

Een TreeView heeft een GetHitTestInfoAt, en ook een GetNodeAt. Bij de OnMouseDown krijg je een x en een y, dus kun je deze twee gebruiken.

Wat curry684 met de GetHitTestInfoAt wil weet ik niet precies... De GetNodeAt retoureneert in ieder geval een TTreeNode, waardoor je redelijk simpel kunt kijken of er een node onder je muis zit, en deze eventueel bewerken, selecteren whatever. Misschien heb je er iets aan...

Voorbeeldje:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
procedure TfrmMain.TreeView1MouseDown(Sender: TObject;
                                      Button: TMouseButton;
                                      Shift : TShiftState;
                                      X, Y  : Integer);
var tn : TTreeNode;
begin
  tn := TreeView1.GetNodeAt(X, Y);  //eerst de node opvragen
  if Assigned(tn) then              //kijken of je op een node hebt geklikt
    if Assigned(tn.Parent) then     //kijken of je op een parent hebt geklikt
      ShowMessage(Node tekst: ' + tn.Text);
end;

Alhoewel GetNodeAt meer lijkt te werken met de Y-coordinaat dan met X-coordinaat. Ook als je langs de node klikt, retourneert hij een node. Maar goed, dat is niet schokkend. En als het dat wel is, kun je er redelijk simpel omheen werken.

[ Voor 52% gewijzigd door OZ-Gump op 25-06-2003 16:48 ]

My personal website


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

OZ-Gump: OnGetHitTestInfo is een event dat de programmeur de mogelijkheid geeft om de default hittest-data te overrulen. Blijkbaar niet in TTreeView aanwezig dus, ignore that remark ;)

Professionele website nodig?


  • Bergen
  • Registratie: Maart 2001
  • Laatst online: 18-08 10:58

Bergen

Spellingscontroleur

Topicstarter
Verwijderd schreef op 25 June 2003 @ 08:23:
waarom niet gewoon die node.text gebruiken? Je kunt met .canvas.textwidt(text) de breedte van je tekst opvragen in pixels. Dan even truncen op de juiste lengte en zetten in node.text..
Hmm ja dat zou natuurlijk kunnen. Ik heb 't geprobeerd maar op de een of andere manier wordt het lettertype ineens heel groot terwijl ik daar geen properties van verander. Als ik voor de functie het font even in een temp variabele zet en na afloop weer terugzet lost dat ook niets op.

Zo issie als ik de hele functie comment: (let ook op de trails terwijl die repaints uit staan nu)

Afbeeldingslocatie: http://www.gerbs.net/talx3.png

Als ik de functie uncomment worden de fonts ineens veel groter. De textwidth wordt wel met de originele fontmaten gemeten; dat heb ik gecontroleerd. Hij maakt er dit van:

Afbeeldingslocatie: http://www.gerbs.net/talx4.png

De tekstafbreking werkt verder prima. Als ik de maximale breedte op 100 pixels zet maakt hij er dit van:

Afbeeldingslocatie: http://www.gerbs.net/talx5.png

Stukje code... (sorry voor de layoutverneuking O-))

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
procedure TMainForm.UsertreeCustomDrawItem(Sender: TCustomTreeView;
        Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
var
        maxWidth, currentWidth, i: integer;
        username: string;
        tempFont: TFont;
begin
        tempFont := Sender.Canvas.Font;
        if Node.Parent = nil then exit; // zelfde verhaal, root vergeten we ff
        maxWidth := 100; //Sender.Width - Node.DisplayRect(true).Left;
        username := TUser(Node.Data).Get_treeviewname;
        currentWidth := Sender.Canvas.TextWidth(username);
        while (currentWidth > maxWidth) and (Length(username) > 0) do
        begin
                {-------- Alleen een puntje? Dan wordt 't een lege zin --------}
                if username = '.' then
                        username := ''
                else
                        {-------- 2 puntjes? Dan wordt 't 1 puntje. --------}
                        if username = '..' then
                                username := '.'
                        else
                                {-------- 3 puntjes? Dan worden het 2 puntjes. --------}
                                if username = '...' then
                                        username := '..'
                                else
                                        {-------- 3 puntjes aan het einde? Dan inkorten. --------}
                                        if (Length(username) > 3) and (Copy(username, Length(username) - 2, 3) = '...') then
                                                username := Copy(username, 1, Length(username) - 4) + '...'
                                        else
                                                {-------- Naam korter dan 4 letters? Dan alles omzetten in puntjes. --------}
                                                if Length(username) < 4 then
                                                        for i := 1 to Length(username) do
                                                                username[i] := '.'
                                                else
                                                        {-------- Anders gewoon laatste 3 vervangen door puntjes --------}
                                                        username := Copy(username, 1, Length(username) - 3) + '...';
                currentWidth := Sender.Canvas.TextWidth(username);
        end;
        Node.Text := username;
        Sender.Canvas.Font := tempFont; // font-debug-ding
end;


Ben ik nou zo achterlijk? 8)7 Zelfs als ik het font bewaar en terugzet dandandan blijven die letters groot!

Aan die OnHitTest en NodeAt functies heb ik niet zoveel als ik met DrawText ga werken. De tekst wordt afzonderlijk getekend door DrawText en daar is de TreeView niet van op de hoogte. Die zal dus ook niet aangeven dat er een node zit waar je klikt. Dat is opgelost als ik de tekst alsnog in Node.Text zet en DefaultDraw op false zet, maar dan verschijnt de scrollbar nog steeds. ;(

Ik denk dat ik de coordinaten van alle rects maar in een list donder en dan de coordinaten van de OnMouseDowns maar vergelijk met die in de list. Kan me niet voorstellen dat MS het ook zo heeft opgelost in hun Messenger, maarja. Als 't maar werkt he... ;)

Verwijderd

Imo doe je het te ingewikkeld. Vergeet painten, wat er niet in komt hoeft er ook niet uit.

Een TTreeView node heeft een Data property. Zet daar je 'lange naam' in, en vul de node.text property bij elke form.resize met passende teksten.

Wil je het netjes doen, maak dan eigen afgeleiden van de gebruikte classes (TTreeview. TTreeNode) met daarin deze functionaliteit.

  • Bergen
  • Registratie: Maart 2001
  • Laatst online: 18-08 10:58

Bergen

Spellingscontroleur

Topicstarter
Verwijderd schreef op 25 June 2003 @ 21:34:
Imo doe je het te ingewikkeld. Vergeet painten, wat er niet in komt hoeft er ook niet uit.
Die staan al uit:
...terwijl die repaints uit staan nu
Een TTreeView node heeft een Data property. Zet daar je 'lange naam' in,
Daar staan ze al in:
username := TUser(Node.Data).Get_treeviewname;
en vul de node.text property bij elke form.resize met passende teksten.
Goed plan, de boel in de Resize functie! Dat kan ik ook es proberen.
Wil je het netjes doen, maak dan eigen afgeleiden van de gebruikte classes (TTreeview. TTreeNode) met daarin deze functionaliteit.
Nou ik was ondertussen van plan om een compleet eigen klasse te schrijven, met alleen de benodigde functionaliteit: 2 dieptelevels, root icoontjes, user icoontjes, drawtext (met dt_end_ellipsis en textwidth) en expanden/collapsen. Maar eerst idd even de Resizefunctie testen! ;)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

GerbenW schreef op 25 June 2003 @ 21:49:
Nou ik was ondertussen van plan om een compleet eigen klasse te schrijven, met alleen de benodigde functionaliteit: 2 dieptelevels, root icoontjes, user icoontjes, drawtext (met dt_end_ellipsis en textwidth) en expanden/collapsen. Maar eerst idd even de Resizefunctie testen! ;)
* curry684 krijg een deja-vu van een control dat ie vorig jaar in BCB heeft geschreven incluis tooltips en alles:

Afbeeldingslocatie: http://crew.tweakers.net/curry/iOffice.PNG

Helaas voor u copyrighted :/

Professionele website nodig?


  • Bergen
  • Registratie: Maart 2001
  • Laatst online: 18-08 10:58

Bergen

Spellingscontroleur

Topicstarter
curry684 schreef op 25 June 2003 @ 22:57:
[...]

* curry684 krijg een deja-vu van een control dat ie vorig jaar in BCB heeft geschreven incluis tooltips en alles:

[afbeelding]
Ziet er mooi uit!! :)
Helaas voor u copyrighted :/
Nah, khou toch niet van source van 't net plukken... anders had ik ook allang de Virtual Treeview gebruikt, maarja, 3rd party componenten zijn niet leuk, dan kun je niet trots zijn op je werk vind ik. :)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

:> 2 fulltime daagjes werk, 100% tilend, alle plaatjes (expand/collapse ook) customizable, smooth scrolling, background kan in alle hoeken en static of scrolling tiled, die gradientlijntjes alphablenden width-scaled met de background (!!!), alles is clickable, foutloze hittesting, correcte hand-cursors boven clickable items (die ook underlinen op dat moment) en popupmenu's customizable op alle niveaus.

* curry684 heeft te lang te veel met VCL gedaan ;)

ps. niet om te patsen, maar gewoon 'giving you a target to beat' :Y)

Professionele website nodig?


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 01:25

Tomatoman

Fulltime prutser

Afbeeldingslocatie: http://home.planet.nl/~robin.gerrets/linked/progsel.gif

Niet om te patsen, maar dat kostte me fulltime 1 minuutje werk ;).


[Edit] om misverstanden te voorkomen: niet als flame bedoeld. Ziet er goed uit, curry684.

[ Voor 28% gewijzigd door Tomatoman op 26-06-2003 00:36 ]

Een goede grap mag vrienden kosten.

Pagina: 1