How to fix naming and scoping conflict? - delphi

Error: Types of actual and formal var parameters must be identical
unit unAutoKeypress;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Memo2: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure SimulateKeyDown(Key:byte);
begin
keybd_event(Key,0,0,0);
end;
procedure SimulateKeyUp(Key:byte);
begin
keybd_event(Key,0,KEYEVENTF_KEYUP,0);
end;
procedure doKeyPress(var KeyValue:byte);
begin
SimulateKeyDown(KeyValue);
SimulateKeyUp(KeyValue);
end;
procedure TForm1.Button1Click(Sender: TObject);
const test = 'merry Christmas!';
var m: byte;
begin
Memo2.SetFocus();
m:=$13;
doKeyPress(m); // THIS IS WHERE ERROR
end;
end.
always error in function doKeyPress(m);
a simple question, why?
I know something wrong with types, but all types are similar, everywhere is byte, strange
for me and I cant run a program.

TForm is inherited from TWinControl and there is a method called DoKeyPress declared in TWinControl, which is in the current scope of the compiler inside the ButtonClick event.

The problem is that doKeyPress is a method of TForm1 (inherited from TWinControl) and so when you write doKeyPress inside a TForm1 method the compiler wants to use TForm1.doKeyPress rather than the local function. The class scope is nearer than the local function scope.
Possible solutions include:
Renaming the local function to avoid the clash.
Using a fully qualified name, unAutoKeypress.doKeyPress.
The former is a better solution in my opinion.

Related

Custom Component - Get Application ActiveControl name

