Recent

Author Topic: RAD development of a GUI application with two versions and a single code base  (Read 532 times)

simone

  • Hero Member
  • *****
  • Posts: 626
I need to create a GUI application developed in RAD way, with a single code base, but having two versions, the first complete with all the functions, the second limited. The limited version, as a consequence, will not have some controls (menus, buttons, etc.) in its GUI.

To achieve this result I obviously use conditional compilation, including different .lfm files depending on the version. To show my approach, consider an example of an application in which the full version has two buttons, while the reduced only one .

Then I proceed as follows:

file unit1.pas:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2. {$DEFINE Full}
  3.  
  4. {$mode objfpc}{$H+}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     {$IFNDEF Full}
  18.     Button2: TButton;
  19.     {$ENDIF}
  20.   private
  21.  
  22.   public
  23.  
  24.   end;
  25.  
  26. var
  27.   Form1: TForm1;
  28.  
  29. implementation
  30.  
  31. {$IFDEF Full}
  32.   {$R unit1a.lfm}
  33. {$ELSE}
  34.   {$R unit1b.lfm}
  35. {$ENDIF}
  36. end.
  37.  

file unit1a.lfm:
Code: Pascal  [Select][+][-]
  1. object Form1: TForm1
  2.   Left = 269
  3.   Height = 240
  4.   Top = 250
  5.   Width = 320
  6.   Caption = 'Form1'
  7.   ClientHeight = 240
  8.   ClientWidth = 320
  9.   LCLVersion = '3.0.0.3'
  10.   object Button1: TButton
  11.     Left = 67
  12.     Height = 25
  13.     Top = 39
  14.     Width = 75
  15.     Caption = 'Button1'
  16.     TabOrder = 0
  17.   end
  18.   object Button2: TButton
  19.     Left = 217
  20.     Height = 25
  21.     Top = 143
  22.     Width = 75
  23.     Caption = 'Button2'
  24.     TabOrder = 1
  25.   end
  26. end
  27.  

file unit1b.lb:
Code: Pascal  [Select][+][-]
  1. object Form1: TForm1
  2.   Left = 269
  3.   Height = 240
  4.   Top = 250
  5.   Width = 320
  6.   Caption = 'Form1'
  7.   ClientHeight = 240
  8.   ClientWidth = 320
  9.   LCLVersion = '3.0.0.3'
  10.   object Button1: TButton
  11.     Left = 67
  12.     Height = 25
  13.     Top = 39
  14.     Width = 75
  15.     Caption = 'Button1'
  16.     TabOrder = 0
  17.   end
  18. end
  19.  

The problem with this approach is that in the case of complex applications the code management becomes complicated. In case the controls were created at run time, it would be easy to use conditional compilation, but in case of RAD approach, how should I proceed? As in the example I showed or is there a better approach? Is it possible to use some kind of conditional compilation inside the .lfm files? Thanks.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

MarkMLl

  • Hero Member
  • *****
  • Posts: 7859
The first thing I found myself wondering was whether frames could be usefully subclassed. I'm not sure that "(optionally) putting a frame inside another frame" would work because of the problem that the IDE has with instantiated frames.

However a better idea might be to create "full fat" forms, then to have the optional controls removed when the form was first activated. At that point you would have to consider the extent to which the remaining controls adjusted to fill gaps, /but/ from a support POV you might be better always being able to say "the button at the bottom-middle of the form" irrespective of whether there were three buttons there or just two (with a gap).

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

wp

  • Hero Member
  • *****
  • Posts: 12401
I would do this by means of frames. This splits functional elements off into separate units and moves the related code away from the main form which otherwise would be difficult to maintain due to thousands of line of code. You can design the frames at designtime like any form, but you must insert them into their parent form (or frame) at runtime, otherwise the risk that you damage properties or events is too high. You man want to apply auto-sizing, aligning and/or anchoring to size/position the frames correctly.

Look at the charteditor project in the TAChart demo folder, it works with lots of frames, even frames within frames.

By all means, I would avoid a "full fat" form which, if I understand correctly, contains all elements and only the needed ones are visible. This would be very hard to design and to maintain.

vfclists

  • Hero Member
  • *****
  • Posts: 1146
    • HowTos Considered Harmful?
You should consider getting creative with the object inspector component at runtime.

What you do is:

1. Load the full fat form at runtime

2. Use the object inspector to disable the parts you don't want.

3. Save the resulting form to an LFM file.

4. Redesign the program to stream in the LFM with the desired state at runtime.

I can't say I have tried this method yet, but I have a feeling it will work. The use of RTTI will probably help. Ask the experts.

The previous answers should also help with this.
Lazarus 3.0/FPC 3.2.2

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1173
Putting things only used sometimes into frames should work ok , however you will want to create all the child controls  of frames at runtime.

Yes it is possible to have nested frames, I used to do it all the time before I switched to custom controls.
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

MarkMLl

  • Hero Member
  • *****
  • Posts: 7859
3. Save the resulting form to an LFM file.

4. Redesign the program to stream in the LFM with the desired state at runtime.

I can't say I have tried this method yet, but I have a feeling it will work. The use of RTTI will probably help. Ask the experts.

I'm uncomfortable with that. I've received Stern Warnings from the core team that some fairly Deep Magic happens when a form is created, and that it's best left to the code inserted by the IDE in the .lpr unit.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

af0815

  • Hero Member
  • *****
  • Posts: 1372
Working around by bypassing the way of working of the IDE will go wrong. One way, described here earlier, is to deactivate the components/ events by programm.

Working with Frames at runtime (NOT designtime) is very good and it is no problem with frames in frames in frames... and also you can made parentframs and inherit to childs. This the same, you can do with normal forms. So you can made a frame with the basic functions and the child can be the fat version. The OOP can here help.

But dont deal with changing the lfm's and it is not possible to use conditional compiling inside of the lfm resource.
regards
Andreas

 

TinyPortal © 2005-2018