Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!



Share:
Notifications
Clear all

[Solved] lazarus pascal unexplained behaviour

25 Posts
2 Users
0 Likes
6,826 Views
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2678
 

Haha, no worries Jim - it happens to me as well, and I'm not 75 yet. 
I hate it when that happens, especially when it wake me up in the middle of the night. But I guess those are also the moments where I realize what went wrong. Which is probably just as poorly timed, and I always have to get out of bed to look at it / fix it ...

I do like what you're done with the Wind Energy and ScrapHeap Challenge.
I think it's a dying art to build something yourself, versus buying something crappy from China.

So I'll overlook you code for now, unless you'd like me to look at something specific.

Coming back to your Linked List question.
Well, you can use linked lists if you want, I'v done this in the past as well.
But you could also use a dynamic array or records (and set size or reset size with "setlength(array,number)")
For simple lists, this is what I use. Actually I've used it for complex lists as well, but it's not always suitable for that.

For example:

Type 
  TMyRecord = record
    field1 : integer;
    field2: string;
    ... // etc
  end;
  TMyRecordsArray = array of TMyRecord;
  ...
  var
    MyList: TMyRecordsArray;
...
    // set list to 5 records:
    setlength(MyList,5);
    // Clear list
    setlength(MyList,5);
    /// read an element (I presume you're familiar with records) from record 3
    writel(MyList[3].field2);
   // etc

I think you get the idea. 

You could add a field to the record to reference another record of course, or just use the index to access a record.

Working with linked lists still remains an option of course (I used to do this all the time in Turbo Pascal). But in a suitable situation, I just found that simply using records in a dynamic array, can be a lot easier. Again; obviously not every situation is as suitable for this.

Also note that with linked lists, one would use a record as well. One would have to add some extra code to add or remove nodes, and code to walk through the nodes of the linked list. I did bump into this article on Linked Lists in Pascal which explains it pretty well.
Advantages of a linked list over an array of records seems of course be that one can easier insert or remove elements. But you'd need to write code to unlink a node, relink the other 2 nodes, and such. So in the end ... I think an array of records will save a lot of time coding.

Hope this helps. 


   
ReplyQuote
(@jimb2019)
Active Member
Joined: 5 years ago
Posts: 14
Topic starter  

Hi Hans,

Mainly good news, the obstacles are being over come... sometimes with work-around's that were not anticipated, and all involving some degree of learning required! (a good and valuable experience)

One problem was the inability to create large arrays of records, I have moved to linked links which I have used in the past in Delphi, but I am not comfortable with them.

You may have some thoughts about an interesting problem- 

An event occurs randomly and the user MUST respond in a given time, 1 second say, the response is via a button, but the user could

 simply keep pressing the button randomly, may "work-around" was to simply disable the button except when the event requires it, but the button changes shade, (colour), when disabled, giving 

the user a large prompt that the event has occurred.

Web searches have failed to find a useful answer although it brought some vaguely related comments.    As you know, I cannot send messages, simple type a search and hope the topic has been covered 

Wishing you well, beat wishes, Jim


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2678
 

Hi Jim!

Great to hear you're making progress and seem to enjoying it! Nice!

Catching the button click like that may be tricky - depending on the surrounding code.
What I mean with that is that when code gobbles up to many resources, the click may be delayed or not caught at all (as you probably already experienced).

I've had that with an "Abort" button, to abort a heavy task in one of my programs.

My fix ended up being using threads, which is not all that easy to work with.
The idea is that one "thread" is doing (for example) the drawing and animation on the screen, while the main program remains in it's own thread, to allow catching the button click. Having said that, I'd have to read up on how easy it will be to apply in your situation. My main concern would be if drawing on the mainform will work from a thread or not.

