Firemonkey LiveBinding to TListbox to show images - delphi

I'm trying to use LiveBindings with TListbox. This works with TListview but not TListbox. I'm trying to display only images in a TListbox (no text) but added CustomerID just to show the LiveBindings works. Just that the image does not display from the CustomerPhoto blob field.
LinkFillControlToField1.Control := Listbox1;
with LinkFillControlToField1 do
begin
FillExpressions.Clear;
with FillExpressions.AddExpression do
begin
SourceMemberName := 'CustomerPhoto';
ControlMemberName := 'Bitmap'; // no error, means ControlMember exists
end;
with FillExpressions.AddExpression do
begin
SourceMemberName := 'CustomerID'; // just added this for testing
ControlMemberName := 'Text'; // displays correct
end;
end;
The Bitmap in TListview seems to be directly in it, whereas the 'Bitmap' of TListbox is in ItemData of the TListboxitem - could this be the issue?
Is there anything else to do to make the bitmap appear in TListbox, given that it's so automatic in TListview?

Related

Delphi FMX, change TComboBox images at runtime

If I programmatically change TComboBox.Images to a new TImageList, only the selected icon in the TComboBox changes, all other icons in the TComboBox (drop-down list) remain the same.
I have two TImageLists, one with color icons and one with black and white icons and I want to change the black and white icons to colored icons and vice versa.
procedure TfrmMain.Button1Click(Sender: TObject);
begin
if ComboBox1.Images = ImageList1 then
ComboBox1.Images := ImageList2
else
ComboBox1.Images := ImageList1;
end;
As pointed in the question comments this is indeed a bug in Delphi as the internal drop down list is not refreshed when changing the Images property after showing the popup at least one time. This can be corrected by making a small change in the FMX.ListBox.pas source file at TCustomComboBox.SetImages procedure:
For Delphi 11:
procedure TCustomComboBox.SetImages(const Value: TCustomImageList);
begin
FImageLink.Images := Value;
FItemsChanged := True; // <- Add this
end;
For Delphi 10.4 CE:
procedure TCustomComboBox.SetImages(const Value: TCustomImageList);
begin
FImageLink.Images := Value;
TComboBoxHelper.SetItemsChanged(Self, True); // <- Add this
end;

TChart with TKnobGauge creates shifted labels at runtime

Following code creates knob with labels shifted to the right:
procedure TForm1.FormShow(Sender: TObject);
begin
_chart := TChart.Create(Self);
_chart.Parent := Self;
_chart.Align := alClient;
_knob := TKnobGauge.Create(Self);
_knob.ParentChart := _chart;
_knob.RotateLabels := False;
_knob.RotationAngle := 180;
end;
The same code as DFM produces the right knob.
What could be wrong?
TeeChart Pro v2015.16.150901 32bit VCL
Delphi 10
There is a bug in TChart. When I set
_chart.Title.Text.Text := 'Some title';
labels are on their places.
When I do
_chart.Title.Text.Text := '';
or
_chart.Title.Visible := False;
they are shifted.
The reason why the same code in DFM produced the right knob is that the visual designer extends my minimal chart declaration by adding several properties automatically. Among these properties was a chart title too. It is automatically filled by "TChart" text.
Sounds as exactly what is described in the ticket #1547, initially reported here.
Please, give a try at the workaround described in the ticket:
I can only workaround by having a small title with only a blank in it.

Delphi/Firemonkey make Listboxses sync scroll better

