Lag when Scrolling a TListBox - ios

I have a TListBox that contains about 50 TListboxItems aka Items. Each item contains 3 TTexts used as labels, 1 TImage with resolution of 48x48 to indicate a 'status', and a Check box for selecting items. When on a device, there is a big lag time when scrolling. It is often jumpy,sporadic,inconsistent.
Is this because I have too many items ? Or is it because they contain the TTexts,Timage, etc. ?
Or is there something I can do to smooth up the scrolling process of the TListbox.
I am using Delphi xe5 to develop an iOS application. I did make sure to check that the 'sorted' property of the TListbox is := False;
UPDATE (Response to Jerry Dodge):
while XMLNode <> nil do begin
Main_Form.LBoxEntries.Items.Add('');
Item1:=Main_Form.LBoxEntries.ListItems[Main_Form.LBoxEntries.Items.Count-1];
Item1.Height := 80;
Item1.Width := ClientWidth;
if XMLNode.ChildNodes['SCANSTATUS'].Text = '0' then begin
Item1.ItemData.Bitmap := Main_Form.Red.Bitmap;
Item1.Tag := 0;
end;
if XMLNode.ChildNodes['SCANSTATUS'].Text = '1' then begin
Item1.ItemData.Bitmap := Main_Form.Orange.Bitmap;
Item1.Tag := 1;
end;
if XMLNode.ChildNodes['SCANSTATUS'].Text = '2' then begin
Item1.ItemData.Bitmap := Main_Form.Green.Bitmap;
Item1.Tag := 2;
end;
Customer := TText.Create(nil);
Customer.Parent := Item1;
Customer.Position.X := 95;
Customer.Position.Y := 8;
Customer.Text := XMLNode.childNodes['CUSTOMERNAME'].text;
Customer.Width := Item1.Width - 105;
Customer.WordWrap := False;
Customer.Color := TAlphaColors.Blue;
Customer.Trimming := TTextTrimming(1);
Customer.Height := 20;
Customer.Font.Size := 18;
Customer.HorzTextAlign := TTextAlign(1);
Customer.Anchors := [TanchorKind.akLeft,TanchorKind.akRight];
Customer.WordWrap := False;
Product := TText.Create(nil);
Product.Parent := Item1;
Product.Position.X := 105;
Product.Position.Y := 30;
Product.Text := 'Product: ' +XMLNode.childNodes['PRODUCT'].text;
Product.Width := Item1.Width - 115;
Product.Trimming := TTextTrimming(1);
Product.Height := 20;
Product.Font.Size := 15;
Product.HorzTextAlign := TTextAlign(1);
Product.Anchors := [TanchorKind.akLeft,TanchorKind.akRight];
Product.WordWrap := False;
QTY := TText.Create(nil);
QTY.Parent := Item1;
QTY.Position.X := 105;
QTY.Position.Y := 50;
QTY.Text := 'QTY: ('+XMLNode.childNodes['QTY'].text+')';
QTY.Width := Item1.Width - 115;
QTY.Trimming := TTextTrimming(1);
QTY.Height := 20;
QTY.Font.Size := 15;
QTY.HorzTextAlign := TTextAlign(1);
QTY.Anchors := [TanchorKind.akLeft,TanchorKind.akRight];
QTY.WordWrap := False;
Item1.ItemData.Detail := ' |' + XMLNode.childNodes['SID'].Text+'|'+
' |' + XMLNode.childNodes['CUSTOMERNAME'].Text+'|'+
' |' + XMLNode.childNodes['PRODUCT'].text+'|'+
' |' + XMLNode.childNodes['QTY'].Text+'| ';
XMLNode := XMLNode.NextSibling;
end;
Main_Form.LBoxEntries.EndUpdate;
No post actions/events are tied to the items.

I removed all of the TLayouts I was using, of which my Listbox was placed upon - still lagged.
I then removed the parent TPanel that acted as the form control (for sliding effect when opening a side menu), and then the lag disappeared. I will do further testing to see if I can just swap the TPanel with a TLayout, or just adjust my program and side-menu accordingly.
Update: TPanel is what caused the lagg when scrolling. Swapped the component for a TLayout and it works smoothly as ever !

