Delphi: Undeclared Identifier in Procedure - function

I want to edit a property of a shape inside a procedure.
However if I create my own procedure I get an "undefinded identifier" error.
I tried to edit the property in the OnCreate event procedure of my form and that works just fine.
Why is it like that and how can I fix it?
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls;
type
Tfrm_main = class(TForm)
shp_wheelLeftInside: TShape;
shp_wheelRightInside: TShape;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frm_main: Tfrm_main;
implementation
{$R *.dfm}
procedure addWheelInsides();
begin
shp_wheelRightInside.Height := 42; //this is where the error occurs
end;
procedure Tfrm_main.FormCreate(Sender: TObject);
begin
shp_wheelLeftInside.Height := 42;
shp_wheelRightInside.Height := 42;
addWheelInsides();
end;
end.

The problem is that shp_wheelRightInside is a field that belongs to your Tfrm_main class whereas the addWheelInsides() method you have declared as a naked, ordinary method that belongs to nothing. The method, therefore, does not have access to the fields which belong to the form.
One solution is to move the method, which intends to operate on objects owned by the form, into the form itself.
Tfrm_main = class(TForm)
shp_wheelLeftInside: TShape;
shp_wheelRightInside: TShape;
procedure FormCreate(Sender: TObject);
private
procedure addWheelInsides(); {declare it here}
public
{ Public declarations }
end;
Which you then implement as a method of the form class as :
procedure Tfrm_main.addWheelInsides();
begin
shp_wheelRightInside.Height := 42;
end;

The shp_wheelRightInside field is not visible in your procedure.
Declare the procedure addWheelInsides() inside the form as a method instead to resolve the shp_wheelRightInside scope.
type
Tfrm_main = class(TForm)
shp_wheelLeftInside: TShape;
shp_wheelRightInside: TShape;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
procedure addWheelInsides;
public
{ Public declarations }
end;
If you want to extend the procedure across several units, pass TShape as a parameter instead.

Related

how do I use setstate (lnet)?

