Change Password Delphi v7 - delphi

Delphi v7
This code is designed to allow the user to change his password. It appears to execute correctly, but the new password is not saved in the the password data field. I must have done something wrong, but I cannot see it.
procedure TForm4.btnPswordClick(Sender: TObject);
var
I: integer;
begin
tblLogin.First;;
for I := 0 to tblLogin.RecordCount do
Begin
If tblLogin.FieldByName('Username').Value = Edit1.Text then
if tblLogin.FieldByName('Password').Value = Edit2.Text then
sign2.Visible := True; //Test in this case tells the application to make Label1
visible if the //username and password are correct
tblLogin.Next;
end;
I:= I+1; //ends search loop of records so program can move on
If sign2.Visible = False then
begin
MessageDlg('Error Username, or Password not correct',
mtConfirmation, [mbCancel], 0);
end
else
if edit3.Text <> edit4.Text then
begin
MessageDlg('Error New Password does not match',
mtConfirmation, [mbCancel], 0);
end
else
begin
tblLogin.Edit;
tblLogin.FieldByName('Password').Value := Edit3.Text;
tblLogin.Post;
//form1.Show;
//form4.Close;
end;

My comment about formatting your code was just me being snide, but in fact I think it really would have helped you find the error yourself. Properly indented, your first loop is this:
tblLogin.First;;
for I := 0 to tblLogin.RecordCount do
Begin
If tblLogin.FieldByName('Username').Value = Edit1.Text then
if tblLogin.FieldByName('Password').Value = Edit2.Text then
sign2.Visible := True; //Test in this case tells the application to make Label1 visible if the
//username and password are correct
tblLogin.Next;
end;
The next line of code is this:
I:= I+1; //ends search loop of records so program can move on
The comment suggests that you expect that line to cause the loop to terminate. But that line isn't in the loop. If it were in the loop, your code never would have compiled because you're not allowed to modify the loop-control variable inside a loop. Even outside the loop, the compiler should have warned you that the current value of I is undefined. That's because the compiler makes no guarantees about the final value of a loop-control variable once the loop has terminated. Adding 1 to an undefined value is still an undefined value.
Furthermore, your loop iterates over more records than your database table contains. If the upper bound of a for loop hasn't had 1 subtracted from it and isn't the result of High or Pred, then you're probably doing something wrong.
Since your I+1 line doesn't actually terminate the loop, you end up traversing all the way to the end of the table, so when you call tblLogin.Edit, you're putting the final record into edit mode, not the record with the matching account details.
Fixing the indentation will also show that you didn't even include all the code for that function. There's a begin without a matching end somewhere.
You could avoid all this code by using a single UPDATE statement on your database:
UPDATE tblLogin SET Password = ? WHERE Username = ? AND Password = ?

Related

Search and Replace in a Trichedit

