Override regional settings at the application start up - delphi

I want to force my application to always use the Spanish regional settings, using the FormatSettings global variable, but the application ignores those settings. Do you know what I have missed ?.
program TestProject;
uses
Vcl.Forms,
SysUtils,
Rutinas in 'Rutinas.pas',
Conexion in 'Conexion.pas' {dmConexion: TDataModule},
MainForm in 'MainForm.pas' {frmMainForm};
{$R *.res}
begin
Application.Initialize;
FormatSettings := TFormatSettings.Create('es-ES');
Application.MainFormOnTaskbar := True;
Application.Title := Application_Name;
Application.CreateForm(TdmConexion, dmConexion);
Application.CreateForm(TfrmMainForm, frmMainForm);
Application.Run;
end.
Thank you.
PS: I know that FormatSettings is not recommended because it's not thread safe, but it shouldn't be a problem here because I only change it once at the application start up, any other time that I need a customized conversion I use a local TFormatSettings variable.

I apologize, the problem wasn't in Delphi but on the DevExpress controls that I use to present the data.
DevExpress uses their own format settings: https://www.devexpress.com/Support/Center/Question/Details/A517/how-to-use-custom-formats-for-editors
Now this works correctly :
program TestProject;
uses
Vcl.Forms,
SysUtils,
cxFormats,
Rutinas in 'Rutinas.pas',
Conexion in 'Conexion.pas' {dmConexion: TDataModule},
MainForm in 'MainForm.pas' {frmMainForm};
{$R *.res}
begin
Application.Initialize;
FormatSettings := TFormatSettings.Create('es-ES');
Application.UpdateFormatSettings := False;
cxFormatController.BeginUpdate;
cxFormatController.UseDelphiDateTimeFormats := True;
cxFormatController.EndUpdate;
cxFormatController.GetFormats;
cxFormatController.NotifyListeners;
Application.MainFormOnTaskbar := True;
Application.Title := Application_Name;
Application.CreateForm(TdmConexion, dmConexion);
Application.CreateForm(TfrmMainForm, frmMainForm);
Application.Run;
end.

Related

How to fix getting Arabic characters display in TListView?

The address book sample displays Arabic characters messed up, like that س ا ش ص. I tried to change the font of the text item to "Arial" or "Courier New", but the result is the same. Is there a way to display non-English characters correctly in TListView?
Loading contacts code:
procedure TForm1.FillContactList(Source: TAddressBookSource);
var
I: Integer;
Contacts: TAddressBookContacts;
begin
Contacts := TAddressBookContacts.Create;
try
AddressBook1.AllContacts(Source, Contacts);
ListViewContacts.BeginUpdate;
try
ListViewContacts.Items.Clear;
for I := 0 to Contacts.Count - 1 do
AddListViewItem(Contacts.Items[I]);
finally
ListViewContacts.EndUpdate;
end;
finally
Contacts.Free;
end;
end;
procedure TForm1.AddListViewItem(Contact: TAddressBookContact);
var
ListViewItem: TListViewItem;
begin
ListViewItem := ListViewContacts.Items.Add;
ListViewItem.Text := Contact.DisplayName;
ListViewItem.Tag := Contact.ID;
end;
Skia indeed solved the problem. More Details:
https://github.com/skia4delphi/skia4delphi#right-to-left
Right-to-Left
Using Skia's Canvas, your application will now support Right-To-Left text rendering. But for that you will need to make 3 changes to your project:
Open the source of your Delphi Application Project (.dpr), include the line Application.BiDiMode := TBiDiMode.bdRightToLeft;, like below:
program Project1;
uses
System.StartUpCopy,
FMX.Forms,
System.Classes,
Skia.FMX,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.BiDiMode := TBiDiMode.bdRightToLeft;
GlobalUseSkia := True;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Set the property BiDiMode of your forms to bdRightToLeft;
Keyboard input controls like TEdit and TMemo, need to be fixed by Embarcadero, meanwhile, as a workaround, set the ControlType property of these controls to Platform.

Create own Splashscreen Delphi 10 seattle

Instead of using the png images through the project options for a splashscreen I want to use my own Form for a splashscreen.
I've found a solution for XE2 in the following link, but it doesn't work for Delphi 10 Seattle: https://stackoverflow.com/a/9080804/2728408
Below I have some examples I've tried in my project .dpr:
Example 1:
program Project2;
uses
FMX.Forms,
System.SysUtils,
Unit1 in 'Unit1.pas' {MainForm},
Unit2 in 'Unit2.pas' {SplashForm};
{$R *.res}
begin
Application.Initialize;
SplashForm := TSplashForm.Create(nil);
SplashForm.Show;
Application.ProcessMessages;
Sleep(1000); // Whatever to control display time of splash screen
Application.CreateForm(TMainForm, MainForm);
SplashForm.Close;
SplashForm.Free;
Application.Run;
end.
Example 2:
program Project2;
uses
FMX.Forms,
System.SysUtils,
Unit1 in 'Unit1.pas' {MainForm},
Unit2 in 'Unit2.pas' {SplashForm};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TSplashForm, SplashForm);
Application.Run;
Sleep(1000);
Application.Terminate;// Also tried Application.Destroy
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
Example 3:
program Project2;
uses
FMX.Forms,
System.SysUtils,
Unit1 in 'Unit1.pas' {MainForm},
Unit2 in 'Unit2.pas' {SplashForm};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TSplashForm, SplashForm);
Application.Run;
Sleep(1000);
Application.CreateForm(TMainForm, MainForm);
SplashForm.Close;
Application.ProcessMessages;
Application.Run;
end.
Anyone has a solution to my problem?
you should not interfere with Application.Terminare/Inititalse the way you do it in the code.
In Firemonkey, you can change the main form of the application in runtime. So, you should show your splash form first, do all the job you want and then switch to your main form.
See this for an example: http://www.uweraabe.de/Blog/2016/01/22/a-splash-form-in-firemonkey/
procedure TFormSplash.FormCreate(Sender: TObject);
begin
StartupTimer.Enabled := false;
StartupTimer.Interval := 500; // can be changed to improve startup speed in later releases
end;
procedure TFormSplash.SplashImagePaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
begin
StartupTimer.Enabled := not FInitialized;
end;
procedure TFormSplash.StartupTimerTimer(Sender: TObject);
begin
StartupTimer.Enabled := false;
if not FInitialized then begin
FInitialized := true;
LoadMainForm;
end;
end;
procedure TFormSplash.LoadMainForm;
var
form: TForm;
begin
form := TMainForm.Create(Application);
form.Show;
Application.MainForm := form;
Close;
end;
Here is what I have been doing for the past 3 days or so.
First: Create the form of the splash screen. Like normal loading of Delphi/C++ IDE, it has an indicator that "xxxx dll is loading..". So the basic steps are to include the splash screen as part of the usual loading of the main application.
Second: Remember that your DPR file takes a vital role in loading and/or creating all the forms. Although I agree with the VCL function (Application.ProcessMessages) to show to the user that it is creating the form.
Third: Never run a procedure in your Main Form OnCreate Event except for Skinning or to instantiate the skin. But call it again in the DPR once the Main Form is created.
Fourth: Disable first your Main Form once it is created, so that the user will not click on buttons or whatever then re-enable it when the Splash Screen is hidden.
Here is the DPR:
program xxxx;
uses
Forms, MidasLib,.....
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.Title := 'xxxxx';
SplashFrm := TSplashFrm.Create(Application);
try
Application.CreateForm(TMain_Form, Main_Form);
Main_Form.Skinning;
Application.ProcessMessages;
SplashFrm.FormStyle := TFormStyle.fsStayOnTop;
Main_Form.Enabled := False;
Main_Form.WindowState := TWindowState.wsMaximized;
Application.ProcessMessages;
SplashFrm.Show; //Never use showModal coz splash form needs to be closed first and create all the rest of the forms.
SplashFrm.Label5.Caption := 'Loading... Database handlers..';
Application.CreateForm(TDM, DM);
Application.ProcessMessages;
SplashFrm.Label5.Caption := 'Loading... Login Libraries..';
Application.CreateForm(TLogin_Frm, Login_Frm);
Application.ProcessMessages;
.....// All the rest of the Forms.
Main_Form.DSiTrimWorkingSet; //[StockOverflow/questions/2031577][1]
finally
SplashFrm.Free;
Main_Form.Check_Registration;
Main_Form.Checking_Internet_Proc;
Main_Form.Enabled := True;
Main_Form.sStatusBar1.Panels[0].Text := 'Ready...';
Application.ProcessMessages;
Main_Form.DSiTrimWorkingSet;
end;
Application.Run;
end.