Hi I have a custom component with 2 Tedit boxes in a panel. When the focus leaves one edit it should set focus on the other edit unless a certain external component(s) has focus. This is straightforward as a VCL app:
unit dem;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StrUtils, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
Edit1: TEdit;
Edit2: TEdit;
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Edit2Exit(Sender: TObject);
procedure Edit1Exit(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Edit1Exit(Sender: TObject);
begin
if AnsiContainsStr(Memo1.Text, Screen.ActiveControl.Name) = True then Exit
else Edit2.SetFocus;
end;
procedure TForm1.Edit2Exit(Sender: TObject);
begin
Edit1.SetFocus;
end;
end.
This switches the focus (on exit) between the 2 edit boxes unless Button2 is clicked.
In my component (I have substituted TStrings(TStringlist) for Memo1 and the TEdits are actually TDBEdits. I need a way to get the application's activecontrol name so I can utilitise the above code. Obviously Screen.ActiveControl.Name does not work but what will? I would be grateful for any help.
Windows 11, delphi 7
Edit
In respect of Andreas Rejbrand’s and Remy Lebeau’s concerns about using OnExit I have rethought this and decided that this component is pointless. I can use something like this to solve the tabbing part
unit dem;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StrUtils, StdCtrls, TypInfo, ExtCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
Edit1: TEdit;
Edit2: TEdit;
Memo1: TMemo;
EnterData: TButton;
Button2: TButton;
Button3: TButton;
procedure EnterDataClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure ToggleTab(ACont:TWinControl;yorn:Boolean);
var
x:Integer;
procedure HasTextProp(AControl: TControl; yorn:boolean);
begin
if IsPublishedProp(AControl, 'TabStop') = True then (AControl as TWinControl).TabStop := yorn;
end;
begin
for x:=0 to ACont.ControlCount-1 do
begin
HasTextProp(ACont.Controls[x],yorn);
end;
end;
procedure TForm1.EnterDataClick(Sender: TObject);
begin
ToggleTab(Form1,False);
Edit1.TabStop:=True;
Edit2.TabStop:= True;
Edit1.SetFocus;
end;
end.
And then using OnActiveControlChange to manage the flow. I am sorry to have wasted all of your times but I did learn NOT to use OnExit in this way so thank you for that.

How to initalize and populate TWideStringDynArray in Pascal?

I am calling a function for SOAP service and one of the required parameters is TWideStringDynArray. How do I initialize and populate this type of array? Or is there another way to convert a normal array to this type?
This is how it's defined in SOAP class
...
ArrayOfString = TWideStringDynArray;
...
PrsDataGet = class(TRemotable)
private
FsRetVal: WideString;
FsInParam: ArrayOfString;
published
property sRetVal: WideString read FsRetVal write FsRetVal;
property sInParam: ArrayOfString read FsInParam write FsInParam;
end;
If i set FsInParam as a array of WideString it says incompatible types
procedure TForm1.Button1Click(Sender: TObject);
var
QuotePrice : Real;
rezultat:WideString;
mnozica:array [0..4] of integer;
parametri: array of WideString;
obstaja:boolean;
PrsGet:PrsDataGet;
PrsFind:PrsDataGet;
begin
PrsGet.sRetVal :=rezultat;
SetLength(parametri, 4);
parametri[0]:= '1234';
parametri[1]:= 'wsprsinfotest';
parametri[2]:= 'efwefawf';
parametri[3]:= 'PRS_MN_P';
PrsGet.sInParam :=parametri;
If i change type of parametri to ArrayOfString it doesn't complain of incompatible types anymore but then it throws an Access Violation at SetLength(parametri, 4);
EDIT
To reproduce the problem:
I import WSDL definition into delphi from https://wwwt.ajpes.si/wsPrsInfo/PrsInfo.asmx?WSDL
Code for the service call:
unit UnKlicServisa;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Rio, SoapHTTPClient,Types,
UnWsPrsInfo_1, UnWsPrsInfo_2;
type
TForm1 = class(TForm)
HTTPRIO1: THTTPRIO;
Edit1: TEdit;
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
rezultat:WideString;
parametri: ArrayOfString;
obstaja:boolean;
PrsGet:PrsDataGet;
begin
PrsGet.sRetVal :=rezultat;
parametri[0]:= '1234';
parametri[1]:= 'wsprsinfotest';
parametri[2]:= '3423445';
parametri[3]:= 'PRS_MN_P';
PrsGet.sInParam :=parametri;
if Trim(Edit1.Text) <> '' then
begin
(HTTPRIO1 as PrsInfoSoap).PrsDataGet(PrsGet);
end
else
begin
MessageDlg('Enter a Valid ISBN code',mtInformation,[mbOk],0);
Edit1.SetFocus;
end;
end;
end.
Note FPC 3.2.0+ also allows array constructors
{$mode Delphi}
uses types;
var arr : TWideStringDynArray;
begin
arr:=TWideStringDynArray.Create('1234','wsprsinfotest','efwefawf','PRS_MN_P');
end.

Delphi update a parent form control from a child form

From a form, I create and show a second form. From the second form I want to update a control on the first form. But I get access violations. I can get it to work with the form in the autocreate, but not when I create the form with the create method I get violations.
Below is an example. If I run it as it is with form 11 in autocreate it works (I update a button caption in the first form). But, if in unit 10, if I comment out form11.show;, and I uncomment the create and the show and then take Form11 out of autocreate, I get an access violation.
Question - How can I update the parent form from the showed form when I create the form with a create method.
Unit10
unit Unit10;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm10 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form10: TForm10;
implementation
uses Unit11;
{$R *.dfm}
procedure TForm10.Button1Click(Sender: TObject);
var
fForm : TForm11;
Begin
// fForm := Form11.Create(Self); //This and next line give me access violation
// fForm.Show; // with form11 out of autocreate
form11.show; //This works with form11 in the autocreate.
end;
end.
Unit11
unit Unit11;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm11 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form11: TForm11;
implementation
uses unit10;
{$R *.dfm}
procedure TForm11.Button1Click(Sender: TObject);
begin
form10.button1.caption := 'Changed';
end;
end.
This is incorrect:
fForm := Form11.Create(Self)
It should be like this:
fForm := TForm11.Create(Self)
That is, TForm11, not Form11. To create an object, you have to call the constructor via the class.
I've always just had my forms auto-creating and can't think of a reason to not do so, but here's the likely cause of your problem:
The Create method needs to be called on a class, not on a variable.
This line would probably work to create a new instance of TForm11:
fForm := TForm11.Create(Self);

Error passing a generic type from a class to another

I am using Delphi 2010
I get the error: E2506 Method of parameterized type declared in interface section must not use local symbol.
Is there a way to accomplish this task?
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Rtti;
type
MyFormType<T: TForm> = class
class procedure SpecialOpen(var FormVar: T; Params: array of TValue);
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure ShowForm<T1: TForm>(var aForm: T1);
end;
var
Form1: TForm1;
implementation
uses Unit2;
{$R *.dfm}
procedure TForm1.ShowForm<T1>(var aForm: T1);
begin
if aForm = nil then
MyFormType<T1>.SpecialOpen(aForm, [Self]) // <-- Error
else
aForm.Show;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowForm<TForm2>(Form2)
end;
{ MyFormType<T> }
class procedure MyFormType<T>.SpecialOpen(var FormVar: T; Params: array of TValue);
var lRttiContext: TRttiContext;
begin
FormVar := lRttiContext.GetType(TClass(T)).GetMethod('Create').Invoke(TClass(T), Params).AsType<T>;
FormVar.Show;
end;
end.
Tanks and sorry for my english.
This is one of a great many generics bugs in Delphi 2010. Your code compiles in XE2. Your options are to look for a workaround that works in 2010, or to upgrade. Delphi XE and XE2 do include a great many fixes for generics compiler bugs and so if you are serious about making use of generics, Delphi 2010 is not a great choice.

Correct the value on datetimepicker when user selects a date

When a user selects a value in my TDateTimePicker I want to override the to-be-set value to the start of the week that goes with the selected value.
I tried setting it in the OnChange event, but then the originally selected value will be set right after I finished the event.
How would I go about this?
use the "ONCloseUp" event - this sample works for me (Delphi 7, WinXP)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, DateUtils, StdCtrls;
type
TForm1 = class(TForm)
dtp1: TDateTimePicker;
btn1: TButton;
edt1: TEdit;
procedure btn1Click(Sender: TObject);
procedure dtp1CloseUp(Sender: TObject);
private
{ Private declarations }
procedure SetDayToMonday();
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.SetDayToMonday;
begin
dtp1.DateTime := dtp1.DateTime - DayOfTheWeek(dtp1.DateTime) + 1;
end;
procedure TForm1.dtp1CloseUp(Sender: TObject);
begin
SetDayToMonday;
end;
end.
--reinhard :-)
Use the onUserInput event!
I would post a message to the form, define a message (WM_USER+1000+X), post it, and handle it. If you don't "pend" it like this, you could also do a PendingDateTimeTimer:TTimer that does validation slightly later (say 10msec) after the OnChange event sets PendingDateTimeTimer.Enabled := true.

Resources