I think the standard advice is if it needs to scroll, use a TListView, not a TListbox. I have done simple apps on iOS and Android with XE5 with 100+ items in a TListView and scrolling has been very smooth.

Related

How to handle realign of components in runtime after screen resize delphi

I searched a lot in google to get a clearer info on how I could solve my current issue, but I got scalability of components as the best answer, that's... not yet my issue.
So, long story short: I want to realign components on my form after the user resizes the window, the form is populated dinamically from a SQL query, this is the constructor code:
procedure TForm2.MakeWindow;
var
dummyMaskedit, dummyEdit: TEdit;
dummyMemo: TMemo;
dummyCombobox: TComboBox;
dummyLabel: TLabel;
dummyLBox: TListBox;
dummybutton: TButton;
i, f: integer;
buffer, workarea: double;
begin
FDQDB.Close;
FDQDB.Open('SELECT * FROM Defs WHERE active = 1');
i := 0;
f := 1;
buffer := Layout1.Width;
workarea := Layout1.Width;
SetLength(aMasks, 0);
while not FDQDB.Eof do
begin
case AnsiIndexStr(FDQDB.FieldByName('comptype').AsString,
['tedit', 'tcombobox', 'tmaskedit', 'tlistbox']) of
0: // TEdit
begin
dummyEdit := TEdit.Create(self);
dummyEdit.Parent := Form2.Layout1;
dummyEdit.Width := FDQDB.FieldByName('size').AsInteger;
if buffer - dummyEdit.Width >= 0 then
begin
buffer := buffer - dummyEdit.Width - 8;
dummyEdit.Position.Y := Panel2.Position.Y + 22 + (45 * i);
dummyEdit.Position.X := workarea - buffer - dummyEdit.Width + 5;
end
else
begin
inc(i);
buffer := workarea;
buffer := buffer - dummyEdit.Width - 8;
dummyEdit.Position.Y := Panel2.Position.Y + 22 + (45 * i);
dummyEdit.Position.X := workarea - buffer - dummyEdit.Width + 5;
end;
dummyEdit.Name := 'field' + IntToStr(f);
inc(f);
dummyLabel := TLabel.Create(self);
with dummyLabel do
begin
Parent := dummyEdit.Parent;
Text := FDQDB.FieldByName('Descricao').AsString;
Position.Y := dummyEdit.Position.Y - 17;
Position.X := dummyEdit.Position.X;
end;
end;
1: // TComboBox
begin
dummyCombobox := TComboBox.Create(self);
dummyCombobox.Parent := Form2.Layout1;
dummyCombobox.Width := FDQDB.FieldByName('size').AsInteger;
if buffer - dummyCombobox.Width >= 0 then
begin
buffer := buffer - dummyCombobox.Width - 8;
dummyCombobox.Position.Y := Panel2.Position.Y + 22 + (45 * i);
dummyCombobox.Position.X := workarea - buffer -
dummyCombobox.Width + 5;
end
else
begin
inc(i);
buffer := workarea;
buffer := buffer - dummyCombobox.Width - 8;
dummyCombobox.Position.Y := Panel2.Position.Y + 22 + (45 * i);
dummyCombobox.Position.X := workarea - buffer -
dummyCombobox.Width + 5;
end;
dummyCombobox.Name := 'field' + IntToStr(f);
dummyCombobox.Items.Delimiter := '|';
dummyCombobox.Items.StrictDelimiter := true;
dummyCombobox.Items.DelimitedText :=
AnsiUpperCase(FDQDB.FieldByName('combovalue').AsString);
inc(f);
dummyLabel := TLabel.Create(self);
with dummyLabel do
begin
Parent := dummyCombobox.Parent;
Text := FDQDB.FieldByName('Descricao').AsString;
Position.Y := dummyCombobox.Position.Y - 17;
Position.X := dummyCombobox.Position.X;
end;
end;
2: // TMaskEdit
begin
dummyMaskedit := TEdit.Create(self);
dummyMaskedit.Parent := Form2.Layout1;
dummyMaskedit.Width := FDQDB.FieldByName('size').AsInteger;
if buffer - dummyMaskedit.Width >= 0 then
begin
buffer := buffer - dummyMaskedit.Width - 8;
dummyMaskedit.Position.Y := Panel2.Position.Y + 22 + (45 * i);
dummyMaskedit.Position.X := workarea - buffer -
dummyMaskedit.Width + 5;
end
else
begin
inc(i);
buffer := workarea;
buffer := buffer - dummyMaskedit.Width - 8;
dummyMaskedit.Position.Y := Panel2.Position.Y + 22 + (45 * i);
dummyMaskedit.Position.X := workarea - buffer -
dummyMaskedit.Width + 5;
end;
dummyMaskedit.Name := 'field' + IntToStr(f);
inc(f);
SetLength(aMasks, length(aMasks) + 1);
Masks.field := dummyMaskedit.Name;
Masks.mask := FDQDB.FieldByName('mask').AsString;
aMasks[length(aMasks) - 1] := Masks;
dummyMaskedit.OnExit := MaskTextExit;
dummyLabel := TLabel.Create(self);
with dummyLabel do
begin
Parent := dummyMaskedit.Parent;
Text := FDQDB.FieldByName('Descricao').AsString;
Position.Y := dummyMaskedit.Position.Y - 17;
Position.X := dummyMaskedit.Position.X;
end;
end;
3: // TListBox
begin
dummyLBox := TListBox.Create(self);
dummyLBox.Parent := Form2.Layout1;
dummyLBox.Width := FDQDB.FieldByName('size').AsInteger;
inc(i);
buffer := workarea;
if buffer - dummyLBox.Width >= 0 then
begin
buffer := buffer - dummyLBox.Width - 8;
dummyLBox.Position.Y := Panel2.Position.Y + 22 + (45 * i);
dummyLBox.Position.X := workarea - buffer - dummyLBox.Width + 5;
end
else
begin
inc(i);
buffer := workarea;
buffer := buffer - dummyLBox.Width - 8;
dummyLBox.Position.Y := Panel2.Position.Y + 22 + (45 * i);
dummyLBox.Position.X := workarea - buffer - dummyLBox.Width + 5;
end;
dummyLBox.Name := 'field' + IntToStr(f);
inc(f);
SetLength(aMasks, length(aMasks) + 1);
Masks.field := dummyLBox.Name;
Masks.mask := FDQDB.FieldByName('mask').AsString;
aMasks[length(aMasks) - 1] := Masks;
dummyLabel := TLabel.Create(self);
with dummyLabel do
begin
Parent := dummyLBox.Parent;
Text := FDQDB.FieldByName('Descricao').AsString;
Position.Y := dummyLBox.Position.Y - 17;
Position.X := dummyLBox.Position.X;
end;
dummybutton := TButton.Create(self);
with dummybutton do
begin
Parent := dummyLBox.Parent;
Text := '+';
Width := 20;
Position.X := dummyLBox.Width + dummyLBox.Position.X + 3;
Position.Y := dummyLBox.Position.Y;
Name := 'ba' + dummyLBox.Name;
OnClick := ButtonsAddClick;
end;
dummybutton := TButton.Create(self);
with dummybutton do
begin
Parent := dummyLBox.Parent;
Text := '-';
Width := 20;
Position.X := dummyLBox.Width + dummyLBox.Position.X + 3;
Position.Y := dummyLBox.Position.Y + 28;
Name := 'br' + dummyLBox.Name;
OnClick := ButtonsRemClick;
end;
end;
end;
FDQDB.Next;
end;
FDQDB.Close;
end;
That works nice and pretty on the windowed state of the application, this code is applied to the onCreate event of the form:
procedure TForm2.FormCreate(Sender: TObject);
begin
FDCDB.Params.Database := ExtractFilePath(ParamStr(0)) + 'window.db';
MakeWindow;
end;
The first form, main form of the application, is the one that summons the new form that has the components built in runtime:
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
Application.CreateForm(TForm2, Form2);
Form2.Layout1.parent := Self.Layout1.Parent;
Form2.Layout1.Width := Self.Layout1.Width;
end;
The second form has a TLayout, just like the first form. Then, when I create the form I bring the TLayout of the second form to the first. So far so good, it works when the application is launched in windowed mode.
But when I put form1 in fullscreen mode, then click the Button that creates the form2, the components stays on the same position as in windowed mode. I've tried changing the workarea variable to these:
Screen.width, //components behave as the application were in fullscreen the whole time
Screen.WorkAreaWidth, //same as screen.width
(Layout1.Parent as TLayout).Width, //invalid typecast
(Layout1.GetParentComponent as TLayout).Width //invalid typecast
None of them worked.
I wanna be able to adjust the position of the components on the screen based on its visual width, so if the user resizes the window before creating the new form, the components gets aligned properly.
Anyone knows a solution for that? Thanks in advance
But when I put form1 in fullscreen mode, then click the Button that
creates the form2, the components stays on the same position as in
windowed mode.
At TForm1.SpeedButton1Click() you call Application.CreateForm(TForm2, Form2); which triggers TForm2.FormCreate(Sender: TObject); which calls MakeWindow. At this point Form2 knows only about the design time size.
After MakeWindow is done, the TForm1.SpeedButton1Click() continues:
Form2.Layout1.parent := Self.Layout1.Parent;
Form2.Layout1.Width := Self.Layout1.Width;
but these do not anymore affect the layout of the controls.
You need to set Form2.Layout1.Width before you call MakeWindow, for example:
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
Application.CreateForm(TForm2, Form2);
Form2.Layout1.parent := Self.Layout1.Parent;
Form2.Layout1.Width := Self.Layout1.Width;
MakeWindow; // remove it from TForm2.FormCreate()
end;
The form has ClientWidth and ClientHeight properties which work well in OnResize to dynamically size a control based on the area available. The OnResize fires before the form is made visible. For example to have a Memo1 with a 100 border around it:
procedure TForm1.FormResize(Sender: TObject);
begin
memo1.Position.X := 100; // Only needs to be done once but here so all code is in one spot
memo1.Position.Y := 100;
memo1.Width := form1.ClientWidth - 200;
memo1.Height := form1.ClientHeight - 200;
end;

