write specific line in tmemo according to line number - delphi

I am using the following to insert text from a text file into TMemo.
procedure TForm1.Button1Click(Sender: TObject);
var
SL: TStringList;
begin
SL := TStringList.Create;
try
SL.LoadFromFile('c:\testimeng\keyfil.txt');
Memo1.Lines.Assign(SL);
finally
SL.Free;
end;
end;
What i want to know is how to add a single line according to row number to TMemo when i choose the specific row number.
Example output:
During this time he has distinguished himself in the academic, sporting and cultural spheres of school life.
During this time he has distinguished himself in the academic and sporting spheres of school life.
During this time he has distinguished himself in the academic and cultural spheres of school life.
During this time he has distinguished himself in the academic aspect of school life.
During this time he has distinguished himself in both the sporting and cultural aspects of school life.
Any help appreciated.

I think you're asking about putting a single line from the TStringList into the TMemo when you specify which item (index, or line number) from the TStringList. If that's the case, you can use something like this:
Memo1.Lines.Add(SL[Index]);
So if the first line in your keyfile.txt is
During this time he has distinguished himself in the academic, sporting and cultural spheres of school life.
You would use
Memo1.Lines.Add(SL[0]); // Desired line number - 1
Ok, after your comment to your question, I think I know what you're wanting to do. Here's one way to do it:
Drop a TListBox, a TButton, and a TMemo on your form. I arranged mine with the ListBox on the left, the button next to it (at the top right corner), and then the memo just to the right of the button.
In the FormCreate event, populate the TListBox with your text file and clear the existing memo content:
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Clear;
ListBox1.Items.LoadFromFile('c:\testimeng\keyfil.txt');
end;
Double-click the button to add an OnClick handler:
procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
begin
// If there's an item selected in the listbox...
if ListBox1.ItemIndex <> -1 then
begin
// Get the selected item
s := ListBox1.Items[ListBox1.ItemIndex];
// See if it's already in the memo. If it's not, add it at the end.
if Memo1.Lines.IndexOf(s) = -1 then
Memo1.Lines.Add(s);
end;
end;
Now run the app. Click on an item in the listbox, and then click the button. If the item is not already present in the memo, it will be added as a new last line. If it's already there, it won't be added (to prevent duplicates).
If you're wanting to add it to the end of the current last line (extending the paragraph, perhaps), then you'd do it like this:
// Add selected sentence to the end of the last line of the memo,
// separating it with a space from the content that's there.
Memo1.Lines[Memo1.Lines.Count - 1] := Memo1.Lines[Memo1.Lines.Count - 1] + #32 + s;
So, it should be clear by now that to add to the end of a specific line, you just grab the content that's already
there and add to it. For instance, if the user types 3 into a TEdit:
procedure TForm1.FormCreate(Sender: TObject);
begin
SL := TStringList.Create;
SL.LoadFromFile('c:\testimeng\keyfil.txt');
end;
procedure TForm1.ButtonAddTextClick(Sender: TObject);
var
TheLine: Integer;
begin
// SL is the TStringList from the FormCreate code above
TheLine := StrToIntDef(Edit1.Text, -1);
if (TheLine > -1) and (TheLine < Memo1.Lines.Count) then
if TheLine < SL.Count then
Memo1.Lines[TheLine] := Memo1.Lines[TheLine] + SL[TheLine];
end;

Write a specific line with String by Mouse Clicking on TMemo
Procedure TForm1.Button1Click(Sender: TObject);
Var SL: TStringList;
LineNumber : Integer;
Begin
LineNumber := Memo1.Perform(EM_LINEFROMCHAR, Memo1.SelStart, 0);
Memo1.SelStart := Memo1.Perform(EM_LINEINDEX, LineNumber, 0);
Memo1.SelLength := Length(Memo1.Lines[LineNumber]) ;
Memo1.SetFocus;
SL := TStringList.Create;
try
SL.LoadFromFile('c:\testimeng\keyfil.txt');
Memo1.SelText := SL.Strings[0];
finally
SL.Free;
end;
End;

Related

How to get Id values for the adjacent records in TcxGrid (TcxGridDBTableView)