When I use setstate I always get this error: unit1.pas(34,49) Error: Only class methods, class properties and class variables can be referred with class references, why does this error occur? I think the error lays in ssNoDelay, as without it the before mentioned error doesn't happen.
I made this empty project as an example:
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, lNetComponents, lNet;
type
{ TForm1 }
TForm1 = class(TForm)
LTCPComponent1: TLTCPComponent;
procedure FormCreate(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
LTCPComponent1.SocketClass.SetState(ssNoDelay);
end;
end.
SetState has to be used on a TLSocket, not on the TLCTPComponent. This means you can only use SetState when you already have a connection you want to apply one of the options (ssNoDelay for example) on (so the best solution is to use setstate in the OnAccept / OnConnect procedure if you want to use an option from the start).

EConvert exception invalid date time when trying to convert json to object using REST.Json

The following code end up in an exception
'2019.10.5 14:16:14,1000' is not a valid date and time
when trying to parse the json to an object. The problem seems to be the decimal in the date.
JSonStr := '{"orderNumber": "395409772020_1", "modified": "2019-10-05T14:16:14.9995946Z"}';
Order := TJson.JsonToObject<TOrder>(JSonStr);
If I use a date with millisecond precision that rounds downwards i.e "modified": "2019-10-05T14:16:14.4995946Z" it works fine.
I've tried adding options to set the format for the date. Order := TJson.JsonToObject<TOrder>(JSonStr, [joDateFormatParse]);. This prevents the code from crashing, but the DateTime is not recognized and the value ends up with "0".
Anyway around this, or is it simply a bug in the library?
I'm running Delphi 10.2 Update 3
I built a simple demo program with your code and it works perfectly with Delphi 10.4.1.
Here is the source code for the demo:
unit JsonParseDateDemoMain;
interface
uses
Winapi.Windows, Winapi.Messages,
System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
REST.Json;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
end;
type
TOrder = class
private
FOrderNumber : String;
FModified : TDateTime;
published
property OrderNumber : String read FOrderNumber write FOrderNumber;
property Modified : TDateTime read FModified write FModified;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
JsonStr : String;
Order : TOrder;
begin
JsonStr := '{"orderNumber": "395409772020_1", ' +
'"modified": "2019-10-05T14:16:14.9995946Z"}';
Order := TJson.JsonToObject<TOrder>(JsonStr);
Memo1.Lines.Add(Order.OrderNumber);
Memo1.Lines.Add(DateTimeToStr(Order.Modified));
Order.Free;
end;
end.
It is a bug in Delphi version you use.

Generics and JSON serialisation in Delphi XE5 reflection

I'm trying to serialise/deserialise the TMySerializableClass declared in the below unit:
unit Unit6;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Generics.Collections, System.SyncObjs, DBXJSon,
DBXJSonReflect;
type
TForm6 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
public
{ Public declarations }
end;
TMySerializableClass<T> = class
MyStringField: string;
MyIntegerField: Integer;
MyBooleanField: Boolean;
end;
var
Form6: TForm6;
implementation
{$R *.dfm}
procedure TForm6.Button1Click(Sender: TObject);
var
Mar: TJSONMarshal; //Serializer
UnMar: TJSONUnMarshal; //UnSerializer
SerializedObject: TJSONObject;
aMySerializableClass1: TMySerializableClass<Integer>;
aMySerializableClass2: TMySerializableClass<Integer>;
aString: string;
begin
try
aMySerializableClass1:= TMySerializableClass<Integer>.Create;
aMySerializableClass2:= TMySerializableClass<Integer>.Create;
Mar:= TJSONMarshal.Create(TJSONConverter.Create);
try
SerializedObject := Mar.Marshal(aMySerializableClass1) as TJSONObject;
finally
Mar.Free;
end;
Memo1.Text:= SerializedObject.ToString;
// UnMarshalling Kid
UnMar := TJSONUnMarshal.Create;
try
aMySerializableClass2 := UnMar.UnMarshal(SerializedObject) as TMySerializableClass<Integer>;
finally
UnMar.Free;
end;
finally
aMySerializableClass1.Free;
aMySerializableClass2.Free;
end;
end;
end.
When I serialise it everything works fine, while when deserialise to a new instantiated variable of the same kind I got the following error:
First chance exception at $74E5C41F. Exception class EConversionError with message 'Internal: Cannot instantiate type Unit6.TMySerializableClass<System.Integer>'. Process Project7.exe (2252)
Edit: this has something to do with the TMySerializableClass<T>, which
is a generic. If I declare it as TMySerializableClass the
deserialisation works fine.
Ideas?
Cannot test on XE5 but on Berlin 10.1 it worked for me after I added alias for instance of generic type as
TMySerializableClassInteger = TMySerializableClass<Integer>;
looks like Delphi does not generate RTTI information if you don't do it.
UPDATE. Seems Delphi does not need alias but just have some declaration of specialized class in interface part of the unit. So if you declare variable or form field as TMySerializableClass<Integer> it will also work.

idhttp.get component doesnt download full HTML File

I am currently working on a program that should download the HTML file of an Wikipedia Page and then convert it from HTML to PDF.
My program so far downloads the HTML file, but without any pictures and the page looks incomplete.
Is there any way I can bring the idhttp.get component from the INDY Package to download the full HTML file?
unit Unit3;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
IdHTTP;
type
TForm3 = class(TForm)
Label1: TLabel;
Button1: TButton;
Button2: TButton;
IdHTTP1: TIdHTTP;
SpeicherEd: TEdit;
SaveDialog1: TSaveDialog;
AuswahlB: TButton;
NameEd: TEdit;
procedure Button1Click(Sender: TObject);
procedure NameEdEnter(Sender: TObject);
procedure AuswahlBClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Speicherort, Form3: TForm3;
implementation
uses
unit2, unit1, Filectrl;
{$R *.dfm}
procedure TForm3.Button1Click(Sender: TObject);
var ResponseStream: TFileStream;
begin
ResponseStream := TFileStream.Create(SpeicherEd.Text, fmCreate);
try
idHTTP1.Get(url, ResponseStream);
finally
ResponseStream.Free;
end;
ShowMessage('Download abgeschlossen');
end;
procedure TForm3.AuswahlBClick(Sender: TObject);
var dir : String;
begin
dir := ExtractFilePath(Application.ExeName);
if SelectDirectory ('Bitte ein Verzeichnis auswählen','',Dir)
then
SpeicherEd.Text := (dir+'\'+NameEd.text+'.html');
end;
procedure TForm3.NameEdEnter(Sender: TObject);
begin
NameEd.Text := '';
end;
end.

JSON to StringList using Delphi Xe5

I am using Delphi Xe5 and I have a component that essentially uses IDTCPCLient (sockets) to talk with are server and retrieve data in the form of JSON. I have spared you all the connection code , etc. It works. The returned JSon works as well. The trouble I am having is converting my JSON into a StringList, which I then use to write out a list of values to a listbox and store the rest of the JSON data objects in the TSTrings OBjects property.
I have a number of funny things happen.
1.) I can't for the life of me get the List property to work properly. I use this list to store my JSON. A string value and then the entire object for each item in the list. You will notice that in the JSONToStringList method, I clear the stringlist (it is commented out, becuase when it isn't, my program hangs)
2.) I get dupplicate values in my list after calling the method more than once for multiple JSON sets needed
TConnector = class(TComponent)
private
{ Private declarations }
FList: TStrings;
procedure SetList(const Value: TStrings);
protected
{ Protected declarations }
public
{ Public declarations }
Constructor Create( AOwner : TComponent ); override;
Destructor Destroy; Override;
Procedure GenerateJSON;
Procedure JSONToStringList(aJSonKey: String);
published
{ Published declarations }
property List: TStrings Read FList Write SetList;
end;
Constructor TConnector.Create(AOwner: TComponent);
begin
inherited;
FList:= TStringList.Create(True);
end;
destructor TConnector.Destroy;
begin
if FList <> nil then
FreeAndNil(FList);
inherited;
end;
Procedure TConnector.GenerateJSON;
begin
if ResponseStream<>nil then
Begin
FreeAndNil(ResponseJSON_V);
ResponseJSON_V := TJSONObject.ParseJSONValue(StreamToArray(ResponseStream),0) as TJSONValue;
End;
end;
procedure TConnector.JSONToStringList(aJSonKey: String);
Var
zLJsonValue : TJSONValue;
zLJSONArray: TJSONArray;
zLJsonObject : TJSONObject;
zI : Integer;
begin
if ResponseJSON_V is TJSONArray then
begin
zLJSONArray:= ResponseJSON_V as TJSONArray;
zLJsonObject := zLJSONArray.Get(0) as TJSONObject;
end
else
if ResponseJSON_V is TJSONObject then
begin
zLJSONArray:= nil;
zLJsonObject := ResponseJSON_V as TJSONObject;
end
else
Exit;
if zLJSONArray<>nil then
begin
***//FList.Clear;***
for zLJsonValue in zLJSONArray do
begin
zLJsonObject := zLJsonValue as TJSONObject;
for zI := 0 to zLJsonObject.Size-1 do
begin
if zLJsonObject.Get(zI).JsonString.Value = aJSonKey then
begin
FList.AddObject(zLJsonObject.Get(zI).JSONValue.Value, zLJsonObject);
end;
end;
end;
end
else
begin
FList.Clear;
for zI := 0 to zLJsonObject.Size-1 do
begin
if zLJsonObject.Get(zI).JsonString.Value = aJSonKey then
FList.AddObject(zLJsonObject.Get(zI).JSONValue.Value, TJSONPair(zLJsonObject.Get(zI)));
end;
end;
end;
I hope this is all understandable. Please let me know if you need to see more. Please feel free to correct anything else you see bad in my code. I am always learning :) - thank you for your help
If FList.Clear hangs then it's most likely memory corruption issue. First two thing I would suspect is that you have not called a constructor or that part of the memory has been overwritten by something else.
Can the duplicate values in the list be cause by the fact that you commented out FList.Clear. Anyway, I suggest using a debugger to see what goes in to the list or log everything added to/removed from the list. This should give you the idea where unneeded values in the list are coming from.
As a general advice you don't need to check if object is not nil before freeing it. The check is made in Free (or in the Free part of the FreeAndNil) anyway.
It turns out , that the FList property should not have been published, but rather made public instead. Which makes since, cause the list is only filled and emptied at runtime, never at design time.
TLiveConnector = class(TComponent)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
List: TStrings;
published
end;
Not sure exactly why that is the case, but it seem to work just fine now
Calling List.Clear instead of FList.Clear;
your code cannot work ... U define a param called "aJSonKey" and u call it "ResponseJSON_V " into the procedure.
Moreover u call this "ResponseJSON_V" into GenerateJSON proc when there is no property called that way.