user54517
user54517

Reputation: 2420

WordWrap for TListBoxItem

I'm making a RSS feed app with Delphi XE7 (Firemonkey) and the articles are displayed with a Listbox : (Text of ListBoxItem for titles and Details of ListBoxItem for articles). But as you can see in this screenshot:

1
(source: evolutiongraph.fr)

the articles are too long and do not come back to the line. The propertie WordWrap for ListBox doesn't exists. So I was looking for a way to solve this problem and I didn't find.

Can you help me ? And if it's impossible to do that way, can you propose me another way to display articles ? Thank you !

Upvotes: 2

Views: 4268

Answers (2)

Using a TListBox (as you did) :

At runtime, ListBoxItems already have a calculated style stored in aListBoxItem.StyledSettings. To change a setting at runtime, you first have to remove it from the list of styled settings.

For example, if you want to change the FontColor, first remove the 'styled' fontcolor:

aListboxItem.StyledSettings := aListboxItem.StyledSettings - [TStyledSetting.FontColor];

Then apply another one:

aListboxItem.FontColor := TAlphaColors.Green;

The WordWrap property is defined in TStyledSetting.Other. To change it:

aListboxItem.StyledSettings := aListboxItem.StyledSettings - [TStyledSetting.Other];

aListboxItem.WordWrap := True;

The TStyledSetting constants and corresponding TTextSettings properties are listed here in Delphi's doc.

On accessing TListBoxItem properties : theListBox.Items[i] gives access to item content, not the item itself. To grab a ListboxItem as a control, and then act on its properties, you can use:

aListboxItem := theListBox.ListItems[i]; 

or

aListboxItem := theListBox.ItemByIndex(i);

Both giving exactly the same result, I cannot say if one is better.

On text height : Once the text is wrapped in the control, you will probably need to adjust the control's height to show the entire text. This can be done OnApplyStyleLookup event, using a TTextLayout :

uses 
... ,FMX.TextLayout;

procedure TfrmForm1.ListBoxItem1ApplyStyleLookup(Sender: TObject);
var
  myLayout: TTextLayout;
  i: integer;
  aPoint: TPointF;
begin

  myLayout := TTextLayoutManager.DefaultTextLayout.Create;
  myLayout.BeginUpdate;

  // Setting the layout MaxSize
  aPoint.X := ListBoxItem1.Width;
  aPoint.Y := TfrmForm1.Height;
  myLayout.MaxSize := aPoint;

  myLayout.Text := ListBoxItem1.Text;
  myLayout.WordWrap := True ;
  myLayout.Font := ListBoxItem1.Font;
  myLayout.HorizontalAlign := ListBoxItem1.TextSettings.HorzAlign;
  myLayout.VerticalAlign := ListBoxItem1.TextSettings.VertAlign;
  myLayout.Padding := ListBoxItem1.Padding;
  // set other properties as needed

  myLayout.EndUpdate;

  ListBoxItem1.Height := Trunc(myLayout.TextHeight) + 3 ;

end;

Note that MaxSize is limitating. For example, aPoint.Y will limit the final TextHeight. You should set it large because, whatever TextHeight should be, if myLayout.TextHeight is larger than myLayout.MaxSize.Y then myLayout.TextHeight will be set to myLayout.MaxSize.Y. Here's a list of TTextLayout properties.

N.B.: You may have to specify the font size at runtime before measuring the text height, or to set different from default at design time. On my testing device (Samsung Note 2), the default font size is measured 14 ( ListBoxItem1.Font.Size = 14 ) but it's rendered as 18. And it's not a scale issue. Then, the calculation for myLayout.TextHeight is done with Font.Size = 14 while the ListBoxItem will still render Font.Size = 18, still not fitting. It can be useful to reset Font.Size just before layout calculations by adding :

ListBoxItem1.StyledSettings := ListBoxItem1.StyledSettings - [TStyledSetting.Size] ;
ListBoxItem1.Font.Size := ListBoxItem1.Font.Size ;

Alternatively, you can use a TListView :

TListView is better suited for long lists and the WordWrap property can be set at design time. To find it in the Object Inspector go to :

ListView1 > ItemAppearanceObjects > ItemObjects > Text > WordWrap

Resizing will still be needed to fit the text height.


Examples of what can be done with ListBox and ListView in this CodeRage video. https://www.youtube.com/watch?v=XRj3qjUjBlc

Upvotes: 4

androschuk.a
androschuk.a

Reputation: 289

You can try to use ListBoxItem.WordWrap. More detail in site http://docwiki.embarcadero.com/

Try write similar function:

for I:= 0 To ListBox1.Items.Count - 1 Do
  ListBox1.Items[I].WordWrap := True;

Upvotes: 0

Related Questions