Pascal : External File Can't be updated - external

I have an issue on rewriting my .txt file, did I made some mistake? The program run smoothly though. This is a piece of my library.
//global variable
uses utheatre;
var loadUDT:TheatreUDT;
//utheatre library
type
TheatreUDT = record
Member:text;
end;
procedure load_main(var loadUDT : TheatreUDT);
begin
load_Member(loadUDT.Member);
end;
procedure load_Member(var Member:text);
begin
assign (Member,'Data/Member.txt');
end;
procedure regis(var loadUDT:TheatreUDT);
var
s:string;
begin
rewrite(loadUDT.Member);
write('> Input Username : ');
readln(s);
write(loadUDT.Member,s);
write(loadUDT.Member,' | ');
write('> Input Password : ');
readln(s);
write(loadUDT.Member,s);
writeln(loadUDT.Member,' | 100000');
writeln('> Registration Successful');
end;
procedure exit(var loadUDT:TheatreUDT; var bool_main:boolean);
begin
close(loadUDT.Member);
bool_main := False;
end;
I expected the output inside my notepad will be
username | password | 100000
but it seems that the Member.txt is not updated. Thanks before.
EDIT : This is My Main Program
begin
bool_main := True;
while(bool_main) do begin
write('> ');
readln(input_main);
case input_main of
'load' : load_main(loadUDT);
'register' : regis(loadUDT);
'exit' : exit();
end;
end;
end.
N.B. I found out that when I add "close(loadUDT.Member)" inside my "regis procedure", it worked, however it didn't work when i insert the "close(loadUDT.Member)" inside the "exit procedure". Any ideas why? Thanks again before.

Nevermind, I found the answer already. exit() is reserved. Sorry Guys.
N.B. Thanks to #gammatester

Related

GMLib MegaDemo.exe Won't load

The map won't load anymore on the megademo.exe.
The problem start when i put: GMMap1.Active := True;
Thanks for the help.
try this
var
FMapLoaded: boolean;
procedure TMainForm.GMMapAfterPageLoaded(Sender: TObject;
First: Boolean);
begin
inherited;
if First and not FMapLoaded then
begin
GMMap.DoMap;
FMapLoaded := True;
end;
end;
To solve this problem, you must to change the method TGMMap.DocumentComplete from GMMapVCL unit with this
before
if (pDisp = CurDispatch) then
after
if not FDocLoaded and (pDisp = CurDispatch) then

How can I declare a function from within a function in Delphi/FreePascal without nesting them?

I would like to do something like this:
(I want to conserve the functions public so I can access them from other procedures/functions).
The functions are on the same form (frmSequenciador) - I didn't post it for it is huge in its integrity..
function geradorDeVetores():TIntArray;
var
contador: Integer;
vetor: array [1..numMax] of integer;
begin
Randomize;
for contador:=1 to numMax do
begin
if contador = 1 then
vetor[contador]=float_round_down(Random*10);
else vetor[contador]:= ***frmSequenciador.evitaRepeticao(contador, vetor)***;
end;
end;
function evitaRepeticao(pos: integer; vetor:TIntArray):integer;
var
numigual: boolean;
temporario, cont: integer;
begin
numigual:=true;
temporario:= float_round_down(Random*10);
for cont:=1 to pos-1 do
if temporario <> vetor[cont] numigual:=false else numigual:=true;
if numigual=false then evitaRepeticao():=temporario else evitaRepeticao():=***frmSequenciador.evitaRepeticao(pos, vetor)***;
end;
It was a simple matter of removing the frmSequenciador prefix of the functions as Ken White stated.
What I wanted to know is: if two functions are inside the same form unit (thx Jerry), do we need a prefix to call each other?
It seems not. Thanks all!

How can I use the IconField argument in LoadFromDataSet function of TGMMarker (GMLIB)

I am using loadfromdataset function of TGMMarker object in GMLib, but I can't get the IconField to work.
I have a BLOB field with a png image to use as a Icon. I load the very same image file directly from the
folder with no problems, but when I try to do it with the IconField argument it gives error.
Here's the code
inherited;
GMMap1.Active := True;
GMMarker1.LoadFromDataSet(Dscameras.DataSet,'Latitude','Longitude',
'Descrição','Distintivo');
Gives this error :"Erro de Script" "Constante de cadeia não finalizada"
The minimum code is:
procedure TForm1.FormCreate(Sender: TObject);
begin
ClientDataSet1.LoadFromFile('markers.xml');
GMMap1.Active := True;
end;
procedure TForm1.GMMap1AfterPageLoaded(Sender: TObject; First: Boolean);
begin
if First then
begin
GMMap1.DoMap;
GMMarker1.LoadFromDataSet(ClientDataSet1, 'lat', 'lng', 'title');
GMMarker1.ZoomToPoints;
end;
end;

