Recent

Author Topic: Questions about Program design.  (Read 963 times)

OC DelGuy

  • Full Member
  • ***
  • Posts: 218
  • 123
Questions about Program design.
« on: April 13, 2025, 11:44:36 pm »
I have two questions:
I'm about to write an application that is going to use several forms.  I've learned to share information between forms by using controls (mainly, the TEdit).
  • How can I share a variable that I don't have displayed in a control?

  • I'm thinking of making a unit (without a form) just to hold type declarations (records that are used by all forms), variables (used by all forms) and will handle the file disk storage and access.  So, I'm thinking one form will be the MainForm and the others are SlaveForms that gather the information from the user, crunch it up a bit and then send to the unit with all the records.  Then the MainForm gets the information from the unit and displays it.  Is this the best concept for writing applications, or should I be doing this differently?
Free Pascal Lazarus Version #: 2.2.4
Date: 24 SEP 2022
FPC Version: 3.2.2
Revision: Lazarus_2_2_4
x86_64-win64-win32/win64

jamie

  • Hero Member
  • *****
  • Posts: 7522
Re: Questions about Program design.
« Reply #1 on: April 14, 2025, 12:22:52 am »
I guess you figured it out.

create a Unit called "Common" for example, where all other units and include it.

Place all your public types and variables in the interface section and you are good to go.

The only true wisdom is knowing you know nothing

silvercoder70

  • Full Member
  • ***
  • Posts: 200
    • Tim Coates
Re: Questions about Program design.
« Reply #2 on: April 14, 2025, 12:36:46 am »
Either way can work.

With your second point, you are starting to separate the UI from the data ... which is a good thing. That separation means you can change the UI (someway) and not have to worry about modifying too much code that would exist in data-related units.

Without going into detail about MVC or related ideas, what you describe is moving toward a cleaner architecture — where you isolate data storage and business logic from user interface concerns. It can make your application more maintainable and easier to test.

Hope that helps.
🔥 Pascal Isn’t Dead -> See What It Can Do: @silvercoder70 on YouTube

VisualLab

  • Hero Member
  • *****
  • Posts: 712
Re: Questions about Program design.
« Reply #3 on: April 14, 2025, 01:30:08 am »
If you want the program to:
  • have a clear code,
  • be relatively easy to expand later,
  • have order in the source code,
you can use data containers that will store:
  • working data, its content can be loaded from a file and also saved by the user to the file when the content of this container changes,
  • auxiliary information, its content will not be saved after the program is closed.
The container from point 1, storing the actual data, could be a class (named e.g. TDataContainer), derived from TObject or TComponent, then it will be convenient to use in the code. It can have methods for cleaning its contents, saving data to a file, loading data from a file). It can also have properties properties used for changing (i.e. actual data) and properties informing about its state (read-only). This is part M of the MVC pattern, only simplified.

The container from point 2, storing auxiliary data could be a record (named e.g. TSession) or a simple class derived from TObject. It is intended only to exchange data between other objects. Its contents are to be lost when the program is closed.

Gradually (as the program develops), you can easily add the necessary properties, methods and events to them. This may seem complicated but in reality it is quite simple. It helps to keep the code simple and tidy. I have been using this approach for quite a long time.

---

EDIT:

You can also add a container that will be responsible for saving and reading program settings (named e.g. TSettings). It can also be implemented as a record or an object (e.g. TObject class). It can have methods for saving and reading program settings to/from an INI file (multi-platform) or the Registry (if the program will be used only on Windows).

Each of these containers would be used to store and exchange various information. Separating them into separate containers allows you to keep your code tidy.

What I would suggest avoiding is placing many simple variables in forms (a multitude of many variables of various simple types placed in different modules). As the program's source code becomes more and more extensive, this approach will be worse than plowing in a rocky field.

In the case of records, it is enough to declare them as a private field in the class of the main program window. To pass them to other windows (e.g. dialog windows), it is enough to pass a pointer to such a record. As 440bx suggests, using advanced records is a very good idea. Moreover, using them is practically covering 3/4 of the way towards OOP :)

Of course I prefer the object-oriented approach (classes), because I am irreversibly tainted by the "religion" of OOP :) And in fact (no kidding), when the program code becomes more complex, classes really simplify further expansion. Some caution is required here: if the program is simple, there is no point in using OOP. This is profitable when the program will ultimately be expanded (I omit using the default Lazarus classes from the LCL library to create the GUI).
« Last Edit: April 14, 2025, 06:55:27 pm by VisualLab »

440bx

  • Hero Member
  • *****
  • Posts: 6083
Re: Questions about Program design.
« Reply #4 on: April 14, 2025, 02:20:41 am »
I'm going to offer a solution that works in Windows.

Here are the two crucial features:

1. Associate a pointer to a form.

In Windows you can stick a pointer to whatever you want in the userdata field of the window or, you can reserve bytes where you stick your pointer or you can associate a property with a window (window properties are slower to access but convenient when you didn't create the window.)  Of those three ways, the simplest, particularly if you are the window creator is to use the userdata field.  See SetWindowLong/LongPtr for more information (caution: I don't know if Lazarus already uses this field for its own purposes, you might want to determine that before you use it.)


2. Create an advanced record that has all the variables you want to share among the forms/windows and store a pointer to that advanced record in the userdata field (as suggested in 1. above.)

You can do the same with a plain record but, an advanced record is better in this case because it allows you to define properties to read/write the fields/variables thereby keeping your forms independent of the actual field names used in the record.  Another advantage is that the advanced record allows you to define constants and types that can be totally private to the record thereby blackboxing the data to some extent.  It also gives you the possibility of defining procedures/functions designed specifically to use and manipulate that data through them.

A "bonus" of this method is that, it also allows sharing that advanced record with non-form functions/procedures by having a function that returns the top level form handle (which is a window handle), once you have the window handle, use GetWindowLongPtr to retrieve the pointer to the advanced record.  That enables _any_ function/procedure/method in your program to access those variables without having to pass them around as parameters.  The important thing in that case is to create a function usable anywhere in the program that given a window handle retrieves the pointer to the advanced record.  Sky is the limit.  Windows has a very convenient function to implement this called "GetTopLevelWindow" unfortunately it's undocumented but it has been in Windows for ages and is likely there to stay (I use it in my code without any worries at all.)  Also, if interested I posted an example of how to use it (Post 6 of Winapi examples.)  Effectively, the advanced record becomes a "selective global variable", selective because only those functions that retrieve the pointer to it can access it.  This is a nice way of keeping global program state without having to use one or more global variables stored in a "common/global" unit.

HTH.
« Last Edit: April 14, 2025, 02:25:12 am by 440bx »
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

cdbc

  • Hero Member
  • *****
  • Posts: 2612
    • http://www.cdbc.dk
Re: Questions about Program design.
« Reply #5 on: April 14, 2025, 09:49:36 am »
Hi
I think THIS thread touches on most of your questions...
...And if that hits your sweet spot, there's a nifty tool, for doing MVP style development HERE.
These architectures scale to big apps, quite easily...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

 

TinyPortal © 2005-2018