TChromium : How to keep session alive

When using DCEF3 TChromium, how can i keep the session alive ?
For instance, if i go to a web-site and login on it, when i close my app and open it again, i need to login again. I want to keep the session alive, just like it would be if i use Google Chrome.
I tried to add 'CefLib' on my app 'uses' clause and set 'CefCache' like the code below, but although i can see files being stored on 'cookies' folder, it seems to make no difference in keeping the session alive :
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
ceflib in 'C:\app\dcef\src\ceflib.pas';
{$R *.res}
begin
CefCache := 'cookies';
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Thanks in advance.
A guy form the official's DCEF3 forum provided the solution below, tested and approved !
CookieManager: ICefCookieManager;
FormCreate:
begin
CookiesPath := ExtractFilePath(Application.ExeName) + 'cookies';
CookieManager := TCefCookieManagerRef.Global(nil);
CookieManager.SetStoragePath(CookiesPath, True, nil);
end;
FormClose:
begin
CookieManager.FlushStore(nil);
end

COM Server application and GetObject - reusing the running application

I'm trying to automate an application (Windows 8, Delphi XE.) For my testing I'm doing the following:
Created a small test application, consisting of a form and a memo (Form1)
Added a new ActiveX Object, CoClass name TestOLE, Threading mode Apartment, Instancing Multiple (as per this article.)
Added one method Method1 which only adds some text to the memo control in Form1
I then start the application and double click on a file named test.vbs which contains the following code:
dim obj
set obj = GetObject("", "Project1.TestOLE")
obj.AddSomeText "Hola mundo"
When the application is running, I see that a new form is created, the text is added and then it exits.
What I want to accomplish is that the opened application should have its memo text changed.
I've repeated creating new projects with both MultipleInstance and SingleInstance, and in an outburst of heuristic anger, I even changed the threading model to single, to no avail.
I see two flags in the type library editor: "Replaceable" and "Aggregatable." However, selecting "Replaceable" ends up in an error in the generated RIDL file.
I've been reading a lot about GetObject. It appears that its documentation is even wrong (it says you can omit the first parameter but I've found that doesn't work).
Is this the right way to write an automation server in Delphi that can be reused?
Well, I got it working (I hope.)
Reading more of the same article cited above, found the following:
Know how to implement servers that support GetActiveObject.
Adding a global object, and registering in the Running Object Table (ROT) accomplishes the desired task of having the COM call passed to the running application:
Project file:
program TestOLEProject3;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
TestOLEProject3_TLB in 'TestOLEProject3_TLB.pas',
Unit2 in 'Unit2.pas' {TestOLE: CoClass},
Unit3 in 'Unit3.pas';
{$R *.TLB}
{$R *.res}
begin
Application.Initialize;
RegisterGlobalTestOLE;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Unit2.pas:
unit Unit2;
{$WARN SYMBOL_PLATFORM OFF}
interface
uses
ComObj, ActiveX, TestOLEProject3_TLB, StdVcl;
type
TTestOLE = class(TAutoObject, ITestOLE)
protected
procedure Method1; safecall;
procedure Quit; safecall;
end;
implementation
uses ComServ, Unit1, Unit3;
procedure TTestOLE.Method1;
begin
Form1.Memo1.Lines.Add('Wheeee');
end;
procedure TTestOLE.Quit;
begin
RevokeGlobalTestOLE;
end;
initialization
TAutoObjectFactory.Create(ComServer, TTestOLE, CLASS_TestOLE, ciMultiInstance,
tmApartment);
end.
Unit3.pas (functions to register and unregister the global object):
unit Unit3;
interface
procedure RegisterGlobalTestOLE;
procedure RevokeGlobalTestOLE;
implementation
uses TestOLEProject3_TLB, ComObj, ActiveX;
var
GlobalTestOLEHandle: longint = 0;
procedure RegisterGlobalTestOLE;
var
GlobalTestOLE: ITestOLE;
begin
GlobalTestOLE := CoTestOLE.Create;
OleCheck(RegisterActiveObject(GlobalTestOLE, CLASS_TestOLE,
ACTIVEOBJECT_STRONG, GlobalTestOLEHandle));
end;
procedure RevokeGlobalTestOLE;
begin
if (GlobalTestOLEHandle <> 0) then
begin
OleCheck(RevokeActiveObject(GlobalTestOLEHandle, nil));
GlobalTestOLEHandle := 0;
end;
end;
end.