Calling TEdit objects based on DB query

I have a form with 7 TEdit having name EditPhone1, EditPhone2 and so on.
In the same form I query a DB to get data to fill those TEdits. Of course I cannot know in advance how many results the query will return.
How can I call the various TEdit objects when looping on the rowcount of the query?
Use FindComponent to "convert" a component name to the component itself:
var
Edit: TEdit;
I: Integer;
begin
DataSet.First;
I := 1;
while not DataSet.Eof do
begin
Edit := TEdit(FindComponent(Format('EditPhone%d', [I])));
if Edit <> nil then
Edit.Text := DataSet.FieldValues['PhoneNo'];
DataSet.Next;
Inc(I);
end;
Now, this requires to hard-code the EditPhone%d string into the source which results in all kinds of maintainability issues. For example: consider renaming the edits.
Alternative 1:
To not rely on the component names, you could instead make use of TLama's idea and add all the edits to a list:
uses
... , Generics.Collections;
type
TForm1 = class(TForm)
EditPhone1: TEdit;
...
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FEdits: TList<TEdit>;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FEdits := TList<TEdit>.Create;
FEdits.AddRange([EditPhone1, EditPhone2, EditPhone3, EditPhone4, EditPhone5,
EditPhone6, EditPhone7]);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FEdits.Free;
end;
procedure TForm1.ADOQuery1AfterOpen(DataSet: TDataSet);
var
I: Integer;
begin
DataSet.First;
I := 0;
while (not DataSet.Eof) and (I < FEdits.Count) do
begin
FEdits[I].Text := DataSet.FieldValues['PhoneNo'];
DataSet.Next;
Inc(I);
end;
end;
This still requires some maintenance in case of adding edits in future.
Alternative 2:
You could also loop over all edits in the form to find the ones tagged to be added to the list, instead of adding them each explicitly:
procedure TForm1.FormCreate(Sender: TObject);
var
I: Integer;
begin
FEdits := TList<TEdit>.Create;
for I := 0 to ComponentCount - 1 do
if (Components[I] is TEdit) and (TEdit(Components[I]).Tag = 1) then
FEdits.Add(TEdit(Components[I]));
end;
But keeping those tags up to date is another burden.
Alternative 3:
I suggest you use a TDBGrid which is a data-component. Opening the linked dataset will automatically add all phone numbers to the grid. With some settings, the grid may kind of look like a couple of edits below each other.
You can, for example, use Tag property, to find needed component. Set all you TEdit's tag from 1 to 7 (or more), and find component by:
Var I: Integer;
MyEdit : TEdit;
For I = 0 To Self.ComponentCount - 1 Do
if (Self.Components[I] IS TEdit) AND (Self.Components[I] AS TEdit).Tag = YourTag
MyEdit = (Self.Components[I] AS TEdit);
You can also dynamically create so many TEdits, you need, and assign Tag property on creation, and find it this code later in runtime.
I'd suggest using DBCtrlGrid. You place your controls for one row on it, and it repeats the controls for as many rows as your data set has.
Get query result (usually using .RowCount property of TDataset return)
After getting the number of row, do iteration to make TEdit and set the text property
Here is sample of code:
...
For i:=0 to RowCount do
Begin
A:=TEdit.Create(self);
A.Parent:=AForm;
A.Top:=i*14;
A.Text:=ADataset.Field(i).AsString;
End;
...

Pascal - not writing to file

Howdy, Pascal masters!
I've got a file type of custom records:
DBCell = record
Name: string[10];
Surname: string[15];
Balance:integer;
OpenDate: record
year: integer;
month: 1..12;
day:1..31
end;
AccountN: string[10];
end;
DBFile = file of DBCell;
And functions, that open and add new element to file:
procedure Fopenf(var F:DBFile; var FName:string; var FOpened:boolean);
begin
Assign(F,FName);
rewrite(F);
FOpened:=true;
end;
procedure InsN(var F:DBFile;var cell:DBCell;var FOpened:boolean);
begin
Write(F,cell);
Close(F);
Rewrite(F);
Writeln('Added');
FOpened:=false;
end;
Problem is, nothing is actually written to file. What am I doing wrong?
It's been a long time since I've done any Pascal, but IIRC Rewrite truncates the file. You should use Append.
You don't need the Rewrite() after inserting a record in the file:
procedure InsN(var F:DBFile;var cell:DBCell;var FOpened:boolean);
begin
Write(F,cell);
Close(F);
Writeln('Added');
FOpened:=false;
end;
If you don't want to truncate the file every time you open it:
procedure Fopenf(var F:DBFile; var FName:string; var FOpened:boolean);
begin
Assign(F,FName);
append(F);
FOpened:=true;
end;
The problem is the 'rewrite' call in InsN. 'Rewrite' creates a new file, so by calling it at the end of your program, you are creating a new, empty file!