Another method, albeit sloppier, is to frequently add "Application.ProcessMessages;" in your code that seemingly requires a lot of resources.
A button click after all triggers a message, and needs to get processed.
I assume that clicking the button has to be done while the circles (that you've mentioned before) are moving.
So in the code that does the moving; add "Application.Messages;" a few times, say every other line (just for testing if this even makes sense).

Hope this is helpful!

Best wishes to you as well Jim, and feel free to ask whenever you have a question 


   
ReplyQuote
(@jimb2019)
Active Member
Joined: 5 years ago
Posts: 14
Topic starter  

Hi Hans,

Thanks again, and again....

I seem to have a couple of exchanges appearing out of chronological order. weird, but not a problem, may be related to a major web failure in our area but not likely.

Great progress here, all systems are running ok'ish; I found I did not need to implement a link list, as the number of dots was not needed for the real program. During trials in old pascal I was using up to 5000 dots which gave visual proof that the area of display was a true circle, in practical use it only uses about 200-500 dots, for which an array is more than adequate.

Current problem relates to the need to create files of test results to be saved for later, I will need to name individual files later but, right now I am struggling with the changes in file handling in Object Pascal.

ALL the examples I find are needlessly complex and/or over loaded with error handling, 

I believe the small size of the files removes the need for streaming  or other speed related additions.

My attempt shown below does NOT recognise F_data as a declared variable,.. Cell is declared and used all over the place.

Hope you are enjoying the heatwave, I have a fridge in my shed but NO air-con

I spent quite a while in the tropics, India and NW Australia and loved it but It takes its toll now !

Best wishes,

Jim

BTW, My wife had her email hacked recently, I believe it was a pest but not toxic, I hope it did not migrate to you, it did get to Australia and most of her contacts .....


procedure TForm1.Save_dots(Sender: TObject); VAR a : Word; f_data : File OF cell; {File of all cell in cells;} BEGIN AssignFile(fdata, 'fdata.dat'); ReWrite fdata; FOR a := 1 TO Num_Dots DO BEGIN Write(F_Data, Cells[a]); END END;

   
ReplyQuote
(@jimb2019)
Active Member
Joined: 5 years ago
Posts: 14
Topic starter  

Hi Hans,

OOps!! within minutes of sending last nights missive I realised my beginners grade error, I had omitted to include a path for the saved filed, Not yet confirmed its validity but the code compiled, ran and did create a file with the right name!

In a months time I am attending the Ophthalmic dept at hospital for my check up and try to quiz the techie folk about the detail of the test procedure I am trying to emulate.

I am sure there are aspects that my program is ignoring and while I have NO idiotic hopes of creating a valid replacement, it would be nice if the result is a "guide" to users of their retinas' condition.

Later on, I hope you can guide me through the process of reducing the executable file size, I understand that Lasarus produces a massive lump of code with all the diagnostic addons still embedded.... 13 MBytes+  !

Cheers, (or is is it Prost)

Jim

  


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2678
 

Hi Jim! 

Glad that got resolved haha ... it happens to the best of us 
I was already wondering in the code. You declared f_data but you're using fdata ... but that's no longer relevant. You found the issue. 

I do like your idea though; even if folks could just do a minimal check before considering or actually going in to see an optometrist.

Making the executables smaller;

Well, with Lazarus (actually it's the Free Pascal Compiler FPC), tiny programs seem large. But as the program becomes much more complex, the size of the executable doesn't increase in the same proportion and stays smaller than expected.
I couldn't find the graph representing this, but initially small Delphi programs produce smaller EXE's. However, as the code becomes bigger, the Delphi EXE size will quickly exceed the size of a Lazarus EXE.

Another observation when comparing Delphi and Lazarus; Lazarus is much more optimized and code is quite often much faster than it's Delphi counter part.

Here is an interesting read on Size and how to fine tune it: Size Matters.

Having said all that, these are the rules I follow to keep size small;

1) When using images (for example PNG's), first optimize the image file size before using it in Lazarus.

Sometimes i use PNG images, and optimize the files (sometimes with amazing results) using ImageOptim (MacOS).
I believe OpiPNG (for Windows) produces similar optimizations.

2) Remove unused code (obvious) - this includes unused variables and units (the compiler actually informs you about those).

3) In Lazarus; create 2 build profiles: "Distribution" and "Debug". When building a release, set the profile to "Distribution".

Under "Project" - "Project Options" - "Compiler Options", you can see that there is a "Default" build mode.
Next to that you'll see a button "..." which allows to automatically create these 2 build modes.

4) After the executabel has been build, you can use the "strip" command in a DOS box.

I'm not sure about Windows, but under MacOS and Linux it still strips a lot of useless info, making the EXE even smaller.

> strip myprogram.exe

If you can't find the DOS strip command, it's somewhere tucked away in the freepascal setup.
If Lazarus was added to the PATH then it should work right away.

Also note: using tools like UPX is something I cannot recommend.
If you're not familiar with UPX. It used to be a great tool that compresses your binary executable to a much smaller executable file. What it in essence does is unpack it's data load (your actual EXE) in memory and then starts the extracted EXE. 
Downside: quite a lot of environments do not seem to like this (unlike the Win 3.1x/DOS days) and it's often falsely identified as malware.

On that note; I guess it also depends on how you'd like to distribute your app. 13Mb is not small, but it may not be a problem for floppy, or email (after using ZIP), or download.

Most of my complexer applications do not exceed 5Mb.

Hope this helps!