How can I display a form for set configuration before the main form?

in my project i have two form's(form1,form2), form1 is configuration form.
i want to show Form1 and when we click Button1 then show Form2 and free(Release) Form1. how can to i do this?
i use this code. but this project start and then exit automatically.A Friend said because the application message loop never start, and application terminates because main form does not exist. how i can to solve this problem?
uses Unit2;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Application.CreateForm(TForm2, Form2);
Release;
end;
///
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Form1:= TForm1.Create(Application);
Application.Run;
end.
Do exactly what you asked in the question title: Create and show the configuration form, and then create and show the main form. The trick is in how you create them. Only use Application.CreateForm for the one form that you want to be your main form. Use the ordinary object creation technique for all other forms.
Modify your DPR file like so:
var
ConfigForm: TConfigForm;
begin
Application.Initialize;
ConfigForm := TConfigForm.Create(nil);
try
if ConfigForm.ShowModal <> mrOK then
exit;
finally
ConfigForm.Free;
end;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
You need to create Form2 first and this will be your main form. You want it to start hidden and be shown after Form1 has done its job. Something like this:
uses Unit2;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.Show;
Release;
end;
///
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm2, Form2);
Form2.Hide;
Form1 := TForm1.Create(Application);
Form1.Show;
Application.Run;
end.
The reason is that the app terminates when your main form closes. And your main form is typically the first one that you create.
You can prohibit Form1 to be shown by setting ShowMainForm to false. Leave the code in the DPR just as the IDE creates it:
uses
Forms,
Unit2 in 'Unit2.pas' {Form2},
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm2, Form2);
Application.Run;
end.
In the FormCreate event of Form2 just set ShowMainForm to false and call Show to make Form2 visible:
procedure TForm2.FormCreate(Sender: TObject);
begin
Application.ShowMainForm := False;
Show;
end;
and in the ButtonClick event of Form2 show Form1 and close Form2:
procedure TForm2.Button1Click(Sender: TObject);
begin
Form1.Show;
Close;
end;
This keeps all necessary changes inside unit2.
Edit
Some remarks that came to mind after sleeping a night over it:
Form2 should be the last one auto-created, i.e. the one directly before the Application.Run statement.
The Form1.Show statement in the ButtonClick event should be moved to the FormClose event. Thus the user can close the form with the Windows close button or whatever he likes best.
If for some reason Form1 should never be shown, some code must be added to close the application. A Halt may serve here.

Resources