Delphi Edit Text Integer: Minus Sign Error - delphi

Hi I am very beginner for Delphi.
But what confuses me is that I have Edit1.Text
and variable "i" which uses StrToInt(Edit1.Text);
Everything is Ok until I type minus sign
If I copy/paste minus with number (eg -2) it works
Can Anyone help me!
Regards, Umar

The StrToInt conversion function is unsafe to use when you're not 100% sure the input string can be converted to an integer value. And the edit box is such an unsafe case. Your conversion failed because you've entered as a first char the - sign that cannot be converted to integer. The same would happen to you also when you clear the edit box. To make this conversion safe, you can use the TryStrToInt function, which handles the conversion exceptions for you. You can use it this way:
procedure TForm1.Edit1Change(Sender: TObject);
var
I: Integer;
begin
// if this function call returns True, the conversion succeeded;
// when False, the input string couldn't be converted to integer
if TryStrToInt(Edit1.Text, I) then
begin
// the conversion succeeded, so you can work
// with the I variable here as you need
I := I + 1;
ShowMessage('Entered value incremented by 1 equals to: ' + IntToStr(I));
end;
end;

You get an error, obviously, because - is not an integer. You can use TryStrToInt instead.

Related

How to specify multiple ranges for an if statement in Delphi? [duplicate]

This question already has an answer here:
Delphi check if character is in range 'A'..'Z' and '0'..'9'
(1 answer)
Closed 5 years ago.
for counter := 1 to lengthofpassword do
begin
currentletter:=password[counter];
currentascii:=Ord(currentletter);
if (96<currentascii<123) OR (64<currentascii<91) OR (47<currentascii<58) then
Writeln('valid')
else
asciicheck:=false;
end;
I know this code is wrong but I did it to explain what I want to ask. How can you specify ranges for an if statement? Before, I messed around with lots of if statements and my code wasn't working the way I wanted it to. Basically, I am making a procedure which checks the user input for anything other than uppercase and lowercase alphabet and numbers. This question is different because I was looking for how this problem could be solved using a Case Of statement.
for counter := 1 to lengthofpassword do
begin
currentletter:=password[counter];
currentascii:=Ord(currentletter);
if (currentascii<48) AND (currentascii>57) then
asciipoints:=asciipoints+1;
if (currentascii<65) AND (currentascii>90) then
asciipoints:=asciipoints+1;
if (currentascii<97) AND (currentascii>122) then
asciipoints:=asciipoints+1;
Writeln(asciipoints);
end;
I also tried to do it like this but then realised this wouldn't work because if one statement was satisfied, the others wouldn't be and the points based system wouldn't work either.
Glad you found the answer yourself.
Another way to make sure the password only contains upper and lower case characters and numbers is what I tried to point to: define a set of characters that are valid and check if each character in your password is in these valid characters.
So with a set defined like this:
const
ValidChars = ['A'..'Z', 'a'..'z', '0'..'9'];
you can use statements like
if password[I] in ValidChars then
This statement will however generate a compiler warning in Unicode Delphi, as the type in a set is limited to 256 possible values, and their ordinalities must fall between 0 and 255. This isn't the case for WideChar with 65.536 values. So the set of char defined is in fact a set of AnsiChar. For this task this is acceptable, as every character that needs to be checked is ASCII, so using the function CharInSet will not generate a compiler warning and have a defined behavior - returning False - if the password contains Unicode characters.
This is the resulting code:
const
ValidChars = ['A'..'Z', 'a'..'z', '0'..'9'];
var
I: Integer;
begin
for I := 1 to passwordlength do
begin
if CharInSet(password[I], ValidChars) then
Writeln('valid') // more likely to do nothing and invert the if statement
else
begin
asciicheck := False;
Break; // No need to look further, the check failed
end;
end;
end;
Multiple ranges is best expressed in a case statement:
begin
for counter := 1 to lengthofpassword do
begin
case Ord(password[counter]) of
48..57,
65..90,
97..122 :
Writeln('valid')
else
asciicheck:=false;
end;
end;
end;
Now, this works for characters < #128. If you are working in a unicode application and don't want the restriction of characters being the english alphabet, it is possible to use TCharHelper.IsLetterOrDigit.
if password[counter].IsLetterOrDigit then ...
Thanks to a comment up above, I have found a solution. I ended up using a Case Of statement like this:
for counter := 1 to lengthofpassword do
begin
currentletter:=password[counter];
currentascii:=Ord(currentletter);
case currentascii of
97..122 : asciicheck:=true;
65..90 : asciicheck:=true;
48..57 : asciicheck:=true;
else asciicheck:=false;
end;
end;
Thanks once again.

Delphi XE3: Convert WideChar array to Unicode string HOWTO?