I have a very dirty way of having 7 listboxses scroll in sync, they all have the exact same height so when I move the position of any one of them the other 6 should also move to that position
What I do is Assume Listbox1 is scrolled and ViewportPositionChange() is fired I say
Listbox2.ViewportPosition := NewViewportPosition;
Listbox3.ViewportPosition := NewViewportPosition;
And this all works and I just add this code to each Listboxses ViewportPositionChange() event, but its terribly jerky and too slow on Andriod, I still need to be able to scroll from any one listbox but is there not a way to improve the performace of the scroll?
Ok to be honest it isn't terribly slow but you can feel its not exactly snappy, and also each listbox can have lots of listboxses and each listbox can also have a few controls and more controls in those controls so alot of repainting is done I think and this is what is making it less snappy.
Sample code
Firstly place a Gridpanel layout on your form, Add 6 columns And add a listbox to each, each Listbox represents a day, where Listbox 1 is Monday, Also Align these to client.
Global variables
private Glistbox : array[0..6] of TListBox;
On form Create
Glistbox[0] := ListBox1;
Glistbox[1] := ListBox2;
Glistbox[2] := ListBox3;
Glistbox[3] := ListBox4;
Glistbox[4] := ListBox5;
Glistbox[5] := ListBox6;
Glistbox[6] := ListBox7;
And now on each listboxses OnViewportPositionChange
//Note that this would be for Listbox1 so for listbox 2 it needs to be changed acordingly
ListBox2.ViewportPosition := NewViewportPosition;
ListBox3.ViewportPosition := NewViewportPosition;
ListBox4.ViewportPosition := NewViewportPosition;
ListBox5.ViewportPosition := NewViewportPosition;
ListBox6.ViewportPosition := NewViewportPosition;
ListBox7.ViewportPosition := NewViewportPosition;
Then add a button with the following code :
var
mainlayout,item1,item2 : Tlayout;
listboxitem : TListBoxItem;
myrec,myrec2 : TRectangle;
lbl1,lbl2 : TLabel;
I: Integer;
begin
for I := 0 to 6 do
begin
listboxitem := TListBoxItem.Create(nil);
mainlayout := TLayout.Create(nil);
mainlayout.Align := TAlignLayout.Client;
mainlayout.Parent:= listboxitem;
item1 := TLayout.Create(nil);
item1.Align:= TAlignLayout.Left;
item1.Parent := mainlayout;
item2 := TLayout.Create(nil);
item2.Align:= TAlignLayout.Right;
item2.Parent := mainlayout;
myrec := TRectangle.Create(nil);
myrec.Align := TAlignLayout.Client;
myrec.Parent := item1;
myrec2 := TRectangle.Create(nil);
myrec2.Align := TAlignLayout.Client;
myrec2.Parent := item2;
lbl1 := TLabel.Create(nil);
lbl1.Align := TAlignLayout.Client;
lbl1.TextAlign := TTextAlign.Center;
lbl1.Text := '1';
myrec.AddObject(lbl1);
lbl2 := TLabel.Create(nil);
lbl2.Align := TAlignLayout.Client;
lbl2.TextAlign := TTextAlign.Center;
lbl2.Text := '2';
myrec2.AddObject(lbl2);
Glistbox[I].AddObject(listboxitem);
item2.Width:= mainlayout.Width/2;
end;
There could sometimes be more controls in a listboxitem but generally I think this would be the norm, Now add a few items and try the scroll
The FMX TListBox has a lot of overhead because every listbox item basically is a styled component that is inserted into a scrollbox. This is good for flexibility, but bad for speed.
In Windows and OSX there is functions like ScrollWindowEx or NSView.scrollRect + NSView.setNeedsDisplayInRect that can help improve performance by scrolling a part of the window without issuing paint messages. So you'd only have to invalidate a part of the listbox. I could imagine that Android has something similar. But you'll likely have to patch FMX in order to use that. This can improve performance a bit, but is still not a magic switch for great performance. A similar approach would be caching the content of the scrollbox in a bitmap and then copy parts of the bitmap to the screen while scrolling.
If you need really good listbox performance then you'll need to develop your own listbox that is optimized for speed. This is what I had to do for the OSX version of my application in order to get the performance I needed.
There's also TListView for Firemonkey which is better choice than TListBox when all items share the same visual structure. There's a tutorial by Ray Konopka (from 2014) explaining what each one is suited for:
https://www.youtube.com/watch?time_continue=934&v=XHYtwAu5fl4
For adjusting scrolling behaviour (in case it helps) see:
https://docwiki.embarcadero.com/RADStudio/Alexandria/en/FireMonkey_Layouts_Strategies#Smooth_Inertial_Scrolling

Delphi - How to add tabs in TMEMO?

As shown like here.
pic: tabs with memo
Currently, my TMEMO displays bunch of different data, like this:
Data #1
Paragraphs
Data #2
Paragraphs
Data #N
Paragraphs
So to avoid scrolling, I want to add tabs to the Nth number.
So what components do I need and how should I intiate the process?
you need to use a combination of a TMemo and TTabControl.
Do not know how you get your paragraphs but you'll have to iterate through them, creating a TabSheet and a Memo for each.
procedure TfrmMemo.CreateTabsWithMemo;
var
pgControl: TPageControl;
TabSheet: TTabSheet;
Memo: TMemo;
begin
pgControl := TPageControl.Create(self);
pgControl.Parent := Self;
pgControl.Align := alClient;
//Do this for each paragraph
TabSheet := TTabSheet.Create(pgControl);
TabSheet.PageControl := pgControl;
TabSheet.Caption := Format('Tab %d', [pgControl.PageCount]);
Memo := TMemo.Create(TabSheet);
Memo.Parent := TabSheet;
Memo.Align := alClient;
Memo.Lines.Text := 'Your Paragraph here'
///
end;
Use TPageControl and TTabSheet. Place a TMemo component on each TTabSheet.
You can drage the TPageControl onto the form to get started.

Problem with adding graphics to TLabel

I'm trying to create with Delphi a component inherited from TLabel, with some custom graphics added to it on TLabel.Paint. I want the graphics to be on left side of text, so I overrode GetClientRect:
function TMyComponent.GetClientRect: TRect;
begin
result := inherited GetClientRect;
result.Left := 20;
end;
This solution has major problem I'd like to solve: It's not possible to click on the "graphics area" of the control, only label area. If the caption is empty string, it's not possible to select the component in designer by clicking it at all. Any ideas?
First excuse-me for my bad English.
I think it is not a good idea change the ClientRect of the component. This property is used for many internal methods and procedures so you can accidentally change the functionality/operation of that component.
I think that you can change the point to write the text (20 pixels in the DoDrawText procedure -for example-) and the component can respond on events in the graphic area.
procedure TGrlabel.DoDrawText(var Rect: TRect; Flags: Integer);
begin
Rect.Left := 20;
inherited;
end;
procedure TGrlabel.Paint;
begin
inherited;
Canvas.Brush.Color := clRed;
Canvas.Pen.Color := clRed;
Canvas.pen.Width := 3;
Canvas.MoveTo(5,5);
Canvas.LineTo(15,8);
end;
What methods/functionality are you getting from TLabel that you need this component to do?
Would you perhaps be better making a descendent of (say, TImage) and draw your text as part of it's paint method?
If it's really got to be a TLabel descendant (with all that this entails) then I think you'll be stuck with this design-time issue, as doesn't TLabel have this problem anyway when the caption is empty?
I'll be interested in the other answers you get! :-)

Resources