Delphi can't get text from TEdit - delphi

I've encountered a problem while writing code in Delphi.
Namely I can't get acces to Components, even though they're declared and I used them in code above ( previously in procedures, now I am trying to use them in functions - maybe this is the reason, I don't know, I am not good at Delphi ).
I made a few screens to make it look clearer.
Take a look.
http://imageshack.us/photo/my-images/135/weirddelphi3.png/">
As you can see on the first screen I'm getting compiler error. It says that the component doesn't exist, but on the third screen you can see that this component exists. On the second screen I can even use this component ( Code Completion can be invoked successfully, but if I try to invoke it in secondFunction's scope I get error like this :
"Unable to invoke Code Completion due to errors in source code " - but what the hell is the error?! ). If I comment these two lines, which refer to Edit7 and Edit8, I can run the program without problems. I really can't figure out what is wrong, if any of you could give me some advice, it would be greatly appreciated. I didn't wanted to post whole code here, because it would take about 300 lines, however if u need to know something else to sort this out then ask I will tell you..
I don't have enough reputation points to post more than 2 hyperlinks so you have to do "copy & paste " with the last one :D

The problem is that Edit7 is a part of the TForm1 class. Edit7 is not accessible by name outside of TForm1. So either you can use the global Form1 variable, and do
function secondFunction(x: extended): extended;
var
paramA, paramB: extended;
begin
paramA := StrToFloat(Form1.Edit7.Text);
paramB := StrToFloat(Form1.Edit8.Text);
Result := paramA + paramB * sin(x);
end;
or you can make the secondFunction part of the TForm1 class:
function TForm1.secondFunction(x: extended): extended;
var
paramA, paramB: extended;
begin
paramA := StrToFloat(Edit7.Text);
paramB := StrToFloat(Edit8.Text);
Result := paramA + paramB * sin(x);
end;
But then you need to declare secondFunction in the declaration of the TForm1 class, like
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
function secondFunction(x: extended): extended;
end;
in the beginning of the unit.

Related

Delphi closure and "old style" object type

Working with anonymous functions I found out that sometimes the compiler throws the following error:
E2555 Cannot capture symbol 'Self' when I try to use some field of the object.
I also noticed that this error seems to be related to the fact that a type, the method belongs to, is declared with "object" key word:
MyType = object()
field: integer;
...
end;
MyType.Method1()
begin
p := procedure
begin
// do something with field
end;
end;
However when a type is declared with "class" keyword it seems it works fine.
I know that to prevent the compiler error I can make a local copy of needed fields and use them inside the anonymous functions, but just to be sure - is "object" type cause of the compiler error and what's the reason of that?
Thanks in advance
As David properly analyzed it is because Self in your case is a value and not a reference. It cannot be moved to the internally created class - same is the case with any method arguments that are records. They also cannot be captured for the very same reason.
For arguments I usually copy them to a local variable which is being captured.
The same can be done for capturing Self in a record or object.
However if you capture it as value you get a copy and calling the closure later might have the "wrong" state because it captured a copy. To make it work similar you would have to capture a reference to Self but then for a value type you cannot guarantee that this reference is still valid when you call the closure.
You can see this in the following code:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TProc = reference to procedure;
PRecord = ^TRecord;
TRecord = object
y: Integer;
procedure Foo;
function GetProc: TProc;
end;
procedure TRecord.Foo;
begin
Writeln(y);
end;
function TRecord.GetProc: TProc;
var
this: PRecord;
begin
this := #Self;
Result :=
procedure
begin
this.Foo;
end;
end;
procedure Nested(var p: TProc);
var
r: TRecord;
begin
p := r.GetProc();
r.y := 0;
p();
r.y := 32;
p();
end;
procedure Main;
var
p: TProc;
begin
Nested(p);
p(); // <- wrong value because PRecord not valid anymore
end;
begin
Main;
end.
If you would capture TRecord it would do a local copy that it captures - you can see that it then will print 0 all the time.
Since Turbo Pascal object is long deprecated, it is reasonable for new language features not to have support for object.
There's not really any need to look much further. Since you are maintaining legacy code, I would not expect you to be introducing new language features like anonymous methods. Once you start introducing such language features, this no longer feels like legacy code maintenance and it would be reasonable to re-factor the code away from the legacy language features like object.
Having said that, I do note that the same restriction to capture applies in methods of advanced records.
type
TProc = reference to procedure;
TRecord = record
procedure Foo;
end;
procedure TRecord.Foo;
var
P: TProc;
begin
P :=
procedure
begin
Foo;
end;
end;
This fails to compile with error:
E2555 Cannot capture symbol 'Self'
Why does this code fail, even though advanced records are a fully supported modern feature?
I don't have an explanation for that and the documentation does not make it clear. A plausible explanation is that records are value types. When a local variable is captured, it is hoisted from being a stack allocated variable to a variable owned by an internally created class. That's possible for Self when Self is a reference to an instance of a class. But when Self is a value like a record, it is too late to hoist the record.
Or perhaps it is much more prosaic. Maybe the designers just implemented the most important use case (capturing Self for a class) and omitted the less widely used cases for expediency. It is frustrating that the documentation does not appear to give any rules for what can and cannot be captured.

Delphi: Types of Actual and Formal Parameters Must Be Identical

There are a lot of questions already with this title; however, none address my issue. I am actually trying to pass by reference, yet am receiving the E2033: Types of actual and formal var parameters must be indentical error when trying to compile my code. I am trying to pass three (3) variables, each is an Integer, two by reference (Var) and the other not.
I do not understand the issue with my code, below. I have included the declaration, the definition, and the call.
Declaration of Routine:
private
updateDeviceStatus(Var aReturnCount, aNotFoundCount: Integer; aNumOfDevices: Integer);
I have tried to not condense the declaration of the arguments and declared Var for the first two, explicitly' however, this did not work.
Question 1: is the error because I am mixing by reference and by value (if I remember, correctly, some languages do not permit this)?
Definition of Routine:
procedure TfrmReturnMeterToMfg.UpdateDeviceStatus(Var aReturnCount, aNotFoundCount: Integer; aNumOfDevices : Integer);
begin
// DO SOMETHING
end;
Really, the code in the body of the routine is trivial with regard to the problem and does not affect the problem (at least it shouldn't be the cause in this case).
The Call to Routine:
The following is contained within another routine's body:
// local variables:
var ReturnCount, NotFoundCount, NumOfDevices: Integer;
begin
// SOMETHING HAPPENS TO EACH OF THESE VALUES (THEY ARE INCREMENTED)
UpdateDeviceStatus([ReturnCount], [NotFoundCount], NumOfDevices);
end;
Then I receive the error.
Question 2: is this a result of my syntax when calling the routine (attempting to pass the arguments)?
EDIT
So, you may be wondering (you being a more experienced Delphi programmer), "Where did this lark pick up the [ and ] bit? Here's the resource I was consulting (and see why I looked at the wrong thing in the comments, below): consulted resource.
I guess the brackets are the problem.
This code works for me:
program Project12;
{$APPTYPE CONSOLE}
type
TfrmReturnMeterToMfg = class
private
procedure UpdateDeviceStatus(Var aReturnCount, aNotFoundCount: Integer; aNumOfDevices : Integer);
end;
procedure TfrmReturnMeterToMfg.UpdateDeviceStatus(Var aReturnCount, aNotFoundCount: Integer; aNumOfDevices : Integer);
begin
// DO SOMETHING
end;
var thing : TfrmReturnMeterToMfg;
ReturnCount, NotFoundCount, NumOfDevices: Integer;
begin
ReturnCount := 4;
NotFoundCount := 2;
NumOfDevices := 42;
thing := TfrmReturnMeterToMfg.Create;
thing.UpdateDeviceStatus( ReturnCount, NotFoundCount, NumOfDevices);
thing.Free;
end.
Adding brackets around the argument changes the meaning of the code completely, they mean something. In this particular case, by adding brackets you instruct the compiler to pass
UpdateDeviceStatus(
[ ReturnCount ], // array or set of integer (with one element)
[ NotFoundCount ], // same again here
NumOfDevices // integer
);
This is something completely different.

How to use this Hyphenation library in delphi?

This is a hyphenation lib by Synopse delphi open source.
The demo is a console application. I do not know how to use it in GUI application.
Below is my test, but not work. It does not display word with hyphen (or separaror). The lib can be downloaded here:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, hyphen, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure testhyphenator;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.testhyphenator;
var
h: THyphen;
s: string;
F, L: Integer;
begin
s := 'hyph_en_US.txt'; //this is from the folder, is that correct to call?
if FileExists(s) then
begin
F := FileOpen(s, fmOpenRead);
L := FileSeek(F, 0, soFromEnd);
if L > 0 then
begin
SetLength(s, L);
FileSeek(F, 0, soFromBeginning);
FileRead(F, s[1], L);
end;
FileClose(F);
end;
h := THyphen.Create(s);
h.Execute('pronunciation'); //is this correct?
ShowMessage(h.filllist); //not display hyphenated word
end;
It does not display hyphenated word. In the demo, I am also confused about the constructor:
H := THyphen.create('ISO8859-1'#10'f1f'#10'if3fa/ff=f,2,2'#10'tenerif5fa');
writeln('"',H.Execute('SchiffahrT'),'"'); writeln(H.FillList);
...
The author has also enclosed the obj file. If I want to compile it into a single exe, how to do it?
Can you please help me understand how to use it correctly?
Thanks a lot.
Disclaimer: I have harnessed a not so recent distribution of Hyphen, it may not be in sync with the latest version.
Here are my points:
Compilation of the distribution
I have compiled it under Delphi 7 and it's OK.
hyphen.rc File
There is no hyph_en_EN.dic file in the distribution. If you are going to rebuild hyphen.res, you may need to fix hyphen.rc using the following:
hyphen Text HYPH_EN_US.dic
I have not checked the hyphen.res file in the distribution wether it contains hyph_en_EN.dic and/or hyph_en_US.dic.
*.dic Files available in my distribution
hyph_it_IT.dic
hyph_es_ES.dic
hyph_fr_FR.dic
hyp_en_US.dic
hyp_de_DE.dic
Answers to the comments in your snippet
s := 'hyph_en_US.txt'; //this is from the folder, is that correct to call?
No! The correct file extension is .dic. You should write instead:
s := 'hyph_en_US.dic;
The following is Ok (you can refer to the definition of THyphen class):
Execute('pronunciation'); // is this correct?
The following is Ok (but it doesn't work because h as a THyphen instance was not properly initialized):
ShowMessage(h.filllist); //not display hyphenated word
Your concern about the constructor
H := THyphen.create('ISO8859-1'#10'f1f'#10'if3fa/ff=f,2,2'#10'tenerif5fa');
It's just one of the proper way to set up THyphen (refer again to the definition of THyphen class among others).
E.g.:
H := THyphen.create('EN');
Harnessing hyphen in a GUI App using Delphi 2007
I can tell that it's OK so long as THyphen instance is properly constructed (Dont forget to include the hyphen.res resource file with {$R hyphen.res}, the hyphen.obj file is already linked in the hyphen.pas unit).
Last but not the least
Feel free to get in touch with Arnaud Bouchez the great man behind Synopse. He is a Stackoverflow member and always ready to help for sure, a top delphi user moreover.
I don't have my Delphi install handy, so understand you may need to tweak this a bit.
After looking at the hyphen code, I believe you are using it incorrectly. The parameter on the constructor is the language or character set.
h := THyphen.Create('UTF-8');
or (based on your file name, I think you need this next one)
h := THyphen.Create('EN');
Then "Execute" is used to generate a hyphenated version of the string passed in. "Execute" is a function that returns a new string. You are calling it, but not doing anything with the result.
NewStr := h.Execute('correct');
"NewStr" should now equal "cor-rect".
If I read the code correctly, the "FillList" function and procedure return a list of all of the possible hyphenation possibilities for the last word that was Execute'd.

Delphi: How to set field value of a generic using RTTI?

I'd like to fill the field of a generic object at runtime using D2010.
program generic_rtti_1;
{$APPTYPE CONSOLE}
uses
SysUtils, rtti;
type
TMyObject = class
FField1: string;
end;
TGeneric<TElement: class> = class
procedure FillFields(Element: TElement);
end;
procedure TGeneric<TElement>.FillFields(Element: TElement);
var
ctx: TRttiContext;
begin
ctx := TRttiContext.Create();
ctx.GetType(TypeInfo(TElement)).GetField('FField1').
SetValue(#Element, TValue.FromVariant('Some string'));
ctx.Free();
end;
When the line ctx.Free(); is executed, I get an AV at line 21986 in System.pas (function _IntfClear()). This is called from FContextToken := nil in rtti.pas. (In fact, the SetValue-induced AV pops up if I step into SetValue, however if step over it, only the ctx.Free-induced is reported. See below.)
If I remove ctx.Free();, the AV appears when calling SetValue(#Element, TValue.FromVariant('Some string'));. This too at line 21986 in System.pas.
Trying to figure this mess out, I replaced
ctx.GetType(TypeInfo(TElement)).GetField('FField1').
SetValue(#Element, TValue.FromVariant('Field 1 is set'));
with this:
rType := ctx.GetType(TypeInfo(TElement));
rField := rType.GetField('FField1');
Val := TValue.FromVariant('Field 1 is set');
rField.SetValue(#Element, Val);
This time, I got no error, however WriteLn(MyObject.FField1) printed an empty string. (The AV re-appears if I combine SetValue and TValue.FromVariant, i.e. write rField.SetValue(#Element, TValue.FromVariant('Field 1 is set'));.
In order to pinpoint the guilty line, I commented out line by line, replacing the commented code with a compound statement. By accident I forgot to comment out the Val := TValue.FromVariant('Field 1 is set');-line above, which causes the AV to disappear once more (still calling rField.SetValue(#Element, TValue.FromVariant('Field 1 is set'));). (Note that I don't actually use Val in the troublesome call, still the AV disappears.)
I'm kind'a lost at this point.
For sake of completeness, here's how I'd like to use the above code:
var
Generic: TGeneric<TMyObject>;
MyObject: TMyObject;
begin
MyObject := TMyObject.Create();
Generic := TGeneric<TMyObject>.Create();
Generic.FillFields();
WriteLn(MyObject.FField1);
Generic.Free();
MyObject.Free();
ReadLn;
end;
end.
Do anyone know what I'm doing wrong? (Is this even possible? Are there better ways to do this using generics? )
Well, I don't know if this makes sense to you guys, but here's how I solved it. Hard cast to TObject in procedure TGeneric<TElement>.FillFields works like a charm. Like so:
ctx.GetType(TypeInfo(TElement)).GetField('FField1').
SetValue(TObject(Element), TValue.FromVariant('Field 1 is set'));
Hope this is useful to someone else out there.

Why does the compiler say "Too many actual parameters" when I think I've provided the correct number?

I've declared the following function:
function next(current, next: string): Integer;
begin
form1.Label1.Caption := next;
form1.Label2.Caption := current;
form1.label3.Caption := clipboard.AsText+inttostr(c);
Result:=1;
end;
I try to execute it with this code:
if label1.Caption = '' then res := next('current', 'next');
I am getting the following error:
[Error] Unit1.pas(47): E2034 Too many
actual parameters
I think all parameters are good, so why am I getting that error?
I just tried your code on both Delphi 7 and Delphi 2010. If it works on those two, it should also work on Delphi 2005.
Conclusion: Delphi wants to use a different version of the "next" routine, because of code scope/visibility. Try ctrl+click-ing on "next" in "res := next();" and see where Delphi takes you. Alternatively post more code so we can tell you why Delphi is not choosing your version of the "next" routine. Ideally you should post a whole unit, starting from "unit name" to the final "end."
As specified by Cosmin Prund, the problem is because of the visibility.
TForm has a procedure with name Next which wont accept any parameters.
Your function uses the same name and as you are calling the function in TForm1 class implementation, compiler is treating the call as TForm1.Next and hence it was giving error.
To solve the problem, precede the unit name before the function name i.e., Unit1.Next().
So this should be your code
if label1.Caption = '' then res := Unit1.next('current', 'next');

Resources