I have DevExpress cxGrid and I would like to get the Ids of the adjacent records. I can use them in the following use case: user deletes focused record and I position the (grid view) cursor on one of the adjacent records (as determined but the current sorting and grouping order of the grid view). Otherwise the position of the grid cursor is poorly determined after removal of the record and after refreshing the grid view.
I have made the following attempts but they are not working - the Id values are junk:
procedure GetAdjacentRecordIds(AView: TcxGridDBTableView; ACdFieldName: string; var APrevId, AId, ANextId: Integer);
var Item: TcxCustomGridTableItem;
RecIdx: Integer;
i, RecCount: Integer;
begin
APrevId:=-1;
AId:=-1;
ANextId:=-1;
if Trim(AIdFieldName)='' then Exit;
if not Assigned(AView) then Exit;
if not Assigned(AView.DataController) then Exit;
Item:=AView.DataController.GetItemByFieldName(UpperCase(AIdFieldName));
if not Assigned(Item) then Exit;
{//First attempt, didn't work, AId was the right one, but APrevId and ANextId were junk
RecIdx:=AView.DataController.FocusedRecordIndex;
AId:=AView.DataController.Values[RecIdx, Item.Index];
APrevId:=AView.DataController.Values[RecIdx-1, Item.Index];
ANextId:=AView.DataController.Values[RecIdx+1, Item.Index];}
//Second attempt, doesn't work, all three Ids are junk
RecIdx:=-1;
RecCount:=AView.ViewData.RecordCount;
for i:=0 to RecCount-1 do begin
if AView.ViewData.Records[i].Focused then begin
RecIdx:=1;
Break;
end;
end;
if RecIdx<0 then Exit;
AId:=AView.ViewData.Records[RecIdx].Values[Item.Index];
if RecIdx>0 then
APrevId:=AView.ViewData.Records[RecIdx-1].Values[Item.Index];
if RecIdx<RecCount then
ANextId:=AView.ViewData.Records[RecIdx+1].Values[Item.Index];
end;
How can I correct this code to get the field values for adjacent records. Or maybe I should use Grid navigator and do prev/next on it, but I would like to find the values in invisible. And DataSet.DisableControls may stop the Grid navigator?
I used the DevExpress knowledgebase to find this answer. You are referencing the internal storage of the grid incorrectly. You can also use dataset.previous and dataset.next to position the record pointer in a bound grid, and simply use dataset.fieldbyname(AidFieldName).AsInteger to retrieve key values.
get-cell-value-by-column-name
procedure TForm1.Button1Click(Sender: TObject);
var
AColumn: TcxGridDBColumn;
I: Integer;
AView: TcxGridDBTableView;
v: Variant;
begin
AView := cxGrid1DBTableView1;
AColumn := TcxGridDBColumn( AView.FindItemByName('cxGrid1DBTableView1Capital'));
if Assigned(AColumn) then
for I := 0 to AView.ViewData.RowCount - 1 do
v := AView.DataController.Values[AView.ViewData.Rows[0].RecordIndex, AColumn.Index];
end;
Use of the navigation functions of DataSet is not the solution, because CxGrid can have completely different sorting order. But DataController navigation is good solution and there is no visual flickering as well. So, the solution is:
RecIdx:=AView.DataController.FocusedRecordIndex;
AId:=AView.DataController.Values[RecIdx, Item.Index];
if not AView.DataController.IsBOF then begin
AView.DataController.GotoPrev;
RecIdx:=AView.DataController.FocusedRecordIndex;
APrevId:=AView.DataController.Values[RecIdx, Item.Index];
AView.DataController.GotoNext;
end;
if not AView.DataController.IsEOF then begin
AView.DataController.GotoNext;
RecIdx:=AView.DataController.FocusedRecordIndex;
ANextId:=AView.DataController.Values[RecIdx, Item.Index];
AView.DataController.GotoPrev;
end;

Delphi-FastReport VCL 5 Conditional highlighting

I've read this manual , and follow it , but the highlighting not working.
What I have?
Create new VCL application.
Drop a TEdit and TButton components in the form (To pass the value).
Drop a TfrxReport on the form.
Open the report in design mode.
Drop a ReportTile band in the report page.
Drop a TfrxMemoView in the ReportTitle band.
Add conditions:
1- Value <= 0 -> Red color
2- Value > 0 -> Green color
The fill color of the memo still Black even the value is >0 or <=0.
The question:
Why this conditions not working? and how can I make the conditions work?
Update:
The value was passed to the TfrxMemoView component as :
procedure TForm1.Button1Click(Sender: TObject);
Var Mem : TfrxMemoView;
begin
Mem := frxReport1.FindObject('Memo1') as TfrxMemoView;
Mem.Text := Edit1.Text;
frxReport1.ShowReport();
end;
None of the rules is applied because the Value property remains NULL. To assign a constant value from Delphi code you can either write a constant expression, for example:
procedure TForm1.Button1Click(Sender: TObject);
var
Memo: TfrxMemoView;
begin
Memo := frxReport1.FindObject('Memo1') as TfrxMemoView;
Memo.Text := Format('[%s]', [Edit1.Text]);
frxReport1.ShowReport;
end;
In the above code I've omitted check if the control was found. And, you need to be careful with the input text. It accepts only floating point values in format that won't collide in decimal separator with separator(s) defined in the ExpressionDelimiters property.
Or simply set the Value property as well:
procedure TForm1.Button1Click(Sender: TObject);
var
Memo: TfrxMemoView;
begin
Memo := frxReport1.FindObject('Memo1') as TfrxMemoView;
Memo.Text := Edit1.Text;
Memo.Value := StrToFloat(Edit1.Text);
frxReport1.ShowReport;
end;
In this one the check if the control was found is missing as well. And the conversion to float is not necessary there. The Value can be just a string convertible to float.

