In my application i save some edit value in a Tstringlist with code below:
procedure TForm1.Button3Click(Sender: TObject);
var
F: TStringList;
begin
SaveDialog1.Filter := 'GPP files (*.GPP)|*.GPP';
if SaveDialog1.Execute then
begin
F := TStringList.Create;
with F do
begin
Add(label7.Caption);
Add(label21.Caption);
SaveToFile(Savedialog1.Filename);
Free;
end;
end;
end;
I want to save Tradiobutton state too in this Tstringlist.
Can you help me?
Regards
Making an answer just to show the code sample in properly formatted form
To read:
try/finally pattern - http://docwiki.embarcadero.com/RADStudio/XE2/en/Writing_a_Finally_Block_(Delphi)
TIniFile class and boolean values - http://docwiki.embarcadero.com/Libraries/XE2/en/System.IniFiles.TCustomIniFile.WriteBool - as a somewhat outdated with limited capabilities but a very simple text structured format.
So your code would become something like
const ini_def_sect = 'Default Section';
procedure TForm1.Button3Click(Sender: TObject);
var
F: TCustomIniFile;
begin
SaveDialog1.Filter := 'GPP files (*.GPP)|*.GPP';
if SaveDialog1.Execute then
begin
F := TIniFile.Create(SaveDialog1.Filename);
try
F.WriteString(ini_def_sect, label7.Name, label7.Caption);
F.WriteString(ini_def_sect, label21.Name, label21.Caption);
F.WriteBool(ini_def_sect, radiobutton1.Name, radiobutton1.Checked);
F.UpdateFile;
finally
F.Destroy;
end;
end;
end;
Or in VCL with-based style (that many dislike as they dislike with statement in Pascal)
const ini_def_sect = 'Default Section';
procedure TForm1.Button3Click(Sender: TObject);
begin
SaveDialog1.Filter := 'GPP files (*.GPP)|*.GPP';
if SaveDialog1.Execute then
begin
with TIniFile.Create(Savedialog1.Filename) do
try
WriteString(ini_def_sect, label7.Name, label7.Caption);
WriteString(ini_def_sect, label21.Name, label21.Caption);
WriteBool(ini_def_sect, radiobutton1.Name, radiobutton1.Checked);
UpdateFile;
finally
Destroy;
end;
end;
end;
And you REALLY REALLY should give your variables (including labels, forms, radio buttons, etc) reasonable names while you still can remember a bit about what do each of those mean. Trust me - a month or two and you would forget.
PS: reading the structured file could be something like
procedure TMainForm.btnOpenClick(Sender: TObject);
begin
OpenDialog1.Filter := 'GPP files (*.GPP)|*.GPP';
if OpenDialog1.Execute then
begin
with TIniFile.Create(OpenDialog1.Filename) do
try
label7.Caption := ReadString(ini_def_sect, label7.Name, '');
label21.Caption := ReadString(ini_def_sect, label21.Name, '');
radiobutton1.Checked := ReadBool(ini_def_sect, radiobutton1.Name, False);
finally
Destroy;
end;
end;
end;
Related
Here its a VCL app and I have a link with my Ini file and I wanna keep adding lines in there with time and date stamps with press of a button.
private
FLog: TStringList;
FIni: TIniFile;
aTime: TDateTime;
procedure TForm2.btnBreakClick(Sender: TObject);
begin
FLog := TStringList.Create;
try
aTime := Now;
begin
FIni.WriteString('FileName', 'Break', FormatDateTime('dd/mm/yyyy hh:nn', aTime));
end;
finally
FLog.Free;
end
end;
With this piece of code I can only replace the previous time and date stamp I have tried to do it with a for loop but without succes.
This is the outcome with the current few lines of code.
[FileName]
Break=09-10-2018 13:35
And what I want is that everytime I hit the break button it needs to add on to the file with a other time.
An INI file contains key/value pairs. To do what you are asking for, you need to create a unique key name with every button press, otherwise you are just overwriting an existing value each time, as you have already discovered.
Try something more like this:
procedure TForm2.btnBreakClick(Sender: TObject);
var
Keys: TStringList;
MaxBreak, I, Num: Integer;
begin
MaxBreak := 0;
Keys := TStringList.Create;
try
FIni.ReadSection('FileName', Keys);
for I := 0 to Keys.Count-1 do
begin
if StartsText('Break', Keys[I]) then
begin
if TryStrToInt(Copy(Keys, 6, MaxInt), Num) then
begin
if Num > MaxBreak then
MaxBreak := Num;
end;
end;
end;
finally
Keys.Free;
end;
FIni.WriteString('FileName', 'Break'+IntToStr(MaxBreak+1), FormatDateTime('dd/mm/yyyy hh:nn', Now));
end;
Or this:
procedure TForm2.btnBreakClick(Sender: TObject);
var
I: Int64;
Key: string;
begin
for I := 1 to Int64(MaxInt) do
begin
Key := 'Break' + IntToStr(I);
if not FIni.ValueExists('FileName', Key) then
begin
FIni.WriteString('FileName', Key, FormatDateTime('dd/mm/yyyy hh:nn', Now));
Exit;
end;
end;
end;
Or this:
procedure TForm2.btnBreakClick(Sender: TObject);
var
NumBreaks: Integer;
begin
NumBreaks := FIni.ReadInteger('FileName', 'NumBreaks', 0);
Inc(NumBreaks);
FIni.WriteInteger('FileName', 'NumBreaks', NumBreaks);
FIni.WriteString('FileName', 'Break' + IntToStr(NumBreaks), FormatDateTime('dd/mm/yyyy hh:nn', Now));
end;
Although you referred to TIniFile, your post and your comments tell me that that is not necessarily what you want. TIniFile is not really intended for the kind of usage you are describing, although it can be used (as the other answer shows).
For simple recording of events I suggest an ordinary text file, and for adding events to it, a TStringList as in the following example. The example is a simplified extract from code I used myself long time ago.
var
EventFile: TFileName;
procedure EventRecorder(EventTime: TDateTime; Description, Comment: string);
var
sl: TStringList;
es: string;
begin
sl: TStringList;
try
if FileExists(EventFile) then
sl.LoadFromFile(EventFile);
es := FormatDateTime('yyyy-mm-dd hh:nn:ss', EventTime)+' '+Description+' '+comment;
sl.Add(es);
sl.SaveToFile(EventFile);
finally
sl.free;
end;
end;
Typical usage
procedure TForm2.btnBreakClick(Sender: TObject);
begin
EventRecorder(now, 'Break', '');
end;
I'm using Delphi 5 Enterprise because that's what the program I'm working with was written in. I have written a procedure which saves bitmaps to an Access database quite happily. Now I want to be able to retrieve the bitmaps. Saving the bitmaps, I use SaveToStream. Retrieving them, I used LoadFromStream but the compiler tells me that it doesn't recognise that function. The code is below:
procedure TForm1.Button2Click(Sender: TObject);
var
Field : TBlobField;
Stream : TStream;
BMap : TBitMapImage;
begin
if BloBQuery.Active then
begin
Field := TBlobField(BlobQuery.FieldByName('Blob'));
Stream := BlobQuery.CreateBlobStream(Field, bmRead);
BMap := TBitMapImage.Create;
try
Image2.Picture.Graphic := BMap.LoadFromStream(Stream);
finally
BMap.Free;
Stream.Free;
end;
end;
end;
Can anyone tell me when LoadFromStream won't work? It seems odd! Thanks.
The code which wrote the bitmap was:
procedure TForm1.Button1Click(Sender: TObject);
var
Field : TBlobField;
Stream : TStream;
begin
if (BlobQuery.Active = True) and (Image1.Picture.Graphic <> nil) then begin
BlobQuery.Insert;
Field := TBlobField(BlobQuery.FieldByName('Blob'));
Stream := BlobQuery.CreateBlobStream(Field, bmWrite);
try
Image1.Picture.Graphic.SaveToStream(Stream);
finally
Stream.Free;
BlobQuery.Post;
end;
end;
end;
Assuming Image1.Picture.Graphic was pointing at a TBitmap object when you saved it to the DB, you need to use a TBitmap object instead of a TBitMapImage object when reading the image back out, eg:
procedure TForm1.Button2Click(Sender: TObject);
var
Field : TBlobField;
Stream : TStream;
BMap : TBitmap;
begin
if BlobQuery.Active then
begin
Field := TBlobField(BlobQuery.FieldByName('Blob'));
Stream := BlobQuery.CreateBlobStream(Field, bmRead);
try
BMap := TBitmap.Create;
try
BMap.LoadFromStream(Stream);
Image2.Picture.Graphic := BMap;
finally
BMap.Free;
end;
finally
Stream.Free;
end;
end;
end;
Alternatively:
procedure TForm1.Button2Click(Sender: TObject);
var
Field : TBlobField;
Stream : TStream;
begin
if BlobQuery.Active then
begin
Field := TBlobField(BlobQuery.FieldByName('Blob'));
Stream := BlobQuery.CreateBlobStream(Field, bmRead);
try
Image2.Picture.Bitmap.LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
end;
In Delphi 6, I could change the Mouse Cursor for all forms using Screen.Cursor:
procedure TForm1.Button1Click(Sender: TObject);
begin
Screen.Cursor := crHourglass;
end;
I am searching the equivalent in Firemonkey.
Following function does not work:
procedure SetCursor(ACursor: TCursor);
var
CS: IFMXCursorService;
begin
if TPlatformServices.Current.SupportsPlatformService(IFMXCursorService) then
begin
CS := TPlatformServices.Current.GetPlatformService(IFMXCursorService) as IFMXCursorService;
end;
if Assigned(CS) then
begin
CS.SetCursor(ACursor);
end;
end;
When I insert a Sleep(2000); at the end of the procedure, I can see the cursor for 2 seconds. But the Interface probably gets freed and therefore, the cursor gets automatically resetted at the end of the procedure. I also tried to define CS as a global variable, and add CS._AddRef at the end of the procedure to prevent the Interface to be freed. But it did not help either.
Following code does work, but will only work for the main form:
procedure TForm1.Button1Click(Sender: TObject);
begin
Application.MainForm.Cursor := crHourGlass;
end;
Since I want to change the cursor for all forms, I would need to iterate through all forms, but then the rollback to the previous cursors is tricky, as I need to know the previous cursor for every form.
My intention:
procedure TForm1.Button1Click(Sender: TObject);
var
prevCursor: TCursor;
begin
prevCursor := GetCursor;
SetCursor(crHourglass); // for all forms
try
Work;
finally
SetCursor(prevCursor);
end;
end;
You'd have to implement your own cursor service that makes it possible to enforce a certain cursor.
unit Unit2;
interface
uses
FMX.Platform, FMX.Types, System.UITypes;
type
TWinCursorService = class(TInterfacedObject, IFMXCursorService)
private
class var FPreviousPlatformService: IFMXCursorService;
class var FWinCursorService: TWinCursorService;
class var FCursorOverride: TCursor;
class procedure SetCursorOverride(const Value: TCursor); static;
public
class property CursorOverride: TCursor read FCursorOverride write SetCursorOverride;
class constructor Create;
procedure SetCursor(const ACursor: TCursor);
function GetCursor: TCursor;
end;
implementation
{ TWinCursorService }
class constructor TWinCursorService.Create;
begin
FWinCursorService := TWinCursorService.Create;
FPreviousPlatformService := TPlatformServices.Current.GetPlatformservice(IFMXCursorService) as IFMXCursorService; // TODO: if not assigned
TPlatformServices.Current.RemovePlatformService(IFMXCursorService);
TPlatformServices.Current.AddPlatformService(IFMXCursorService, FWinCursorService);
end;
function TWinCursorService.GetCursor: TCursor;
begin
result := FPreviousPlatformService.GetCursor;
end;
procedure TWinCursorService.SetCursor(const ACursor: TCursor);
begin
if FCursorOverride = crDefault then
begin
FPreviousPlatformService.SetCursor(ACursor);
end
else
begin
FPreviousPlatformService.SetCursor(FCursorOverride);
end;
end;
class procedure TWinCursorService.SetCursorOverride(const Value: TCursor);
begin
FCursorOverride := Value;
TWinCursorService.FPreviousPlatformService.SetCursor(FCursorOverride);
end;
end.
MainUnit:
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
begin
TWinCursorService.CursorOverride := crHourGlass;
try
Sleep(2000);
finally
TWinCursorService.CursorOverride := crDefault;
end;
end;
The IFMXCursorService is how the FMX framework manages cursors. It is not intended for your use. The mechanism that you are meant to use is the form's Cursor property.
This means that you will need to remember the cursor for each form in order to restore it. I suggest that you use a dictionary to do that. Wrap the functionality up into a small class and then at least the pain is localized to the implementation of that class. You can make the code at the call site reasonable.
I did some searching and only found more unanswered questions. :)
Using D5pro.
I want to reassign the DataSource to a TDBGrid at run time. I have seven identical structured DataSets and depending on a button click I want the appropriate DataSet displayed in the grid.
I have tried everything and I cannot get it to show the next DataSet. It sticks with the first one assigned at start up. I am getting to overkill approaches and still nothing is working. Here's where I am at the moment.
procedure SetSource(var aSrc : TDataSource);
begin
aSrc.DataSet.Close;
dbgridShowData.DataSource:=aSrc;
aSrc.DataSet.Open;
aSrc.DataSet.First;
aSrc.DataSet.Refresh;
end;
Where am I going wrong?
Thanks
You can change the Dataset shown by a DBGrid quite easily at runtime quite easily. There two approaches:
1: use a single DataSource assigned to DBGrid.DataSource and change the DataSource.DataSet to the desired DataSet. Here is a simple example with all assignments made at runtime.
procedure TForm1.FormCreate(Sender: TObject);
begin
DBGrid1.DataSource := DataSource1;
DataSet1.Active := true;
DataSet2.Active := true;
DataSet3.Active := true;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
DataSource1.DataSet := DataSet1;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DataSource1.DataSet := DataSet2;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
DataSource1.DataSet := DataSet3;
end;
2: use a DataSource for each DataSet and change DBGrid.DataSource to the desired DataSource. Here is a simple example with all assignments made at runtime.
procedure TForm1.FormCreate(Sender: TObject);
begin
DataSource1.DataSet := DataSet1;
DataSource2.DataSet := DataSet2;
DataSource3.DataSet := DataSet3;
DataSet1.Active := true;
DataSet2.Active := true;
DataSet3.Active := true;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
DBGrid1.DataSource := DataSource1;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DBGrid1.DataSource := DataSource2;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
DBGrid1.DataSource := DataSource3;
end;
If you define the columns of the DBGrid, the structure of the DataSets will need to be the the same, or you will have to change the column definitions when you change the Dataset displayed.
I prefer using a DataSource per DataSet because it is more flexible.
You probably need to change the DataSource.DataSet instead:
procedure SetDataFromDataSet(const aDataSource: TDataSource;
const aNewDataSet: TDataSet);
begin
aDataSource.DataSet.Close;
aDataSource.DataSet := aNewDataSet;
if not aNewDataSet.Active then
aNewDataSet.Open;
end;
Sample use:
SetDataFromDataSet(DataSource1, CustomerQuery);
You may not want to close and open datasets globally like this, though. It's probably better to do that from the calling code. Of course, that would depend on what you need for your app.
Tested with Delphi5 pro.
procedure TForm1.setDataSourceDataSet(var newDataSource:TDataSource);
begin
if DBgrid1.DataSource = nil then begin
DBgrid1.DataSource:=newDataSource;
end else begin
if DBgrid1.DataSource.Name = newDataSource.Name then exit;
DBGrid1.DataSource.Enabled:=False;
DBgrid1.DataSource:=newDataSource;
end;
If DBgrid1.DataSource.DataSet.active=False then DBgrid1.DataSource.DataSet.active:=True;
DBGrid1.DataSource.Enabled:=True;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
setDataSourceDataSet(DataSource1);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
setDataSourceDataSet(DataSource2);
end;
The secret lies in:
DBGrid1.DataSource.Enabled:=False;
...making changes...
DBGrid1.DataSource.Enabled:=True;
Tested with D5Pro
I want to know, how to add or remove windowMenu option of actionMenuBar component, i have a mdi aplication i can add the option but later I can't remove it
sorry my english
i have this:
//add windowmenu and works fine
procedure TForm2.Button1Click(Sender: TObject);
begin
Form1.ActionMainMenuBar1.WindowMenu := '&Ventana';
end;
//remove windowmenu but dont work
procedure TForm2.Button2Click(Sender: TObject);
begin
Form1.ActionMainMenuBar1.WindowMenu := '';
end;
type
ActionMainMenuBarAccess = class(TActionMainMenuBar);
procedure TForm2.Button2Click(Sender: TObject);
begin
ActionMainMenuBar1.WindowMenu := '';
ActionMainMenuBarAccess(ActionMainMenuBar1).FWindowMenuItem := nil;
ActionMainMenuBarAccess(ActionMainMenuBar1).RefreshMDIMenu;
end;
See also this QualityCentral report.