I've done some research here regarding the problem given above and come up with the following code:
VarStr = array of WideChar;
function ArrayToString(const a: VarStr): UnicodeString;
begin
if Length(a) > 0 then
begin
ShowMessage ('Länge des übergebenen Strings: ' + IntToStr(Length(a)));
SetString(Result, PWideChar(#a[0]), Length(a) div 2)
end
else
Result := '';
end;
ShowMessage displays the correct number of characters in a given array, but the result of the function is always an empty string.
Your ideas please?
You are passing the wrong length value. You only ask for half of the characters. Fix your code like this:
function ArrayToString(const a: VarStr): string;
begin
SetString(Result, PWideChar(a), Length(a));
end;
However, you also report that your function returns an empty string. The most likely cause for that is that you are passing invalid input to the function. Consider this program:
{$APPTYPE CONSOLE}
type
VarStr = array of WideChar;
function ArrayToStringBroken(const a: VarStr): UnicodeString;
begin
SetString(Result, PWideChar(#a[0]), Length(a) div 2);
end;
function ArrayToStringSetString(const a: VarStr): UnicodeString;
begin
SetString(Result, PWideChar(a), Length(a));
end;
var
a: VarStr;
begin
a := VarStr.Create('a', 'b', 'c', 'd');
Writeln(ArrayToStringBroken(a));
Writeln(ArrayToStringSetString(a));
end.
The output is:
ab
abcd
So as well as the problem with the code in your question, you would seem to have problems with the code that is not in your question.
Perhaps when you said:
The result of the function is always an empty string.
You actually meant that no text is displayed when you pass the returned value to ShowMessage. That's a completely different thing altogether. As #bummi points out in comments, ShowMessage will truncate its input at the first null-terminator that is encountered. Use proper debugging tools to inspect the contents of variables.
Result:= Trim(string(a));
UPDATE: As colleagues graciously pointed in comments, this is a wrong answer! It works only because internal string and dynamic array implementation are pretty similar and there is no guarantee that such code would work in the future compilator versions. The correct way to DynArray->String conversion is described in the David answer. I would not delete my answer to preserve comments, in my opinion their worth is much greater..

Delphi: Help needed with errors with strings and integers

I need to make a 'Calculator' that works out and average for 3 different marks.
procedure TForm1.btnAddClick(Sender: TObject);
var
sName : string;
iprac, itheory, iproject : integer;
begin
sName := edtStudentName.text;
iprac := sedPrac.value;
iTheory := sedTheory.Value;
iProject := sedProject.Value;
lblOutput.caption := sName + ' You got ' + IntToStr (iPrac + iTheory + iProject) / 3;
end;
end.
Thats the code so far, but I get an error:
[Error] ComputerStudyMarks_u.pas(46): Incompatible types: 'String' and 'Integer'
Please be patient with me! I am a hardcore noob but this is for school.
Maybe someone can help me with this program.
I am busy using the book "Enjoy Delphi" and the code I am copying from the book itself is giving me an error.
Any help would be much appreciated!
P.S I cant add a picture of the form because I dont have enough reputation :(
iprac := sedPrac.value;
It's not clear what sedPrac is. And therefore what the Value property it. If Value is a string then you cannot assign a string to an integer. Your would need to convert to integer first, like this:
iprac := StrToInt(sedPrac.value);
Likewise for iTheory and iProject.
Of course, it may be that Value is already an integer, in which case your code is fine. My best guess is that these variables refer to TSpinEdit controls, and that Value is an integer, and so all is well. But that is just a guess.
IntToStr (iPrac + iTheory + iProject) / 3
Now, IntToStr is a function that returns a string. And there is no / operator defined for strings. Presumably you meant to write:
IntToStr((iPrac + iTheory + iProject) div 3)
Note that you have to use div since the value is an integer and / is floating point division.
Some final pieces of advice.
When presenting code, present all the information. You omitted to present some types here and so we don't know what sedPrac is.
When you present an error message, make sure that we can marry up the line number in the message with the code that you present. In your question, we don't know which line is line 46.

Delphi: How to determine and empty TDatetime value

Seems there is no way to assign NULL (either an "unassigned value" to TDateTime variables.
The only way I've imagined is using something like this:
function isNull(aDate : TDateTime) : boolean;
const NullDate = 0.0;
var aNullDate : TDatetime;
ms : Int64;
begin
aNullDate := NullDate;
ms := MilliSecondsBetween(aDate,aNullDate);
result := (ms = Int64(0));
end;
Is there anybody out who knows better solution what not overlaps 0 date value?
Are negative TDateTime values dangerous? (As an able resource for previous purpose)
As Andreas already wrote, the TDateTime type is actually double and thus not "nullable". I use
const
c_UnassignedDate = -693594;
for a empty date value as this represents an impossible date of 00/00/0000. But for example DevExpress uses
NullDate = -700000;
InvalidDate = NullDate + 1;
So there seems to be no agreed upon standard vale, you should pick one which suits your need.
First you need to define what you mean by 'an empty TDateTime value'.
A TDateTime value is a double with the date encoded in the integer part and the time encoded in the fractional part. So, the closest thing to a 'null date' you can get is probably 0.
Hence, simply test ADate <> 0 to test if the date is 'null'.
But beware: if you declare a TDateTime local variable then it will not necessarily be =0 before you give it a value. It can be anything. Of course, the same thing applies to variables of type integer, double, boolean, ...
Also, I believe that a TDateTime with value 0 encodes the date 1899-12-30.
Finally, negative TDateTime values are perfectly normal. For instance, -5000 corresponds to 1886-04-22.
I don't quite get the point of your code. If you want to use 0 as the 'unassigned' value (which is bad if you are interested in dates close to 1899-12-30), why not do simply
function IsUnassigned(ADate: TDateTime): boolean;
begin
result := ADate = 0;
end;
or, possibly (but not equivalently!),
function IsUnassigned(ADate: TDateTime): boolean;
begin
result := IsZero(Date);
end;
In his answer, ain gave a couple of more reasonable choices for the 'unassigned date' value.
At unit Spring.Persistence.Core.Session.pas of library Spring Framework for Delphi (http://www.spring4d.org) in method TSession.ExecuteScalar<T> in case of NULL for result used value Default(T);
I think, Your function can look like
function IsNull(ADate: TDateTime): Boolean;
begin
Result := ADate = Default(TDateTime);
end;
tDateTime is undefined for the values between 0 and -1 which means that a tDateTime of -0.5 is an undefined value and useful for a null date as an alternative to NaN. DateTimeToString will display -0.5 the same as +0.5;
Use PDateTime instead TDateTime, and send as nil value. If no pointer to value, result no value.
To check value use Assigned ptr :
MyDatePointer := nil;
if ( Assigned(MyDatePointer)) then ...

Variable might not have been initialized. Can I switch this warning on for a string?

When I compile this code
{$WARNINGS ON}
function Test(s: string): string;
var
t: string;
d: double;
begin
if s = '' then begin
t := 'abc';
d := 1;
end;
Result := t + FloatToStr(d);
end;
I get the warning "Variable 'd' might not have been initialized", but I do not get the same warning for variable 't'. This seems inconsistent. This code is only a simple example to show the compiler warnings, but I have just found a bug in my live code which would have been caught by a compile-time warning for uninitialised string variables. Can I switch this warning on somehow in Delphi 6? Or in a newer version of Delphi?
Nope, there is no switch for this. The warning doesn't occur because a string is a compiler managed type and is always initialized by the compiler.
Yes :-)
Use shortstrings or pChars
{$WARNINGS ON}
function Test: String;
var
p: pChar;
d: double;
begin
Result := p + FloatToStr(d);
end;
//This code will give a warning.
Seriously
No, the normal Delphi strings and shortstrings are automatically initialized to '' (empty string). Shortstrings live on the stack and don't need cleanup. Other strings are so called 'managed' types and automatically deleted when they are no longer used using reference counting.
PChars, the good news
pChars are just pointers. Delphi does not manage them.
However Delphi does automatically convert them to strings and visa versa.
pChars the bad news
If you convert a pChar to a string Delphi copies the contents of the pChar into the string and you are still responsible for destroying the pChar.
Also note that this copying takes time and if you do it a lot will slow your code down.
If you convert a string to a pChar Delphi will give you a pointer to the address the string lives in. And !! Delphi will stop managing the string. You can still assign values to the string, but it will no longer automatically grow.
From: http://www.marcocantu.com/epascal/English/ch07str.htm
The following code will not work as expected:
procedure TForm1.Button2Click(Sender: TObject);
var
S1: String;
begin
SetLength (S1, 100);
GetWindowText (Handle, PChar (S1), Length (S1));
S1 := S1 + ' is the title'; // this won't work
Button1.Caption := S1;
end;
This program compiles, but when you run it, you are in for a surprise: The Caption of the button will have the original text of the window title, without the text of the constant string you have added to it. The problem is that when Windows writes to the string (within the GetWindowText API call), it doesn't set the length of the long Pascal string properly. Delphi still can use this string for output and can figure out when it ends by looking for the null terminator, but if you append further characters after the null terminator, they will be skipped altogether.
How can we fix this problem? The solution is to tell the system to convert the string returned by the GetWindowText API call back to a Pascal string. However, if you write the following code:
S1 := String (S1);
the system will ignore it, because converting a data type back into itself is a useless operation. To obtain the proper long Pascal string, you need to recast the string to a PChar and let Delphi convert it back again properly to a string:
S1 := String (PChar (S1));
Actually, you can skip the string conversion, because PChar-to-string conversions are automatic in Delphi. Here is the final code:
procedure TForm1.Button3Click(Sender: TObject);
var
S1: String;
begin
SetLength (S1, 100);
GetWindowText (Handle, PChar (S1), Length (S1));
S1 := String (PChar (S1));
S1 := S1 + ' is the title';
Button3.Caption := S1;
end;
An alternative is to reset the length of the Delphi string, using the length of the PChar string, by writing:
SetLength (S1, StrLen (PChar (S1)));

Resources