How to make percentage from calculation record divided with summary DBGRID Delphi

I have dbgrid which display column subtotal and column percentage, how to display column percentage from this formula : (subtotal / grandtotal) * 100% ? for detail information please see below picture
I couldnt modify my SQL, because my SQL is very complicated, so i think solution maybe use calculated field, doesnt it? Could someone help me to solve this problem.
Thanks in advanced.
The following assumes that your dataset doesn't actually contain the last row you've shown, the one that contains "111077, 100" - if it does, then the steps I show below to calculate the GrandTotal are unnecessary, and you only need to populate the Percent calculated field, which is trivial.
If your DataSet is a TClientDataSet, you can implement the Percent values quite easily using the
combination of a TAggregateField to represent the GrandTotal and a calculated field to represent each data row's contribution towards the GrandTotal. See code below.
If you are not using a TClientDataSet already then you have several options,
including
If your DataSet is of a type which supports aggregate fields then you can do the equivalent of the code below.
Use your existing DataSet as the dataset source of a TDataSetProvider, and use the TDataSetProvider as the Provider of a TClientDataSet and use the TClientDataSet to supply the data to your grid.
Don't use a TClientDataSet and/or TAggregateField and instead do similar to what is shown below with your existing DataSet, but make the Percent field an fkInternalCalc field if your DataSet type supports it, or an fkCalculated one if not, omit the GrantTotal TAggregateField field and calculate the GrandTotal in code. One way to do this would be to calculate it by a once-only traversal of the dataset (while not DataSet.Eof ...) after you open it.
In the code below, I've created all the fields in code, rather than using the Object Inspector's Fields editor, so you can easily see exactly what are the minimum settings necessary to get a TAggregateField to work.
Note: I could be wrong but don't think you could get a standard TDBGrid to display the final, 100%, row of your screenshot. Somthething similar could be done using the Developer Express TcxGrid, amongst others, but if you need a TDBGrid to do this, you should ask how to in a new question.
Code
TForm1 = class(TForm)
CDS: TClientDataSet;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
procedure CDSCalcFields(DataSet: TDataSet);
procedure FormCreate(Sender: TObject);
private
CDSID : TIntegerField;
CDSTotal : TCurrencyField;
CDSPercent : TFloatField;
CDSGrandTotal : TAggregateField;
public
procedure SetUp;
end;
[...]
procedure TForm1.SetUp;
var
i : Integer;
begin
CDSID := TIntegerField.Create(Self);
CDSID.FieldName := 'ID';
CDSID.FieldKind := fkData;
CDSID.DataSet := CDS;
CDSTotal := TCurrencyField.Create(Self);
CDSTotal.FieldName := 'Total';
CDSTotal.FieldKind := fkData;
CDSTotal.DataSet := CDS;
CDSPercent := TFloatField.Create(Self);
CDSPercent.FieldName := 'Percent';
CDSPercent.FieldKind := fkInternalCalc;
CDSPercent.DataSet := CDS;
CDSGrandTotal := TAggregateField.Create(Self);
CDSGrandTotal.FieldName := 'GrandTotal';
CDSGrandTotal.FieldKind := fkAggregate;
CDSGrandTotal.Expression := 'Sum(Total)';
CDSGrandTotal.DataSet := CDS;
CDSGrandTotal.Active := True;
CDS.OnCalcFields := CDSCalcFields;
CDS.IndexFieldNames := 'ID';
CDS.CreateDataSet;
for i := 1 to 2 do begin
CDS.InsertRecord([i, i]);
end;
CDS.First;
end;
procedure TForm1.CDSCalcFields(DataSet: TDataSet);
var
Value : Double;
V : Variant;
begin
V := CDSGrandTotal.Value;
if not VarIsNull(V) then begin
Value := CDSTotal.AsFloat;
Value := Value * 100 / V;
CDSPercent.Value := Value;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
SetUp;
end;

Loop through records on a cxgrid and update a field/column

