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;
Related
I try to add TLineView objects to a report.
The number of lines is depending on a certain number, retrieved by the reports dataset.
I have put my code into the scripts initialization part and in a very experimental test version it looks like this:
var nol, i: integer;
child, newChild: TfrxChild;
noteLine1, noteLine2: TfrxLineView;
page: TfrxPage;
begin
page := ReportName;
nol := <DS_MAIN."VOLUME"> /2;
nol := nol + <DS_MAIN."VOLUME"> mod 2;
child3.child := TfrxChild.create(nil);
newchild := child3.child;
newChild.Visible := true;
noteLine1 := TfrxLineView.create(newChild);
noteLine1.name := 'nl1000';
noteLine1.Top := 0.73;
noteLine1.Width := 7.5;
noteLine1.Left := 3;
noteLine1.Visible := true;
noteLine1.Parent.Objects.Remove(noteLine1);
noteLine1.Parent.Objects.Add(noteLine1);
// newChild.Objects.Add(noteLine1);
noteLine2 := TfrxLineView.create(newChild);
noteLine2.name := 'nl1001';
noteLine2.Top := 0.73;
noteLine2.Width := 7.5;
noteLine2.Left := 11.2;
newChild.Objects.Add(noteLine2);
noteLine2.Visible := true;
for i := 1 to nol do begin
Child := TfrxChild.create(nil);
NewChild.child := Child;
newChild := child;
end;
end.
Instead of getting two lines side by side, with a gap between them, I get only a single short line of a length of around 3-4 mm.
The above code is just a snap of my trial-and-error session.
Hope now that there could be anyone to give me some clues.
If I understand your question correctly, you need to consider at least the following:
With your for loop you create bands, not lines. You may try to change the logic and create objects (memos, lines, shapes) with bands as owners.
The objects’ coordinates and sizes are set in pixels, so you need an additional calculation.
From documentation:
Objects’ coordinates and sizes are set in pixels. Since the «Left,»
«Top,» «Width,» and «Height» properties of all objects have the
«Extended» type, you can point out non-integer values. The following
constants are defined for converting pixels into centimeters and
inches:
fr01cm = 3.77953;
fr1cm = 37.7953;
fr01in = 9.6;
fr1in = 96;
The following working example generates five TfrxLineView objects. Just put an empty report on your form and add report title band:
procedure TfrmMain.btnPreviewClick(Sender: TObject);
var
nol, i: integer;
left: Extended;
band: TfrxReportTitle;
line: TfrxLineView;
begin
// Band
band := (report.Report.FindObject('ReportBand') as TfrxReportTitle);
// Lines generation
left := 3;
nol := 5;
for i := 1 to nol do begin
line := TfrxLineView.Create(band);
line.CreateUniqueName;
line.Top := 0.73;
line.Width := fr1cm * 2;
line.Left := left;
left := left + line.Width + 30;
end;
// Report preview
report.ShowReport(False);
end;
This is my final solution:
procedure Child8OnBeforePrint(Sender: TfrxComponent);
var nol, i: integer;
left1, left2: extended;
child, newChild: TfrxChild;
noteLine1, noteLine2, line: TfrxLineView;
page: TfrxPage;
band: TfrxChild;
begin
nol := <DS_MAIN."VOLUME"> /2;
nol := nol + <DS_MAIN."VOLUME"> mod 2;
band := TfrxChild(TRP_ORDER_NOTE.FindObject('Child9'));
// Lines generation
left1 := 3*fr1cm;
left2 := 11.2*fr1cm;
for i := 1 to nol do begin
line := TfrxLineView.Create(band);
line.Name := 'noteLine'+intToStr(1+2*(i-1+trunc(random*1000000))); //Panic solution
line.Top := fr1cm*(0.73 + (i-1)*0.75);
line.Width := 7.5*fr1cm;
line.Left := left1;
if (<DS_MAIN."VOLUME"> mod 2 > 0 ) and (i = nol) then
exit
else
begin
line := TfrxLineView.Create(band);
line.Name := 'noteLine'+intToStr(2*i+trunc(random*1000000));
line.Top := fr1cm*(0.73 + (i-1)*0.75);
line.Width := 7.5*fr1cm;
line.Left := left2;
end;
end;
end;
I want to view the records of the database table in the frame being created and run time contains Label to display this data
I do not know what the code is
The data appears duplicate.
procedure TForm3.Button1Click(Sender: TObject);
var
cartRow: TFrm;
lin :SmallInt;
posX,posY : SmallInt;
s , id: string;
i : Integer;
begin
ScrollBox1.DestroyComponents;
s := FDQuery1.FieldByName('CountryAr').AsString;
id:= FDQuery1.FieldByName('CountryID').AsString;
posX := 0;
posY := 0;
for lin := 0 to FDTable1.RecordCount - 1 do
begin
cartRow := TFrm.Create(ScrollBox1);
cartRow.Parent :=ScrollBox1;
cartRow.Name := '';
cartRow.Left := posX -1;
cartRow.Top := posY -1;
cartRow.Label1.Caption := (s);
cartRow.Label2.Caption :=(id);
cartRow.Width := (ScrollBox1.Width) -3;
cartRow.Height := 35;
posY := posY + cartRow.Height +1;
end;
cartRow.Free;`
You have multiple issues in your code. First, you assign the values to s and id once, and then use those same values for every label, ignoring anything in the database after that assignment. Second, you never advance the record pointer in your loop, which means that it will end up in an infinite loop. Third, you're looping through FDTable1 fields, but reading the values from FDQuery1. Fourth, you're unnecessarily using a call to RecordCount instead of a simple while not Eof loop. And finally, you're freeing CartRow when it shouldn't be free'd; you're assigning ScrollBox1 as the owner of the control created, which means the scrollbox will free it when the scrollbox is free'd.
Something like this will work much better for you:
procedure TForm3.Button1Click(Sender: TObject);
var
cartRow: TFrm;
posX,posY : SmallInt;
begin
ScrollBox1.DestroyComponents;
posX := 0;
posY := 0;
FDQuery1.First;
while not FDQuery1.Eof do
begin
cartRow := TFrm.Create(ScrollBox1);
cartRow.Parent := ScrollBox1;
cartRow.Left := posX - 1;
cartRow.Top := posY - 1;
cartRow.Label1.Caption := FDQuery1.FieldByName('CountryAr').AsString;
cartRow.Label2.Caption := FDQuery1.FieldByName('CountryID').AsString;
cartRow.Width := ScrollBox1.Width - 3;
cartRow.Height := 35;
posY := posY + cartRow.Height + 1;
FDQuery1.Next;
end;
end;
I am a newbie to this Delphi. I have been given an assignment that to create buttons dynamically. But the problem is that all buttons have to be aligned in a manner that it should fit inside the whole screen. i.e, if 10 buttons created the whole screen should be filled. Or if 9 is given 9 should be present and filled in the screen. Is it possible to do that? I tried and searched everywhere. But was helpless.
Please help me if its possible. A good example is also appreciated since I mentioned earlier I am really new to this. The code I did follows here.
procedure TfrmMovieList.PnlMovieClick(Sender: TObject);
begin
for i := 0 to 9 do
begin
B := TButton.Create(Self);
B.Caption := Format('Button %d', [i]);
B.Parent := Panel1;
B.Height := 23;
B.Width := 100;
B.Left := 10;
B.Top := 10 + i * 25;
end;
end;
This looks workable to me:
procedure TForm1.CreateButtons(aButtonsCount, aColCount: Integer; aDestParent: TWinControl);
var
rowCount, row, col, itemWidth, itemHeight: Integer;
item: TButton;
begin
if aColCount>aButtonsCount then
aColCount := aButtonsCount;
rowCount := Ceil(aButtonsCount / aColCount);
itemHeight := aDestParent.Height div rowCount;
itemWidth := aDestParent.Width div aColCount;
for row := 0 to rowCount-1 do begin
for col := 0 to aColCount-1 do begin
item := TButton.Create(Self);
item.Caption := Format('Button %d', [(row*aColCount)+col+1]);
item.Left := itemWidth*col;
item.Top := itemHeight*row;
item.Width := itemWidth;
item.Height := itemHeight;
item.Parent := aDestParent;
Dec(aButtonsCount);
if aButtonsCount=0 then
Break;
end; // for cols
end; // for rows
end;
An example of usage is:
procedure TForm1.Button1Click(Sender: TObject);
begin
CreateButtons(10, 4, Panel1);
end;
The function Ceil requires the uses of unit Math.
The method receives the count of buttons and the numbers of columns to calculate the number of rows. It also receives the destination parent where the buttons will be located.
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.
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.