Delphi Change resolution of webcam in directshow

i am trying to change the resolution of the frames to 320x240 because my webcam is providing frames in 640x480 and the encoder i am using is not working right with higher resolution, i do it this way
procedure OnDevieStart()
begin
FilterGraph.ClearGraph;
FilterGraph.Active := False;
Filter.BaseFilter.Moniker := SysDev.GetMoniker(TMenuItem(Sender).tag);
FilterGraph.Active := true;
SetVideoProperties(Filter as iBaseFilter);
with FilterGraph as ICaptureGraphBuilder2 do
try
RenderStream(#PIN_CATEGORY_PREVIEW, nil, Filter as IBaseFilter, SampleGrabber as IBaseFilter, VideoWindow as IbaseFilter);
FilterGraph.Play;
except
ShowMessage('Unable to use specified device!')
end;
end;
function SetVideoProperties(pVideoCapture: IBaseFilter):Boolean;
var
hr:HRESULT;
pStreamConfig: IAMStreamConfig;
pAM_Media: PAMMediaType;
pvih: PVIDEOINFOHEADER;
pICGP2: ICaptureGraphBuilder2;
begin
pICGP2 := FilterGraph as ICaptureGraphBuilder2;
hr := pICGP2.FindInterface(#PIN_CATEGORY_CAPTURE, nil, pVideoCapture,
IID_IAMStreamConfig, pStreamConfig);
if (SUCCEEDED(hr)) then begin
pStreamConfig.GetFormat(pAM_Media);
pvih := pAM_Media.pbFormat ;
pAM_Media.subtype := MEDIASUBTYPE_RGB24;
pvih.bmiHeader.biWidth := 320;
pvih.bmiHeader.biHeight := 240;
pvih.AvgTimePerFrame := 10000000 div 15;
pStreamConfig.SetFormat(pAM_Media^);
DeleteMediaType(pAM_Media);
pStreamConfig := nil;
end;
end;
But the resolution stays the same when grabbing the frames through the sample grabber
Is there anything wrong with this approach?
UPDATE
Ok i think i am now updating all the members
function SetVideoProperties(pVideoCapture: IBaseFilter):Boolean;
var
hr:HRESULT;
pStreamConfig: IAMStreamConfig;
pAM_Media: PAMMediaType;
pvih: PVIDEOINFOHEADER;
pICGP2: ICaptureGraphBuilder2;
begin
pICGP2 := FilterGraph as ICaptureGraphBuilder2;
hr := pICGP2.FindInterface(#PIN_CATEGORY_CAPTURE, nil, pVideoCapture,
IID_IAMStreamConfig, pStreamConfig);
if (SUCCEEDED(hr)) then begin
pStreamConfig.GetFormat(pAM_Media);
pAM_Media.subtype := MEDIASUBTYPE_RGB24;
pAM_Media.majortype := MEDIATYPE_Video;
pAM_Media.bFixedSizeSamples := True;
pAM_Media.bTemporalCompression := False;
pAM_Media.lSampleSize := 230400;
pAM_Media.formattype := FORMAT_VideoInfo;
pAM_Media.pUnk := nil;
pAM_Media.cbFormat := 88;
pvih := pAM_Media.pbFormat;
pvih.dwBitRate := 6912000;
pvih.AvgTimePerFrame := 10000000 div 15;
pvih.bmiHeader.biSize := 40;
pvih.bmiHeader.biWidth := 320;
pvih.bmiHeader.biHeight := 240;
pvih.bmiHeader.biPlanes := 1;
pvih.bmiHeader.biBitCount := 24;
pvih.bmiHeader.biCompression := 0;
pvih.bmiHeader.biSizeImage := 230400;
pvih.bmiHeader.biXPelsPerMeter := 0;
pvih.bmiHeader.biYPelsPerMeter := 0;
pvih.bmiHeader.biClrUsed := 0;
pvih.bmiHeader.biClrImportant := 0;
hr := pStreamConfig.SetFormat(pAM_Media^);
If Succeeded(hr) then ShowMessage('SUCCEED') else ShowMessage(IntToStr(hr));
DeleteMediaType(pAM_Media);
pStreamConfig := nil;
end;
end;
Your initialization of new media type with new resolution is incorrect/incomplete: update other members as well
You should be checking SetFormat result to detect failures in format settings
The code itself appears to be incomplete, there is no evidence you are at all changing the format and the source filter exists and added to the filter graph
See DSPack demo "...\dspack2.3.4\Demos\D6-D7\videocap"
You need to enumerate all availible formats of webcam, and then set one.
Thats the code from there:
(button Start OnClick handler)
VideoMediaTypes,
AudioMediaTypes: TEnumMediaType;
.......
// configure output Video media type
if VideoSourceFilter.FilterGraph <> nil then
begin
PinList := TPinList.Create(VideoSourceFilter as IBaseFilter);
if VideoFormats.ItemIndex <> -1 then
with (PinList.First as IAMStreamConfig) do
SetFormat(VideoMediaTypes.Items[VideoFormats.ItemIndex].AMMediaType^);
PinList.Free;
end;
Here
SetFormat(VideoMediaTypes.Items[VideoFormats.ItemIndex].AMMediaType^);
VideoMediaTypes is a list of available formats that populated when user selects the Source.
VideoFormat is GUI control (ListBox) for selecting the format

Trouble with dynamic array of timage and tlabel in delphi

I want to add an attachment, and have the form grow longer each time an attachment is added, to make room for a line that holds information about the attachment with a label and some 16X16 images. For this I chose to use a dynamic array (not sure whether that's best). each time an attachment is added, I want to create a new instance of these objects. My code doesn't seem to work. what's wrong with the follwing code?
procedure TVisionMail.AddAttachment(FileString: String);
var
I: Integer;
begin
AttCount := AttCount + 1; // increment attachment count
//set attachment file name
if (AttCount <> 0) and (edAttachment.Text <> '') then
edAttachment.text := edAttachment.text + ';';
edAttachment.text := edAttachment.text + FileString;
//move objects position down to allow space for attachment line
VisionMail.Height := VisionMail.Height + 25;
Panel1.Height := Panel1.Height + 25;
btnSend.Top := btnSend.Top + 25;
btnExit.Top := btnExit.Top + 25;
StatusMemo.Top := StatusMemo.Top + 25;
Memo1.Top := Memo1.Top + 25;
lblBody.Top := lblBody.Top + 25;
//Allocate memory for arrays
SetLength(newImg, AttCount);
SetLength(newlbl, AttCount);
SetLength(newDel, AttCount);
SetLength(newPin, AttCount);
//create new instance and set parents, positions, color, events
newImg[AttCount]:= TImage.Create(VisionMail);
with newImg[AttCount] do
begin
Parent := Panel1;
Top := Memo1.Top - 25;
Left := 408;
Height := 16;
Width := 16;
end;
newlbl[AttCount]:= TLabel.Create(VisionMail);
with newlbl[AttCount] do
begin
Parent := Panel1;
Top := newImg[I].Top + 2;
Left := 397;
Height := 3;
Width := 13;
BiDiMode := bdRightToLeft;
end;
newDel[AttCount] := TAdvToolButton.Create(VisionMail);
with newDel[AttCount] do
begin
Parent := Panel1;
Top := newImg[I].Top;
Left := 440;
Height := 16;
Width := 16;
color := clBtnFace;
colorChecked := clBtnFace;
colorDown := clBtnFace;
colorHot := clBtnFace;
OnClick := btnDelAttClick;
OnMouseEnter := btnDelAttMouseEnter;
OnMouseLeave := btnDelAttMouseLeave;
end;
newPin[AttCount] := TImage.Create(VisionMail);
with newDel[AttCount] do
begin
Parent := Panel1;
Top := newImg[I].Top;
Left := 425;
Height := 16;
Width := 16;
end;
//get Icon for extension of file
lstIcons.GetBitmap(GetIcon(ExtractFileExt
(OpenDialog1.FileName)),
newImg[AttCount].Picture.Bitmap);
newlbl[AttCount].Caption := ExtractFileName(FileString);
end;
The most obvious flaw is that you are writing off the end of all of your arrays. For example, you write
SetLength(newImg, AttCount);
and that means that the valid indices for newImg are 0 to AttCount-1 inclusive. But then you write
newImg[AttCount] := ...
and that is an out of bounds access because the last index is AttCount-1. You do the same for all your array access.
If you compile with range checking enabled, the compiler will generate a runtime error that explains what you have done wrong.
Personally I think you would be better using a record to hold your four components:
TAttachmentControls = record
Img: TImage;
Lbl: TLabel;
.. etc.
end;
And use a TList<TAttachmentControls> as your container.

Create run time TTabItem , firemonkey

Seems like i need some help with a project.
I have a routine , that constructs run time multiple TabItems on to a page control in firemonkey, and i want to have a close button on the tab.
The new tab has a checkbox for the close button loading from the styler of the tabitems.
The page has a default tab, and within some button, i am adding run time the new tab items.
I have managed to apply the event for closing the default tab page, but doesn't work within the run time created tab pages. Any help would be appreciated.
This is the piece of code for the runtime tabitems
procedure TForm1.Button1Click(Sender: TObject);
var
t : TTabItem;
o : TFmxObject;
i : Integer;
c : TControl;
begin
t := TTabItem.Create(pgeControl);
t.Parent := pgeControl;
o := FindBinding('imgCloseTabPage');
if o<>nil then
begin
for i := 0 to ComponentCount - 1 do
begin
if Components[i] is TCheckBox then
begin
TCheckBox(Components[i]).OnClick := CheckBox1Click;
end;
end;
end;
if pgeControl.TabCount - 1 <= nTab then
begin
nTab := nTab + 1;
t.Index := nTab
end
else
begin
t.Index := pgeControl.TabCount - 1;
nTab := pgeControl.TabCount - 1;
end;
t.Tag := nTab;
t.Text := 'Some text...' + ' ' + IntToStr(nTab);
t.Name := 'tabPatient' + IntToStr(nTab);
t.Height := 35;
t.Width := 250;
t.Margins.Top := 0;
t.Margins.Left := 0;
t.Margins.Bottom := 0;
t.Margins.Right := 0;
t.Padding.Top := -5;
t.Padding.Left := 0;
t.Padding.Bottom := 0;
t.Padding.Right := 0;
t.TextAlign := TTextAlign.taLeading;
t.Width := (Length(t.Text) * 6 ) + 60;
t.Font.Size := 15;
t.StyleLookup := 'tabMainStyle1';
l := TLayout.Create(t);
l.Parent := t;
l.Align := TAlignLayout.alClient;
l.Margins.Top := -5;
l.Margins.Left := 5;
l.Margins.Right := 5;
l.Margins.Bottom := 5;
l.Padding.Top := 0;
l.Padding.Left := 0;
l.Padding.Bottom := 0;
l.Padding.Right := 0;
pgeControl.ActiveTab := pgeControl.Tabs[pgeControl.TabCount - 1];
end;
You shoud call FindBinding after having applyed the custom style. Currently you call this before, so it can't find the object. Additionally there was a mistake when you was looking for the object.
so put this
o := t.FindBinding('imgCloseTabPage');
if o<>nil then
begin
if o is TCheckBox then
TCheckBox(o).OnClick := CheckBox1Click;
end;
after
t.StyleLookup := 'tabMainStyle1';
and the event should assigned.

How to add buttons created at runtime into an array?

I'm sorry if the question looks stupid,but It seems I can't use my head properly in the last hours.
I have a record,
type
TMain = record
Sub:Array of TSubMain; //another record
Button:TsSpeedButton; //this is what we need!
end;
a variable
Main:Array of TMain;
and function:
procedure TFrameSkilLView.CreateButtons(MainBtns,SubMainBtns:byte;title:Array of string);
var i,t,l,w,h:word;
section:string;
begin
l := 41; t:= 57; w := 58; h := 25;
section := 'TOOLBTN_SKILLS_MAIN';
for i := 0 to MainBtns + subMainBtns - 1 do
with TsSpeedButton.Create(nil) do begin
Width := w; Height := h; Top := t; Left := l;
if(i = 0) then SkinData.SkinSection := section + '_C' else skindata.SkinSection := section;
caption := title[i];
Parent := Self;
inc(l,w+4);
if(i = MainBtns - 1) then begin
l := 52; t := 83; w := 64; h := 28;
section := 'TOOLBTN_SKILLS_SUBMAIN';
end;
end;
end;
Lets focus on the loop 'for i := 0 to MainBtns + subMainBtns - 1'.I'd like to add the button created below to the array created above named 'Main:Array of Tmain'.
It should look like this:
for i:=0 to X do
with TsSpeedButton.Create(nil) do begin
Main[i] := this; //where this is the created sSpeedButton.
Howeve,this code can't even be compiled,so I'm asking for a doable way to accomplish what I'm trying to do.
Thank you.
First off, "this" is C++, not Pascal. The Delphi version is "Self". Second, you can't refer to the with-ed object by name. You're better off not using with at all. Try something like this:
for i:=0 to X do
begin
tempButton := TsSpeedButton.Create(nil);
Main[i] := tempButton;
//whatever else
end;

Resources