I have a cxGrid where I apply a filter to select certain records. When that is done I want to be able to update a field/column in the grid to mark each record that is to be used for the next operation.
I haven't been able to figure this out
Maybe I haven't been specific enough when describing my problem.
I have the cxGrid where I have applied a filter selecting some records.
What I then need to do is to click a columnheader and then have a field called fldselected set to True for these records.
What your updated q is asking for is straightforward and as usual with Devex stuff, it's
all in the OLH as long as you can find your way into it.
A way to find which rows currently match the filter is to use the
cxGrid1DBTableView1.DataController.FilteredRecordIndex[]
property. You can then find that record in the dataset to process it in some way using
cxGrid1DBTableView1.DataController.LocateByKey().
Update: The original version of this answer assumed that the dataset had an integer ID field.
As the OP has said he uses GUIDs instead, I've upddated it accordingly.
Assuming the TClientDataSet CDS1 has fields Guid : TGuidField, Name : TStringfield, size 32
and Selected : TBooleanField and is connected to
a cxDBTableView, with filtering enabled, of a TcxGrid.
Make sure the cxGrid1DBTableView1.DataController.KeyFieldNames is set to 'Guid'.
Add a regular TDBGrid to the form and point it at the same datasource as the TcxGrid. The point
of this is to make it easy to verify that the code is working as required.
Add the code below to the unit, and point cxDBTableView1's OnColumnHeaderClick at
the handler cxGrid1DBTableView1ColumnHeaderClick, and the form's OnCreate at the FormCreate.
Compiler & run
Code:
procedure TForm1.cxGrid1DBTableView1ColumnHeaderClick(Sender: TcxGridTableView;
AColumn: TcxGridColumn);
begin
if AColumn = cxGrid1DBTableView1Name then
ProcessFilteredRecords;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
AGuid : TGuid;
i : Integer;
lResult : Longint;
begin
CDS1.IndexFieldNames := 'Name';
CDS1.CreateDataSet;
for i:= 0 to 6 do begin
lResult := SysUtils.CreateGUID(AGuid);
CDS1.Insert;
CDS1.FieldByName('Name').AsString := Chr(Ord('A') + i);
CDS1.FieldByName('Guid').AsString := GuidToString(AGuid);
CDS1.FieldByName('Selected').AsBoolean := False;
CDS1.Post;
end;
CDS1.First;
end;
procedure TForm1.ProcessFilteredRecords;
var
V : Variant;
i,
Index: Integer;
BM : TBookMark;
begin
BM := CDS1.GetBookMark;
CDS1.DisableControls;
try
for i := 0 to cxGrid1DBTableView1.DataController.FilteredRecordCount - 1 do begin
Index := cxGrid1DBTableView1.DataController.FilteredRecordIndex[i];
// Next, get the GUID value of the row
V := cxGrid1DBTableView1.DataController.Values[Index, 0];
if cxGrid1DBTableView1.DataController.LocateByKey(V) then begin
CDS1.Edit;
CDS1.FieldByName('Selected').AsBoolean := True;
CDS1.Post;
end;
end;
finally
CDS1.EnableControls;
CDS1.GotoBookmark(BM);
CDS1.FreeBookmark(BM);
end;
end;
Check out https://www.devexpress.com/Support/Center/Question/Details/A1095, the article from Dev Express. Don't let the fact that the article is 11 years old fool you. The same technique still applies. And you can set this up either in code or in the grid editor.
Create the column in the grid editor.
Set the columns DataBinding.ValueType to Boolean (if that's what you want the checkbox to represent)
Set the Data Controller's KeyFieldNames property. Very important! I have spent hours scratching my head with an non-functioning unbound column only to find that the KeyFieldNames wasn't set.
An unbound column can be referenced in your next operation using the DataController Records or Values array, depending on how you set that up. Because it is unbound you cannot reference it through the underlying DataSet though.

Incremental search of a dbgrid using an edit box

It has been awhile since I have done any programming in Delphi and I was looking around for some examples on how to incrementally search a dbgrid by typing a search term into a edit box and I found the following code which seems to do the trick for the most part, but it checks for the filter condition on every column in the grid and I would like to limit the filter condition so it only checks one column in the grid (Column 1 for instance), how would I do that using the code provided ?
procedure TForm1.Edit1Change(Sender: TObject);
begin
FDTable1.Filtered := false;
FDTable1.Filtered := Edit1.Text <> '';
end;
procedure TForm1.FDTable1FilterRecord(DataSet: TDataSet;
var Accept: Boolean);
var
i: integer;
begin
for i := 0 to DataSet.FieldCount - 1 do begin
Accept := Pos(UpperCase(Edit1.Text),
UpperCase(DataSet.Fields[i].AsString)) = 1;
if Accept then exit;
end;
end;

Resources