And yes cheers and prost both works for me! 
Cheers! 


   
ReplyQuote
(@jimb2019)
Active Member
Joined: 5 years ago
Posts: 14
Topic starter  

Hi Hans,

Still plodding on, but most of the anticipated problems are solved.. but am learning more about the fine detail of the many field tests that are used. there are details of the process that create a new wave of complexity, not only regarding the delivery of the test environment but also the interpretation of the results.

I will have to stop short of a real substitute but as you observed, a simple test MAY be just good enough to give a user an idea.

As you are aware, I am working on saving the data  files and a very silly problem has emerged, I need to create a file name on the fly as part of the process. After some considerable searching I believed that a TEdit box may be the way to enable the user to create a file name but it is obvious that I am NOT understanding haw to do this.

There may be a simpler, sensible solution but maybe you can see the obvious flaws in my current approach... the code follows 

The commented lines are simply removed attempts at bad ideas 

procedure TForm1.Save_dots(Sender: TObject);
VAR a : Word;
    filname : string;
    f_data : File OF cell; {File of all cell in cells;}
BEGIN
  form1.edit1.visible := True; // my way of making the form appear rather than enabling it when needed
  readLn(filname); //rubbish
// readLn(form1.edit1.text);
// filname := Form1.Edit1.text;
// AssignFile(f_data, 'd:/users/fdata.dat'); // works fine
    AssignFile(f_data, 'd:/users/'+filname+'.dat'); // works fine
  ReWrite( f_data);
  FOR a := 1 TO Num_Dots DO
  BEGIN
    Write(F_Data, Cells[a]);
  END
END;                 

   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2678
 

Hi Jim 

Well, for defining a filename, you could go 3 routes.

Options 1 and 3 have the downside that you'll need to somehow determine the path where to save the file (I'd recommend the 2nd option).
The "directoryseparator" is a constant which contains "/" or "\" (depending on the OS you're compiling on).

And of course after that

AssignFile(f_data, MyFileName);

You could define the variable "MyPath", in the expample 1 and 3, as 'd:/users/' of course, but I would not assume every user has a D-drive.

1. Derive it from the name (if entered somewhere on the form) followed by a date, for example "John Smith - 01-01-2019"

You could generate date (with time if needed) using the "FormatDateTime" function (in the unit "sysutils"), like so:

MyFileName := MyPath + directoryseparator + CustomerFirstName + ' ' + CutsomerLastname + ' - ' + FormatDateTime('DD-MM-YYYY',now) + '.dat';

"Now" is a known value and represents the current clock date and time.

2. You could use the TSaveDialog, where you can type the filename and determine the file location. (recommended)

Add a TSaveDialog to your form and do this:

if SaveDialog1.Execute then
  begin
    ...
    MyFileName := SaveDialog1.Filename;
    ...
  end;

The SaveDialog1.Execute will return TRUE if the user indeed clicked "Save" or "OK", and returns FALSE when the user clicks "CANCEL".

3. Of course using a TEdit for this can work as well.

Add a TEdit to your form and do this
if Edit1.Text<>'' then
  MyFileName := MyPath + directoryseparator + Edit1.Text + '.dat';
  ...

Hope this helps! 


   
ReplyQuote
(@jimb2019)
Active Member
Joined: 5 years ago
Posts: 14
Topic starter  

Hi Hans, 

As usual, within an hour of posting, I remembered an idea... DialogueBox, and after a few tries this morning, had a file save procedure running as needed!!

A crucial requirement of this procedure is to enable the user to enter the file name during run time. 

However, your post did prompt other thoughts,... as you mention in solution 1, the file name can be input using AssignFile(), but this, (I believe), can only be done in the code, and either the file name must be preordained in the code or must be obtained earlier via a user input medium. 

I believe that the same constraint applies to using the TEdit object. If I am wrong, please show me, my attempts to type into TEdit.text, (during run time), does not seem to function

As I say, the SaveDialog does solve the problem, but it is a bit untidy, so if TEdit can be used, I would prefer to go that way.

Thanks again,

Jim


   
ReplyQuote
 Hans
(@hans)
Famed Member Admin
Joined: 11 years ago
Posts: 2678
 

Hi Jim 

You're welcome!
Yeah I know how that goes - walk away from the problem for a few minutes and suddenly there is the answer 

One should be able to type in a TEdit, I guess that's the purpose of a TEdit.
The user should be able to type something there (if enabled = true).
If this is not the case, then something is terribly wrong ...

In code you can type something in a TEdit as well. You can set Edit1.Text := 'some string' and you can read Edit.Text as a string.


   
ReplyQuote
Page 2 / 2
Share: