program MouseInput;
Uses WinCrt,WinMouse, Graph;
Var
GraphicsDriver, GraphicsMode,
ErrCode : smallint;
x, y: shortstring;
Begin
x:=GetMouseX;
Y:=GetMouseY;
Writeln('Initialising Graphics, please wait...');
GraphicsDriver := Detect;
InitGraph(GraphicsDriver, GraphicsMode,'');
GetmouseX();
GetmouseY();
OuttextXY(0,0,x);
readln();
end.
It give me the error:
23 / 20 mouse.pas
Error: Incompatible types: got "WORD" expected "SHORTSTRING"
But i don't know how to change it so it works becase GetmouseX needs to be Word.
Change X,Y back to word and change the outtextxy line to
OuttextXY(0,0,inttostr(x));
Make sure "sysutils" is in your uses clause
Your GetMouseX and GetMouseY functions don't return a result and where you call them doesn't read the result, I'd have thought you'd get a stack overflow error since they call themselves (or is this a compiler error).
Having just seen paulsm's comment (I can't remember the Turbo Pascal functions) I think your code should be like this:
InitGraph(GraphicsDriver, GraphicsMode,'');
x := GetmouseX();
y := GetmouseY();
OuttextXY(0,0,x);
From Your link:
InitGraph(GraphicsDriver, GraphicsMode,'');
InitMouse;
x := GetmouseX;
y := GetmouseY;
Related
I've designed a little project reads from Comport with ComPort Library version 4.10. When i tested with com0com emulator it works perfectly but when i read data from real machine (it's an electronic test machine sending data via RS232) data comes with CR and LF,i've searched alot and tried all procedures to clear CR&LF but failed.
Here are my codes;
var veri:string;
begin
panel1.Color:=clGreen;
panel1.Caption:='VERÄ° OKUNUYOR';
veri:=Trim(Str);
memo1.lines.add(CleanupString(trim(veri)));
I've tried to remove #13,#13#10,#13+#10,#32,sLineBreak and tried below functions;
function CleanupString(S :string) :string;
var
i :integer;
begin
Result := S;
for i := 1 to Length(Result) do
if Result[i] in [#3..#13] then
Result[i] := '_';
end;
function RemoveCRLF (const aString : string) : string;
var i, j : integer;
begin
result := aString;
j := 0;
for i := 1 to Length (result) do
begin
if (not (result [i] in [#10, #13]))
then begin
inc (j);
result [j] := result [i];
end;
end;
SetLength (result, j);
end;
But no luck so far, below image shows what my memo content looks like;
Device sending data starting with "APSiS0BE" and seems like sending CR&LF with every parameter but i couldn't be able to get data in one line.
I don't think that you are seeing what you believe you are seeing.
When you add a line to TMemo, you implicitly add a CR+LF, so you are removing them, but then adding them back in. If you were not, when you open the contents in Notepad++ as you do, there would be empty blank lines, and you are not seeing them.
So, I think you are successfully removing the CR+LF, you just don't realise it.
Delphi has the Trim method which is built in and will remove leading and trailing whitespace and control characters (CRLF, etc). Your method removes them from anywhere in the string but for RS-232 protocols often Trim is all you would typically need.
That said, the TMemo.lines.Add method adds a line to the memo... with a CRLF, so if you're examining the memo output it will naturally have line ending characters in it. Without it the text would just continue on a single line.
I use ComPort too and I use StringReplace to remove CR + LF :
S:= StringReplace(C, sLineBreak, '', [rfReplaceAll]);
StringReplace
My program has following code:
function FooBar(const s: string): string;
var
sa: AnsiString;
begin
// ..........................
sa := AnsiString(s);
sa := AnsiString(StringReplace(string(sa), '*', '=', [rfReplaceAll]));
sa := AnsiString(StringReplace(string(sa), ' ', '+', [rfReplaceAll]));
result := string(sa);
// ..........................
end;
I noticed that the program did crash "somewhere" and FastMM4 said that I had written to a freed object. As soon as I have commented out "const", the program did work.
I have read the Delphi documentation about const arguments, but I can't figure out why the const argument crashes the program. I would love to understand it.
UPDATE: The program does only crash in Delphi 6 and only if optimization is ON. If the optimization is OFF, the program will work normally. Might it be a Delphi bug?
There are a few peculiar gotchas when it comes to const string parameters.
Many years ago I helped a colleague resolve a similar peculiar problem (D3 iirc). The following simplified example doesn't look like your specific issue, but it may give you some ideas:
type
TMyClass
FString: string;
procedure AppendString(const S: string);
end;
procedure TMyClass.AppendString;
begin
FString := FString + S;
end;
Now if you have an instance of TMyClass and try to call AppendString(FString); to double up the string, you may get an access violation. (There are a few other factors that can affect if you do.) The reason is as follows:
The const prevents refcounting the string on the method call.
So FString may have refCount = 1 when its value is changed.
In which case Copy-on-Write doesn't apply and the string is reallocated. (Most likely at a different address.)
So when the method returns, S is referring to an invalid address, and triggers an AV.
For this case:
sa := s;
automatic reference counting (ARC) works. This is idiomatic way, compiler know how to work with these string - if sa will change, it creates new copy and so on.
For case of hard typecasting (though type is the same)
sa := AnsiString(s);
you tell compiler that you want to get only pointer to string, and you know how to work with this string reference. Compiler will not interfere and annoy you, but you are responsible for correct operations
P.S. I can not reproduce the problem with Delphi XE5 - both simple assigning and typecasting causes LStrLAsg (internal function) call with ARC. (Of course, compiler magic could be changed a bit)
We debugged a crash today that was a Delphi 5 compiler code-gen bug:
procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
begin
s := 'Hello, world! '+IntToStr(7);
DoSomething(s);
//String s now has a reference count of zero, and has already been freed
ShowMessage(s);
end;
procedure TForm1.DoSomething(const Title: string);
var
s: AnsiString;
begin
s := AnsiString(Title);
if Now = 7 then
OutputDebugString('This is a string that is irrelevant');
end;
The Delphi 5 compiler mistakenly tries to decrement the reference counts of both
Title
s
and causes the const string's reference count to go to zero. This causes it to be freed. So when DoSomething returns, you are using a freed string.
An access violation waiting to happen.
Or, in the case of customers: happening.
That becouse AnsiString is a pointer. So, you could'n operate it as a usual strings (which mean a array of chars). Crash is random, so you can gain the crash as result of stackoverflow or access violations at any time, not depend on optimization.
Than you function FooBar return the result, sa variable are already free from mamory.
Try to use the PChar or PAnsiChar and allocate the memory for this variables as your needs.
Since it doesn't make sense to convert to AnsiString and back here, I would rewrite this as
function FooBar(const s:string):string;
begin
Result:=
StringReplace(
StringReplace(
s
,'*','=',[rfReplaceAll])
,' ','+',[rfReplaceAll]);
end;
I'm new to Delphi XE5 (part of Embarcadero's RAD Studio), and using the StrToFloat function in a VCL Forms project designed to build a simple calculator.
The code to display the text to the user works well, but I'm having trouble extracting it in a way that will allow the calculator to actually perform calculations. The means I've settled on is displaying the code to the user in a Tedit, and storing the code to be executed in a Tmemo. Pressing the buttons on the calculator stores the numbers to both, and pressing an operator (the symbols for add, subtract, exponent, multiply, and divide) starts a new line in the memo. This way, each number is on its own line, and each operator is on its own line.
I then want to extract the numbers with respect to the operators, by iterating through the lines of the memo. For 3 ^ 4, you would see...
3
^
4
...in the TMemo.
I want to find the ^ sign at line index 1 (lines start at index 0, right?), and store 3 in a base variable by the logic that, if ^ is lines[1], then 3 is lines[1-1], or lines[0], and store 4 in an exponent variable. Both variables would be of type extended. This is the code I've created to do this...
procedure TForm1.btnEqualsClick(Sender: TObject);
var
i: Integer;
base: extended;
exponent: extended;
result: extended;
begin
{This For loop looks for the exponentiation operator (^) in memCurrentEntry. If
it's found, it then solves the equation.}
for i := Low(memCurrentEntry.Lines.Text.Length) to High(memCurrentEntry.Lines.Text.Length) do
if AnsiContainsStr(memCurrentEntry.Lines.Text, '^') then
begin
base := StrToFloat(memCurrentEntry.Lines[ansipos('^', memCurrentEntry.Lines.Text)-1]);
exponent := StrToFloat(memCurrentEntry.Lines[ansiPos('^', memCurrentEntry.Lines.Text)+2]);
result := power(base, exponent);
end;
When I run the calculator, the numbers appear correctly, but when I hit the equals button to run the code above, I get the message Project Calculator_u.exe raised exception class EConvertError with Message ''' is not a valid floating point value'.
I know the StrToFloat function is trying to convert a null character or something (How do I identify what code is generating " '' is not a valid floating point value" error dialogue box), but what should I do to correct this?
Below is the code for each button -- the digit (0, 1, 2, 3, etc.) changes, but the rest is the same for each one...
procedure TForm1.btn0Click(Sender: TObject);
begin
//Adds the digit 0 to the end of the current number in memCurrentEntry
memCurrentEntry.SelStart := Length(memCurrentEntry.Text);
memCurrentEntry.Lines.Text := Copy(memCurrentEntry.Lines.Text,1,
memCurrentEntry.SelStart)+'0'+ Copy(memCurrentEntry.Lines.Text,
memCurrentEntry.SelStart+1,Length(memCurrentEntry.Lines.Text)
- memCurrentEntry.SelStart);
//Adds the digit 0 to the end of the current number in edtCurrentEntry
edtcurrententry.Text := edtcurrententry.Text + '0';
end;
I can post the full unit file upon request.
Use TryStrToFloat. This returns a boolean indicating whether or not the conversion succeeded.
var
str: string;
val: Double;
....
if TryStrToFloat(str, val) then
// val contains the floating point value represented by str
else
// str does not contain a floating point value, do something else with it
Of course, you could use StrToFloat, and catch the exception. But since you expect to encounter the exception, it will result in much cleaner code if you use TryStrToFloat.
the usage of lines on the memo is wrong:
base := StrToFloat(memCurrentEntry.Lines[ansipos('^', memCurrentEntry.Lines.Text)-1]);
the lines.text returns the ENTIRE text, which is not what you want. Instead use some LOCAL variables to hold your lookup values...that way you can set a breakpoint and see whats wrong and use the following method to locate the "^"
result := 0;
carrotLine := memCurrentEntry.Lines.IndexOf('^');
if carrotline > 0 then // must be 1 or greater, so a number can be at the 0 position
begin
base := TryStrToFloat(MemCurrentEntry.Lines[carrotLine-1],0);
exponent := 0;
// only try to read the next value if there is one.
if memCurrentEntry.Lines.Count >= carrotLine then
exponent := TryStrToFloat(MemCurrentEntry.Lines[carrotline+1],0);
result := power(base,exponent);
end;
Note that this code ONLY handles a single ^ in the memo (your code had the same issue), to go beyond this is to use a loop and possibly a state engine or some other parsing logic to handle computations.
Use StrToFloat is not wrong. If the conversion is failed, user should see an error message. If you want to suppress the error quietly, then you should add a try/except to protect your code.
try
Value := StrToFloat(A_String);
except
on EConvertError do
Value := 0; // Fallback to a default value or execute other code logic
end;
According to your given code example, if the base and the exponent are entered in your given format (first line is the base, second line is a "^" and the third line is the exponent). I'd suggest you write your code as follows:
var
Numbers: TArray<string>;
// Other variables go here
begin
// ...
Numbers := memCurrentEntry.Lines.Text.Split('^');
if Length(Numbers) = 2 then
try
Base := StrToFloat(Numbers[0]);
Exponent := StrToFloat(Numbers[1]);
Result := Power(Base, Exponent);
except
on EConvertError do
begin
ShowMessage(Format('Unable to calculate the formula %s', [memCurrentEntry.Lines.Text]));
Result := 0; // Fallback to a default value, such as 0
end;
end;
// ...
end;
Please help, how can i convert a real declared variable into a string one. Is there any function like IntToStr() ? RealToStr() function won't work.
There is a bunch of conversion routines in SysUtils unit, ie FloatToStr and other FloatTo* functions. Also see the Format function.
A really old method uses the 'Str' procedure, which has two parameters: the first is a real or integer, and the second is a string variable, into which the formatted number will be placed.
Examples:
i:= 1;
str (i, a); // a = '1'
r:= 1.5;
str (r:2, a); // a = '1.50'
It depends on the Delphi version you are using.
There is a FloatToStr in newer versions.
I think something like this would work...
procedure TestConversion;
Var
StringValue : String;
RealValue : Real;
begin
RealValue := 1 + 1.95;
Str(RealValue:0:2,StringValue);
// to display it in a label for example, it should be like this:
Label1.Caption := StringValue + ' is a Real Value!';
end;
so the output should be displayed in the Label1.Caption(as example) without problems like this:
2.95 is a Real value!
I have GetVersion function in [Code] that returns a string like this "1004", "1003", etc.
I created this function to check the registry value for lowest version numbers and uninstall them.
Here is a snippet of the code it is giving error point to StrtoInt conversion line stating
Comma (,) expected
Here is the snippet:
function DoesOldVersionsExist(): Boolean;
var
AppVersion: integer;
mstr: string;
VersionInstalled: cardinal;
begin
AppVersion := StrToInt(GetVersion({#MyAppVersion}), 0);
...
after that line I'm simple comparing the values and return true or false. Much Appreciated.
This is what error message says:
Line 55
Column 40.
Comma (,) expected
Thanks Deanna but unfortunately that is the error message pointing to this :
AppVersion := StrToInt(GetVersion({#MyAppVersion}), 0);
^
Here is the GetVersion function:
function GetVersion(AppVersion: String): String;
var
Version: String;
CharIndex: integer;
c: char;
begin
for CharIndex := 1 to Length(AppVersion) do begin
c := AppVersion[CharIndex];
if (c <> '.') then
Version := Version + c;
end;
Result := Version;
end;
I think that you can't just have Inno Setup constants in code like this, you have to use ExpandConstant():
AppVersion := StrToInt(GetVersion(ExpandConstant('{#MyAppVersion}')), 0);
You have not given us enough information to give a definite answer, but I think that the situation is as follows.
You have defined some constant called MyAppVersion which you let the ISPP (the Inno Setup pre-processor) substitute. Now, you have not told us what type this variable is, and you have not told us what the signature of GetVersion is (in particular, what type of argument does it expect?). However, if these types are strings, you need to write
StrToInt(GetVersion('{#MyAppVersion}'), 0);
in order to obtain, say,
StrToInt(GetVersion('Some string, this is!'), 0);
instead of
StrToInt(GetVersion(Some string, this is!), 0);
which is malformed (indeed, to such an extent that it hurts my eyes to look at it).