We are working with XE7. We are trying to build a search and replace feature into a TRichEdit.
We would like it to work just like it works in the Delphi compiler. We display our own search and replace dialog, we are not using the Delphi replace dialog.
We display the dialog, and when the user clicks the Replace button, the dialog closes, and for each instance found we want to popup a message dialog asking the user whether they want to replace that occurrence.
When we do this, the user cannot see what is selected, and if they click Yes on the message dialog, nothing is being replaced.
Our code is below:
procedure Tviewform.select_text(fndpos:integer);
begin
setfocus;
asciieditor.selstart:=fndpos;
asciieditor.sellength:=length(vwvars[curviewwin]^.finddata);
end;
procedure Tviewform.search_and_replace;
var position,endpos,fndans,cont:integer; foptions:tsearchtypes; msgques,stopall:word;
begin
with asciieditor do
begin
endpos:=length(asciieditor.text)-vwvars[curviewwin]^.sstartpos;
foptions:=[];
stopall:=0;
cont:=0;
if findinfo.onbut.checked then foptions:=foptions+[stMatchCase];
lines.beginupdate;
fndans:=findtext(vwvars[curviewwin]^.finddata,vwvars[curviewwin]^.sstartpos,endpos,foptions);
while (fndans<>-1) and (stopall=0) do
begin
select_text(fndans);
msgques:=mainform.silang1.messagedlg('Replace with '+vwvars[curviewwin]^.replace+'?.',mtinformation,[mbyes,mbno,mbcancel],0);
if msgques=mryes then
begin
asciieditor.clearselection;
seltext:=vwvars[curviewwin]^.replace;
end else
begin
if msgques=mrcancel then
begin
cont:=0;
stopall:=1;
end else cont:=1;
end;
asciieditor.Repaint;
if cont=1 then
begin
inc(vwvars[curviewwin]^.sstartpos,length(vwvars[curviewwin]^.finddata));
endpos:=length(asciieditor.text)-vwvars[curviewwin]^.sstartpos;
fndans:=findtext(vwvars[curviewwin]^.finddata,vwvars[curviewwin]^.sstartpos,endpos,foptions);
end;
end;
lines.endupdate;
end;
end;
I see a number of issues with your code:
You are moving input focus away from the TRichEdit when you call select_text() and MessageDlg(), so make sure that TRichEdit.HideSelection is set to False (it is True by default) in order to actually see the selection.
You are calling BeginUpdate() on the TRichEdit, which disables screen redraws for it, including Repaint().
You don't need to call TRichEdit.ClearSelection() before setting the TRichEdit.SelText.
When updating vwvars[curviewwin]^.sstartpos after each replacement, you need to reset it to fndAns (the current selection's position) plus the length of vwvars[curviewwin]^.replace (the new text), not the length of vwvars[curviewwin]^.finddata (the old text). You are not moving it beyond the new text, so you are searching older text over and over.
If the user chooses No in the MessageDlg(), you are not updating vwvars[curviewwin]^.sstartpos to move past the text that the user didn't want to replace.
When setting endpos, length(asciieditor.text) can be asciieditor.gettextlen() instead for better efficiency. But more importantly, you should not be subtracting vwvars[curviewwin]^.sstartpos from endpos at all. By doing that, you are skipping more and more text at the end of the TRichEdit from the search with each replacement made. In fact, you should be using just the asciieditor's current text length as the end position of each search, so you don't actually need endpos at all.
Depending on the size of your TRichEdit and its content, if it has scrollbars enabled, you should send the TRichEdit a EM_SCROLLCARET message each time you find a matching text and before you prompt the user with the MessageDlg(), in case the matching text is off-screen.
With that said, try something more like this:
procedure Tviewform.search_and_replace;
var
fndAns: Integer;
fOptions: TSearchTypes;
msgQues: Word;
procedure select_text;
begin
{AsciiEditor.}SetFocus;
AsciiEditor.SelStart := fndAns;
AsciiEditor.SelLength := Length(vwvars[curviewwin]^.finddata);
AsciiEditor.Perform(EM_SCROLLCARET, 0, 0);
AsciiEditor.Update;
end;
begin
fOptions := [];
if FindInfo.OnBut.Checked then Include(fOptions, stMatchCase);
repeat
fndAns := AsciiEditor.FindText(vwvars[curviewwin]^.finddata, vwvars[curviewwin]^.sstartpos, AsciiEditor.GetTextLen, fOptions);
if fndAns = -1 then Break;
select_text;
msgQues := MainForm.SiLang1.MessageDlg('Replace with ' + vwvars[curviewwin]^.replace + '?', mtinformation, [mbYes,mbNo,mbCancel], 0);
if msgQues = mrYes then
begin
AsciiEditor.SelText := vwvars[curviewwin]^.replace;
AsciiEditor.Update;
Inc(fndAns, Length(vwvars[curviewwin]^.replace));
end
else if msgQues = mrNo then
begin
Inc(fndAns, Length(vwvars[curviewwin]^.finddata));
end else
Break;
vwvars[curviewwin]^.sstartpos := fndAns;
until False;
end;

In a textfile, How to express if ( Line 1's answer = Line 2's answer ) then

I just started Delphi.
I'm making a simple login form, and the text file (UserInfo.txt) is set up like this
I just want Delphi to run through the TextFile to look for the string, then if that string equals edtUseranme.Text then it must check if that string is equal to the string on the second line.
If it equals then it can continue to the next Form
Here is my code:
for I := 0 to Eof(tFile) do
begin
Readln(tFile, sLine);
Inc(I);
if ReadLn(tFile) = edtUsername.Text then
begin
if edtUsername.Text = then
begin
frmMain.Show;
frmLogin.Hide;
end
else
begin
ShowMessage('INPUT INVALID (Try again)');
end;
end;
end;
At that second if statement, I don't know what to put after =.
Like Ken White suggested, you could redesign your text file and then use a TStringList to parse it. That would certainly make it easier to work with the data. However, if you want to stick with the code you already have, then you could do something more like this instead:
var
tFile: TextFile;
//Declare variables for temporally storing read username and password
sUser, sPass, sDivider: string;
Valid: Boolean;
...
Valid := False;
//use while loop to read every line till the end of file
while not Eof(tFile) do
begin
//Read username into sUser variable
Readln(tFile, sUser);
//Read password into sPass variable
Readln(tFile, sPass);
//Read divider into sDivider variable
Readln(tFile, sDivider);
//Use if clause to perform multiconditional logical comparison to see if
//read username and password equals to those specified in suitable edit
//boxes
//NOTE: Each separate logical condition must be in its own brackets
if (sUser = edtUsername.Text) and (sPass = edtPassword.Text) then
begin
//If conditions are met we set local variable Valid to true
Valid := True;
//and then break the loop
Break;
end;
end;
//If local variable valid was set to True show the main form
if Valid then
begin
frmMain.Show;
frmLogin.Hide;
end else
//else we show message about invalid input entered
ShowMessage('INPUT INVALID (Try again)');
Your file format is poorly designed for what you're wanting to do, I'm afraid.
You'd be better off using a more standard format (realizing, of course, that it's totally insecure to store names and passwords as plain text). Delphi makes it easy to work with name/value pairs using TStringList with text like this:
Name=Value
This would mean your text file would contain the username=password type lines:
Bob=Password
Sue=Bambi
You then use TStringList to load the file and read the value associated with the name, like this:
var
SL: TStringList;
UserName, Password: string;
begin
UserName := Edit1.Text; // Your username control
Password := Edit2.Text;
// You should check to make sure that both the username and password
// were entered here before proceeding. I'll leave that to you to do.
SL := TStringList.Create;
try
SL.LoadFromFile('C:\Temp\UserInfo.txt'); // Replace with your filename
// The next line looks for a name in the stringlist equal to the
// entered username, and if it's found compares its value to the
// password that was provided.
//
// You'll need to handle making sure that you do a case-sensitive
// (or non-sensitive, depending on your needs) comparison is done
// if needed.
if SL.Values[UserName] = Password then
// Login succeeded
else
// Login failed.
finally
SL.Free;
end;
end;

Prevent inserting an empty memo

I am checking the contents of the memo before an insert query.
if memo1.lines.Text = '' then begin
showmessage('Warning:Missing data!');
abort;
end else ....
It works ok as long as there is nothing in the memo1.
However, when user hits enter inside the empty memo and the cursor moves
to the second line,running the query, fires the insert without a warning message,
though theres nothing in the memo.
Is there a way to prevent this ?
After the user hits enter your memo's text contains whitespace (the line-return), and so it doesn't equal ''.
You need to Trim the Text first. http://docwiki.embarcadero.com/Libraries/XE2/en/System.SysUtils.Trim
var
memoText : String;
...
memoText := Trim(memo1.lines.Text);
if memoText = '' then
begin
showmessage('Warning:Missing data!');
abort;
end else ....
If the user pressing RETURN is resulting in an additional line in the memo, then you must have the WantReturns property set to TRUE, and an OnKeyPress or OnKeyDown event handling the #13 key or VK_RETURN virtual key code.
If you set WantReturns to FALSE then the user must use CTRL+ENTER to insert a new line, and a simple striking of the RETURN key will not insert an empty line.
But if you are happy with the way your user interface currently behaves and simply want to check whether or not the memo contains only whitespace then you will have to validate this separately using Trim(Memo.Text) or some other mechanism for testing the content of the memo to meet your applications definition of "not empty".
As others have noted, using Trim() on Memo.Text simply in order to test for the presence of non-whitespace characters is potentially very inefficient, though how much of a concern this is in your case will depended a great deal on the expected content of the memo in your application.
A more efficient way to test for a non-whitespace string would be:
function ContainsOnlyWhitespace(const aString: String): Boolean;
var
i: Integer;
begin
result := FALSE;
for i := 1 to Length(aString) do
if (aString[i] > ' ') then
EXIT;
result := TRUE;
end;
Which would be used thus:
if ContainsOnlyWhitespace(Memo.Text) then
begin
// show warning message etc...
end;
This will be significantly more efficient than Trim() since it does not involve producing any new strings or modifying the string being tested.

Delphi7, Save User's Changes or other User's Information / Notes

In my program, the user completes a form and then presses Submit. Then, a textfile or a random extension file is created, in which all the user's information is written. So, whenever the user runs the application form, it will check if the file, which has all the information, exists, then it copies the information and pastes it to the form. However, it is not working for some reason (no syntax errors):
procedure TForm1.FormCreate(Sender: TObject);
var
filedest: string;
f: TextFile;
info: array[1..12] of string;
begin
filedest := ExtractFilePath(ParamStr(0)) + 'User\Identity\IdentityofMyself.txt';
if FileExists(filedest) then
begin
AssignFile(f,filedest);
Reset(f);
ReadLn(info[1], info[2], info[3], info[4], info[5], info[6], info[7],
info[8], info[9], info[10], info[11], info[12]);
Edit1.Text := info[1];
Edit2.Text := info[2];
ComboBox1.Text := info[3];
ComboBox5.Text := info[4];
ComboBox8.Text := info[4];
ComboBox6.Text := info[5];
ComboBox7.Text := info[6];
Edit3.Text := info[7];
Edit4.Text := info[8];
Edit5.Text := info[11];
Edit6.Text := info[12];
ComboBox9.Text := info[9];
ComboBox10.Text := info[10];
CloseFile(f);
end
else
begin
ShowMessage('File not found');
end;
end;
The file exists, but it shows the message File not found. I don't understand.
I took the liberty of formatting the code for you. Do you see the difference (before, after)? Also, if I were you, I would name the controls better. Instead of Edit1, Edit2, Edit3 etc. you could use eFirstName, eLastName, eEmailAddr, etc. Otherwise it will become a PITA to maintain the code, and you will be likely to confuse e.g. ComboBox7 with ComboBox4.
One concrete problem with your code is this line:
readln(info[1], info[2], info[3], info[4], info[5], info[6], info[7],
info[8], info[9], info[10], info[11], info[12]);
You forgot to specify the file f!
Also, before I formatted your code, the final end of the procedure was missing. Maybe your blocks are incorrect in your actual code, so that ShowMessage will be displayed even if the file exists? (Yet another reason to format your code properly...)
If I encountered this problem and wanted to do some quick debugging, I'd insert
ShowMessage(BoolToStr(FileExists(filedest), true));
Exit;
just after the line
filedest := ...
just to see what the returned value of FileExists(filedest) is. (Of course, you could also set a breakpoint and use the debugger.)
If you get false, you probably wonder what in the world filedest actually contains: Well, replace the 'debugging code' above with this one:
ShowMessage(filedest);
Exit;
Then use Windows Explorer (or better yet: the command prompt) to see if the file really is there or not.
I'd like to mention an another possibility to output a debug message (assuming we do not know how to operate real debugger yet):
{ ... }
filedest := ExtractFilePath(ParamStr(0)) + 'User\Identity\IdentityofMyself.txt';
AllocConsole; // create console window (uses Windows module) - required(!)
WriteLn('"' + filedest + '"'); // and output the value to verify
if FileExists(filedest) then
{ ... }

Table.Edit forcing Cursor to the EOF

Can someone please tell me why this only works one time after the aTbl.Edit.
If I rem out the four lines for editing the table it iterates through all 49 records. It seems that the Edit and Post will position the file-cursor at the end of the file as I am only ever getting one record changed and it quits with the EOF.
I am using D5, Zeos-6 and SQLite3. I even tried grabbing the Auto-inc before the edit and then a Locate after it, but it still quits after the edit.
Thanks for anything you can suggest, but this has been driving me nuts all afternoon. I keep thinking it is something stupid I have done, but I cannot find it. :)
aTbl.First; // Test DB has 49 records
while not aTbl.EOF do
begin
for i := 0 to lbCt.Items.Count-1 do // Currently only two items in the list
begin // and only the second makes a match
aMatch := False; // which then forces the edit
CtStr := lbCt.Items[i]);
case InOut.ItemIndex of
0: aMatch := aTbl.FieldByName(fld_A).AsString = CtStr;
1: aMatch := aTbl.FieldByName(fld_B).AsString = CtStr;
2: aMatch := (aTbl.FieldByName(fld_A).AsString = CtStr) or
(aTbl.FieldByName(fld_B).AsString = CtStr);
3: aMatch := (aTbl.FieldByName(fld_A).AsString = CtStr) and
(aTbl.FieldByName(fld_B).AsString = CtStr);
end;
if aMatch then
begin
aTbl.Edit;
aTbl.FieldByName('Account').AsString := lbCt.Items[i];
aTbl.FieldByName('Folder').AsString := lbCt.Items[i];
aTbl.Post;
end;
end;
aTbl.Next;
end;
The problem is most likely that you have an index active that uses either Account or Folder as one of the index fields. Those are the fields you're changing the value of, and if either of them is in the current index expression it will move the record pointer to the new location for the row (which might in fact be EOF).

Resources