Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2009-05

TFPColor vs TColor

22 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

I'm looking at starting the conversion of fpGUI Toolkit's own Canvas and Image classes, to using the TFPCustomCanvas and related image classes.

Looking at TFPColor as defined below.... I looked at using something similar to this in fpGUI, but soon realized that published properties of record type is not supported. So I ended up using similar to Lazarus and Delphi - TColor of type integer.

==============[ fpimage.pp ]===============
TFPColor = record

    red,green,blue,alpha : word;
  end;

========================================

I really like the idea of having separated R,G,B,A colors. Plus you always know the order of the separated R, G, B and A. The individual colors could also store values higher that 0..254 for other color space implementations (I think). But what's the point of having TFPColor when properties of that type can't be published.

You will never be able to have something like the following...

  TPanel = class(...)
     ...
  published
     property Color: TFPColor read FColor write FColor;
  end;

Even Lazarus had to override all the FPColor properties in Canvas and Image classes to use TColor instead. So what's the point? Am I missing something.

If the Reader/Writer classes used for streaming Lazarus Form files
(*.lfm) could handle TFPColor the output could look as follows:
  object Panel1: TPanel
    Left = 213
    Height = 50
    Top = 37
    Width = 170
    Caption = 'Panel1'
    Color = (240,0,115,0)
  end

Color being of type TFPColor and the values in brackets are always in R, G, B, A order (no matter the platform). I have seem many theme config files under Linux using a similar format for storing color values. Is this possible with the Reader/Write? But first we have to address the problem of the TFPColor not being able to be published.

So in summary:

* What's the point of TFPColor when we cannot publish it.
* Can the Reader/Writer support TFPColor

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Michael Van Canneyt
to Graeme Geldenhuys
Graeme Geldenhuys wrote 23 lines
Hi, I'm looking at starting the conversion of fpGUI Toolkit's own Canvas and Image classes, to using the TFPCustomCanvas and related image classes. Looking at TFPColor as defined below.... I looked at using something similar to this in fpGUI, but soon realized that published properties of record type is not supported. So I ended up using similar to Lazarus and Delphi - TColor of type integer. ==============[ fpimage.pp ]=============== Color being of type TFPColor and the values in brackets are always in R, G, B, A order (no matter the platform). I have seem many theme config files under Linux using a similar format for storing color values. Is this possible with the Reader/Write? But first we have to address the problem of the TFPColor not being able to be published. So in summary: * What's the point of TFPColor when we cannot publish it.

When designing FPCanvas and so on, streaming was not taken into consideration at all. The point was to be able to represent all possible colors, independent of a GUI system or streaming system.

* Can the Reader/Writer support TFPColor

No, because records cannot be published. To do this, you'd need something like a TGUIColor wrapper, which is a TPersistent:

TGUIColor = Class(TPersistent)
Private
  FColor : TFPColor
Public
  Property Color : TFPColor Read FColor Write FColor;
Published
  Property Red : Word Read FColor.Red Write FColor.Red
  // Same for blue,green,alpha
end;

Publish a property TGUIColor for streaming, but use it's color property when drawing.

Another possibility would be
TMyColor = Int64
publish this, and typecast in the getter/setter to/from TFPColor.

Personally, I'd go for the first option.

Michael.

Reply by email

Graeme Geldenhuys
to Michael Van Canneyt
Michael Van Canneyt wrote
When designing FPCanvas and so on, streaming was not taken into consideration at all. The point was to be able to represent all possible colors, independent of a GUI system or streaming system.

Fair enough.... Design without any perceived limitations. ;-)

Show quoted text 5 lines
> * Can the Reader/Writer support TFPColor No, because records cannot be published. To do this, you'd need something like a TGUIColor wrapper, which is a TPersistent:

Clever idea - I like that. A quick test revealed that streaming to LFM will look like this:

object AMyComponent: TMyComponent

Left = 0

Height = 22

Top = 0

Width = 126

Caption = 'AMyComponent'

Color = clSkyBlue

ParentColor = False

TabOrder = 5

FPColor.Red = 42662

FPColor.Green = 51914

FPColor.Blue = 61680

FPColor.Alpha = 65535

end

Obviously removing Color property (of type TColor) from published section in final design.
Thanks Michael for your quick response.

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Luca Olivetti
to Graeme Geldenhuys

En/na Graeme Geldenhuys ha escrit:

Show quoted text 15 lines
On Tue, May 5, 2009 at 9:30 AM, Michael Van Canneyt wrote: > When designing FPCanvas and so on, streaming was not taken into consideration > at all. The point was to be able to represent all possible colors, independent > of a GUI system or streaming system. Fair enough.... Design without any perceived limitations. ;-) >> * Can the Reader/Writer support TFPColor > No, because records cannot be published. To do this, you'd need something > like a TGUIColor wrapper, which is a TPersistent: Clever idea - I like that. A quick test revealed that streaming to LFM will look like this:

I'm not sure, but I think that if it is a visual component, changing its color it should invalidate/redraw itself.
With 4 properties it will be redrawn 4 times instead of just one.

Bye

Luca

Reply by email

Michael Van Canneyt
to Luca Olivetti
Luca Olivetti wrote 22 lines
En/na Graeme Geldenhuys ha escrit: > On Tue, May 5, 2009 at 9:30 AM, Michael Van Canneyt > wrote: > > When designing FPCanvas and so on, streaming was not taken into > > consideration > > at all. The point was to be able to represent all possible colors, > > independent > > of a GUI system or streaming system. > > Fair enough.... Design without any perceived limitations. ;-) > > > > * Can the Reader/Writer support TFPColor > > No, because records cannot be published. To do this, you'd need something > > like a TGUIColor wrapper, which is a TPersistent: > > > Clever idea - I like that. A quick test revealed that streaming to LFM > will look like this: I'm not sure, but I think that if it is a visual component, changing its color it should invalidate/redraw itself. With 4 properties it will be redrawn 4 times instead of just one.

There are various ways around this. beginupdate/endupdate for instance. Setting .Color will set all 4 components at once, and should redraw only once.

If, of course, you choose to set the RGB separately, then you'll redraw 4 times. But that is up to you.

Michael.

Reply by email

Graeme Geldenhuys
to Luca Olivetti: En/na Graeme Geldenhuys ha escrit: I'm not sure, but I think that if it is a visual…
Luca Olivetti wrote
I'm not sure, but I think that if it is a visual component, changing its color it should invalidate/redraw itself. With 4 properties it will be redrawn 4 times instead of just one.

* When loading a stream from *.lfm files, no updates occur until everything is loaded.

* If setting each R, G, B, A properties individually, then yes you would get 4 redraws. But if the property supports
BeginUpdate/EndUpdate, then that can be overcomed.

* If modified the TGUIColor class to have a few public properties (the joys of class types - that's why I like Java code) which gives you TFPColor and TColor (Delphi/Lazarus style) support. Setting any of those will only cause a single redraw.

Anyway, fpGUI doesn't use streaming of form files by default. Forms are defined via normal code (and redraws are limited to only once while initializing a form). But I want to make sure fpGUI can support streaming if required in the future or if LCL-fpGUI is developed.

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Vincent Snijders
to Graeme Geldenhuys
Graeme Geldenhuys wrote
Anyway, fpGUI doesn't use streaming of form files by default. Forms are defined via normal code (and redraws are limited to only once while initializing a form). But I want to make sure fpGUI can support streaming if required in the future or if LCL-fpGUI is developed.

Under what circumstances are properties of fpGUI classes streamed when LCL-fpGUI is developed?

Vincent

Reply by email

Graeme Geldenhuys
to Vincent Snijders
Vincent Snijders wrote
Under what circumstances are properties of  fpGUI classes streamed when LCL-fpGUI is developed?

I haven't delved much into the LCL widgetset internals, so I might have this wrong. I would have thought streaming will occur when the properties of fpGUI components (TfpgForm, TfpgButton etc) are being set when a LCL-fpGUI based form (*.lfm) is loaded?

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Vincent Snijders
to Graeme Geldenhuys
Graeme Geldenhuys wrote 10 lines
On Tue, May 5, 2009 at 1:08 PM, Vincent Snijders wrote: > Under what circumstances are properties of fpGUI classes streamed when > LCL-fpGUI is developed? I haven't delved much into the LCL widgetset internals, so I might have this wrong. I would have thought streaming will occur when the properties of fpGUI components (TfpgForm, TfpgButton etc) are being set when a LCL-fpGUI based form (*.lfm) is loaded?

An LCL form is streamed and LCL properties and components are set. When creating a handle (widget reference) an fpGUI object will be created by the TFpGuiWidgetSet interface, but that is done without streaming.

Vincent

Reply by email

Mattias Gaertner
to Graeme Geldenhuys: On Tue, May 5, 2009 at 1:08 PM, Vincent Snijders I haven't delved much into the LCL…
Show quoted text 10 lines
On Tue, May 5, 2009 at 1:08 PM, Vincent Snijders wrote: > > Under what circumstances are properties of  fpGUI classes streamed > when LCL-fpGUI is developed? I haven't delved much into the LCL widgetset internals, so I might have this wrong. I would have thought streaming will occur when the properties of fpGUI components (TfpgForm, TfpgButton etc) are being set when a LCL-fpGUI based form (*.lfm) is loaded?

No.
Only the widgetset independent LCL properties are set. The LCL interfaces then reads/sets the widgetset properties.

fpgui needs published properties when you want to edit components visually. At the moment lazarus has designers for lcl TFrame, lcl TForm and fcl TDataModule. Maybe someday you want to add a designer for fpgui forms. hint, hint ;)
The object inspector, property editors and component editors work with TComponent, so they already work with fpgui forms/controls.

Mattias

Reply by email

Graeme Geldenhuys
to Vincent Snijders: An LCL form is streamed and LCL properties and components are set. When creating a handle…
Vincent Snijders wrote
An LCL form is streamed and LCL properties and components are set. When creating a handle (widget reference) an fpGUI object will be created by the TFpGuiWidgetSet interface, but that is done without streaming.

Ah ok - now I get it. Thanks for explaining that.

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Graeme Geldenhuys
to Mattias Gaertner: On Tue, 5 May 2009 13:15:02 +0200 No. Only the widgetset independent LCL properties are…
Mattias Gaertner wrote
No. Only the widgetset independent LCL properties are set. The LCL interfaces then reads/sets the widgetset properties.

Thanks for explaining...

fpgui needs published properties when you want to edit components visually. At the moment lazarus has designers for lcl TFrame, lcl TForm and fcl TDataModule. Maybe someday you want to add a designer for fpgui forms. hint, hint ;)

What would be the benefit of having a Lazarus form designer for fpGUI compared to fpGUI's own UI Designer? Would such a form designer generate non-LCL code?

fpGUI's own UI Designer works quite different to Lazarus's TForm form designer in that it generates Object Pascal code instead of LFM files (this was my personal preference). I can also have multiple forms in a single unit, I can handle unknown properties (properties not registered with the form designer - I still need to implement RTTI automated property detection) etc... Make no mistake, the fpGUI UI Designer also has plenty of limitation, but it's more than capable enough for what I needed. It's quicker than designing a form layout by hand - that's until I get around to completing the MiG Layout Manager implementation.

The object inspector, property editors and component editors work with TComponent, so they already work with fpgui forms/controls.

Yeah, I made sure I keep to the TComponent style of design - simply because you don't know what you want to do in the future. Maybe I need form streaming somewhere down the line. ;-)

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Mattias Gaertner
to Graeme Geldenhuys
Show quoted text 18 lines
On Tue, May 5, 2009 at 1:36 PM, Mattias Gaertner wrote: > > No. > Only the widgetset independent LCL properties are set. The LCL > interfaces then reads/sets the widgetset properties. Thanks for explaining... > fpgui needs published properties when you want to edit components > visually. At the moment lazarus has designers for lcl TFrame, lcl > TForm and fcl TDataModule. Maybe someday you want to add a designer > for fpgui forms. hint, hint ;) What would be the benefit of having a Lazarus form designer for fpGUI compared to fpGUI's own UI Designer? Would such a form designer generate non-LCL code?

If you mean the pascal code: Yes.
The code generation works with TPersistent and TComponent.

If you don't like the lfm format, write a TReader/TWriter for your format.

fpGUI's own UI Designer works quite different to Lazarus's TForm form designer in that it generates Object Pascal code instead of LFM files (this was my personal preference).

Yes, this has the big advantage of better smart linking and that the compiler checks the properties.
It has the disadvantage that programmers will more likely try to edit it. Does the fgui designer keep user changes or will it rewrite the whole file every time?
I was thinking about writing a TReader/TWriter for pascal code, but it has low priority at the moment.

I can also have multiple forms in a single unit,

Multiple forms per unit makes error handling much more complicated. The one-form-per-unit concept is easy to understand and not a big limitation. Just like the java one-class-per-file limitation.

I can handle unknown properties (properties not registered with the form designer - I still need to implement RTTI automated property detection) etc...

Ehm, this sounds as if you don't use RTTI for streaming. How does the fgui designer work?

Show quoted text 5 lines
Make no mistake, the fpGUI UI Designer also has plenty of limitation, but it's more than capable enough for what I needed. It's quicker than designing a form layout by hand - that's until I get around to completing the MiG Layout Manager implementation.

:)

Show quoted text 6 lines
> The object inspector, property editors and component editors work > with TComponent, so they already work with fpgui forms/controls. Yeah, I made sure I keep to the TComponent style of design - simply because you don't know what you want to do in the future. Maybe I need form streaming somewhere down the line. ;-)

Mattias

Reply by email

Graeme Geldenhuys
to Mattias Gaertner
Mattias Gaertner wrote
If you don't like the lfm format, write a TReader/TWriter for your format.

I don't have issues with the LFM format, it's the extra file I have an issue with, plus a few others... see below.

Yes, this has the big advantage of better smart linking and that the compiler checks the properties.

Correct. Plus the following...

* If a component changes, a simple "search and replace" can fix all your code.

* One unit contains everything. No need for .pas, .lfm and .lrs files.

* Not all form / component properties in the form need to be published. I like my components and event handlers private and only surface what is truly needed. It's called good OO design. ;-)

* No need for an automated global form variable.

* I can define forms or dialogs in the Implementation section as well.

It has the disadvantage that programmers will more likely try to edit it.

Hence the reason for feature request #13514. Regions that can be folded by default when opened in the editor, so I can hide the automated GUI generation code. If the developer knows what he is doing, then by all means allow him or her to edit the code manually. Who hasn't edited a *.lfm or *.dfm file every now and again. ;-) Though Lazarus is a lot more tolerant when it comes to error handling compared to Delphi. :-)

http://bugs.freepascal.org/view.php?id=13514

Does the fgui designer keep user changes or will it rewrite the whole file every time?

I launch the fpGUI UI Designer from inside Lazarus IDE using the current editor file (setup via Tools menu). The designer keeps track of changes internally and only saves the file once, when the user selects "File > Save". Once your quite the form designer, you are return to Lazarus IDE, which that auto detects the file change and prompts for a reload. This works brilliantly. Lazarus IDE is great! The fpGUI UI Designer uses comment markers to know what to read and edit. Other code is not touched at all.

I was thinking about writing a TReader/TWriter for pascal code, but it has low priority at the moment.

Interesting. Where would it save that pascal code? An external file (maybe an include file) or directly inside the .pas file?

Multiple forms per unit makes error handling much more complicated. The one-form-per-unit concept is easy to understand and not a big limitation. Just like the java one-class-per-file limitation.

I limit myself to one form per unit as well (in my own projects). It only came in handy when I designed the fpGUI standard dialogs in the fpg_dialog.pas unit (similar to Lazarus's dialogs.pp unit).

Ehm, this sounds as if you don't use RTTI for streaming. How does the fgui designer work?

No, it doesn't for streaming. :-) I only use RTTI to detect if properties of components contain non-default values. So I can limit to generated code. The UI Designer is crude, but effective for it's needs. It's not designed to be a Delphi or Lazarus form designer - but it's still very effective.

Each component I want in the form designer registers itself, what properties must appear in the object inspector and optionally and property hint. The properties that are not registered are still accessible in the object inspector via the "unknown properties" memo. For the latter you can't see visual change, but they will be there at runtime. Each property type (boolean, integer etc.) has a class that knows how to read or write object pascal code.

There also exists property designer for more complex properties like Columns in a StringGrid.

And in case I haven't registered a visual component with the designer, you can always fall back to using the special TOtherWidget component. When placed on a form it pops up and asks for the name and base class. You can then use the "unknown properties" memo to fill in any extra property values. A nice "catch all" feature. ;-)

==================
  // ComboBox
  wc          := TVFDWidgetClass.Create(TfpgComboBox);
  wc.NameBase := 'ComboBox';
  wc.AddProperty('FontDesc', TPropertyFontDesc, 'The font used for
displaying the text');
  wc.AddProperty('Items', TPropertyStringList, '');
  wc.AddProperty('ParentShowHint', TPropertyBoolean, '');
  wc.AddProperty('ShowHint', TPropertyBoolean, '');
  wc.AddProperty('TabOrder', TPropertyInteger, 'The tab order');
  wc.WidgetIconName := 'vfd.combobox';
  RegisterVFDWidget(wc);
==================

So yes, I believe this is a very different design to what Lazarus IDE follows. Programming is great - a 101 ways to accomplish a similar task. :)

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Mattias Gaertner
to Graeme Geldenhuys
Show quoted text 17 lines
On Tue, May 5, 2009 at 2:30 PM, Mattias Gaertner wrote: > > If you don't like the lfm format, write a TReader/TWriter for your > format. I don't have issues with the LFM format, it's the extra file I have an issue with, plus a few others... see below. > Yes, this has the big advantage of better smart linking and that the > compiler checks the properties. Correct. Plus the following... * If a component changes, a simple "search and replace" can fix all your code.

This works in lfm too, doesn't it?

* One unit contains everything. No need for .pas, .lfm and .lrs files.

One unit to rule them all ...

I guess, the code observer will give a lot of hints for these files. ;)

Do you know that the lrs files can now be deleted? Lazarus can auto create them in the output directory.
And if you write a TReader/TWriter for pascal code, well, then lazarus will not need the lfm/lrs files. Although I recommend to put the code into an include file (see below).

* Not all form / component properties in the form need to be published. I like my components and event handlers private and only surface what is truly needed. It's called good OO design. ;-)

Can you give an example?

* No need for an automated global form variable.

Streaming does not need them.

* I can define forms or dialogs in the Implementation section as well.

That's even worse for error handling.

Show quoted text 7 lines
> It has the disadvantage that programmers will more likely try to > edit it. Hence the reason for feature request #13514. Regions that can be folded by default when opened in the editor, so I can hide the automated GUI generation code. If the developer knows what he is doing, then by all means allow him or her to edit the code manually.

Why write a sophisticated hiding when you can avoid all the problems and put it into a separate file? See below.

Who hasn't edited a *.lfm or *.dfm file every now and again. ;-)

Of course, that's why they are in text form.
But I fear if we support 'pascal forms' then the users will soon create bug reports that it does not support the whole 'pascal' syntax (e.g. expressions and constants, see below).

Though Lazarus is a lot more tolerant when it comes to error handling compared to Delphi. :-)

:)

Show quoted text 14 lines
http://bugs.freepascal.org/view.php?id=13514 > Does the fgui designer keep user changes or will it rewrite > the whole file every time? I launch the fpGUI UI Designer from inside Lazarus IDE using the current editor file (setup via Tools menu). The designer keeps track of changes internally and only saves the file once, when the user selects "File > Save". Once your quite the form designer, you are return to Lazarus IDE, which that auto detects the file change and prompts for a reload. This works brilliantly. Lazarus IDE is great! The fpGUI UI Designer uses comment markers to know what to read and edit. Other code is not it rewrites the whole sections. That avoids a lot of problems.

How much 'pascal' does the reader understand?
IFDEFs?
Expressions?
With statements? Nested with statements?
What about datamodules?
What about VFI?

Show quoted text 5 lines
> I was thinking about writing a TReader/TWriter for pascal code, but > it has low priority at the moment. Interesting. Where would it save that pascal code? An external file (maybe an include file) or directly inside the .pas file?

I vote for an include file. This way the reader/writer can work even if there are errors in the unit. Just imagine, you want to save your work and the IDE tells you have to first fix your code.

The include directive could be anywhere in the code.

Show quoted text 7 lines
> Multiple forms per unit makes error handling much more complicated. > The one-form-per-unit concept is easy to understand and not a big > limitation. Just like the java one-class-per-file limitation. I limit myself to one form per unit as well (in my own projects). It only came in handy when I designed the fpGUI standard dialogs in the fpg_dialog.pas unit (similar to Lazarus's dialogs.pp unit).

;)

Show quoted text 16 lines
> Ehm, this sounds as if you don't use RTTI for streaming. > How does the fgui designer work? No, it doesn't for streaming. :-) I only use RTTI to detect if properties of components contain non-default values. So I can limit to generated code. The UI Designer is crude, but effective for it's needs. It's not designed to be a Delphi or Lazarus form designer - but it's still very effective. Each component I want in the form designer registers itself, what properties must appear in the object inspector and optionally and property hint. The properties that are not registered are still accessible in the object inspector via the "unknown properties" memo. For the latter you can't see visual change, but they will be there at runtime. Each property type (boolean, integer etc.) has a class that knows how to read or write object pascal code.

This sounds as if you have reinvented RTTI ...

Show quoted text 8 lines
There also exists property designer for more complex properties like Columns in a StringGrid. And in case I haven't registered a visual component with the designer, you can always fall back to using the special TOtherWidget component. When placed on a form it pops up and asks for the name and base class. You can then use the "unknown properties" memo to fill in any extra property values. A nice "catch all" feature. ;-)

... and you reinvented property and components editors. I wonder what you would come up with if the world would stop wheeling for a year. :)

Show quoted text 17 lines
================== // ComboBox wc := TVFDWidgetClass.Create(TfpgComboBox); wc.NameBase := 'ComboBox'; wc.AddProperty('FontDesc', TPropertyFontDesc, 'The font used for displaying the text'); wc.AddProperty('Items', TPropertyStringList, ''); wc.AddProperty('ParentShowHint', TPropertyBoolean, ''); wc.AddProperty('ShowHint', TPropertyBoolean, ''); wc.AddProperty('TabOrder', TPropertyInteger, 'The tab order'); wc.WidgetIconName := 'vfd.combobox'; RegisterVFDWidget(wc); ================== So yes, I believe this is a very different design to what Lazarus IDE follows. Programming is great - a 101 ways to accomplish a similar task. :)

Well, it looks quite familiar to me:

  RegisterPropertyEditor(ClassTypeInfo(TCustomPage),
    TCustomNotebook, 'ActivePage', TNoteBookActiveControlPropertyEditor);

Mattias

Reply by email

Graeme Geldenhuys
to Mattias Gaertner
Mattias Gaertner wrote 5 lines
>  * If a component changes, a simple "search and replace" can fix all > your code. This works in lfm too, doesn't it?

I don't know, Delphi didn't. Does it search LFM's when you do "Find in Files" and select "all files in project"? I thought it doesn't. I meant search and replace all files in a directory or all files part of a project - not just the current file in the editor.

One unit to rule them all ... I guess, the code observer will give a lot of hints for these files. ;)

Oh yes it does. I tried to add exclude rules but gave up after a while. ;)

Do you know that the lrs files can now be deleted? Lazarus can auto create them in the output directory.

I read something like that a while back. Very handy.

Show quoted text 5 lines
>  * Not all form / component properties in the form need to be > published. I like my components and event handlers private and only > surface what is truly needed. It's called good OO design. ;-) Can you give an example?

It's just a pet peeve of mine when I see code as follows:

  lvar := EditUserForm.edName.Text;

Compared to:

  lvar := EdituserForm.UserName;

In the first example, I need to know the form instance name, component name and property name of that component.

Not to mention every label, panel, groupbox etc are visible to the world. I don't design a business object model like that (all properties default as published), so why must I design my forms like that?

Then again, the forms in my applications are completely empty (almost). They are pure visual display of business objects. If I want to access the Username, I rather do it via the business class and not the GUI layer. What would happen if I wanted to create a web version of that rich client application. No code in the GUI layer, means a much quicker port to a web version. But hey, now I'm drifting to another topic here.

Why write a sophisticated hiding when you can avoid all the problems and put it into a separate file? See below.

That's actually true... I got the idea from Visual Studio and C# which folds the auto-generated form designer code by default. But then Visual Studio does use include files. ;)

But then again, if you use include files you might need two of them. One for the Interface section and one for the Implementation section. Or roll them into one, but then you have to use some IFDEF trickery as follows...

Interface section...

{ This lets us use a single include file for both the Interface and
  Implementation sections. }
{$define read_interface}
{$undef read_implementation}
    {$IFDEF DUnit}
      {$I DUnitCompatibleInterface.inc}
    {$ENDIF DUnit}

Implementation section....

{$undef read_interface}
{$define read_implementation}
    {$IFDEF DUnit}
      {$I DUnitCompatibleInterface.inc}
    {$ENDIF DUnit}

.... and then the include file

============[ DUnitCompatibleInterface.inc ]============== {%MainUnit fpcunit.pp}

{$IFDEF read_interface}
    class procedure Check(pValue: boolean; pMessage: string = '');
{$ENDIF read_interface}
{$IFDEF read_implementation}
class procedure TAssert.Check(pValue: boolean; pMessage: string);
begin
  AssertTrue(pMessage, pValue);
end;
{$ENDIF read_implementation}
==============[ end ]==================

Also if you use a source code management system like SVN or Git, it means your form history is now split over multiple files and not a single file. Though I guess this is not a major issue really.

So it rewrites the whole sections. That avoids a lot of problems.

Yes.

How much 'pascal' does the reader understand? IFDEFs?

No

Expressions?

No, unless the property is one of the "unknown" properties, then it works fine.

With statements? Nested with statements?

Partial... The form designer generates with statements as a start - it looks neater and I don't have to debug that code (tooltip debugging doesn't support with statements).

Here is some sample code written by the form designer...

=====================================
procedure TSystemLocksForm.AfterCreate;
begin
   SystemLocksForm}
  Name := 'SystemLocksForm';
  SetPosition(310, 242, 397, 256);
  WindowTitle := 'System Locks';
  grdLocks := TfpgStringGrid.Create(self);
  with grdLocks do
  begin
    Name := 'grdLocks';
    SetPosition(8, 8, 381, 208);
    Anchors := [anLeft,anRight,anTop,anBottom];
    FontDesc := '#Grid';
    HeaderFontDesc := '#GridHeader';
    RowCount := 0;
    RowSelect := False;
    TabOrder := 0;
  end;
  btnRemove := TfpgButton.Create(self);
  with btnRemove do
  begin
    Name := 'btnRemove';
    SetPosition(8, 224, 92, 24);
    Anchors := [anLeft,anBottom];
    Text := 'btnRemove';
    FontDesc := '#Label1';
    Hint := '';
    ImageName := 'stdimg.remove';
    TabOrder := 1;
    OnClick := @btnDeleteClicked;
  end;

=====================================

What about datamodules?

I don't use them. I use tiOPF for database applications.

What about VFI?

No, but I do have forms that reuse frames (embedded forms).

Like I said, the fpGUI UI Designer is crude. It was simply to help me design forms visually because hand coding them took to long. It is a stop-gap until I can implement MiG Layout Manager. I have no intention to implement yet another full-featured form designer or IDE. Lazarus IDE already works perfectly for me.

I vote for an include file. This way the reader/writer can work even if there are errors in the unit. Just imagine, you want to save your work and the IDE tells you have to first fix your code.

True, but fpGUI UI Designer already ignores everything outside the comment markers. So if the rest of your code doesn't compile, you can still edit your forms.

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Mattias Gaertner
to Graeme Geldenhuys
Show quoted text 11 lines
On Tue, May 5, 2009 at 4:21 PM, Mattias Gaertner wrote: > >>  * If a component changes, a simple "search and replace" can fix >> all your code. > > This works in lfm too, doesn't it? I don't know, Delphi didn't. Does it search LFM's when you do "Find in Files" and select "all files in project"? I thought it doesn't. I meant search and replace all files in a directory or all files part of a project - not just the current file in the editor.

I use Find in files in a directory for that.

Show quoted text 7 lines
[...] > Why write a sophisticated hiding when you can avoid all the problems > and put it into a separate file? See below. That's actually true... I got the idea from Visual Studio and C# which folds the auto-generated form designer code by default. But then Visual Studio does use include files. ;)

And yet another reason for not using Visual Studio for inspiration.

Show quoted text 44 lines
But then again, if you use include files you might need two of them. One for the Interface section and one for the Implementation section. Or roll them into one, but then you have to use some IFDEF trickery as follows... Interface section... { This lets us use a single include file for both the Interface and Implementation sections. } {$define read_interface} {$undef read_implementation} {$IFDEF DUnit} {$I DUnitCompatibleInterface.inc} {$ENDIF DUnit} Implementation section.... {$undef read_interface} {$define read_implementation} {$IFDEF DUnit} {$I DUnitCompatibleInterface.inc} {$ENDIF DUnit} .... and then the include file ============[ DUnitCompatibleInterface.inc ]============== {%MainUnit fpcunit.pp} {$IFDEF read_interface} class procedure Check(pValue: boolean; pMessage: string = ''); {$ENDIF read_interface} {$IFDEF read_implementation} class procedure TAssert.Check(pValue: boolean; pMessage: string); begin AssertTrue(pMessage, pValue); end; {$ENDIF read_implementation} ==============[ end ]==================

There are ways to use a single include file. For example:

---------
{$I unit1.lfm}
constructor TForm1.Create(TheOwner: TComponent);
begin
  RegisterComponentInit(@InitTForm1,TForm1);
  inherited Create(TheOwner);
end;
--------
unit1.lfm:
procedure InitTForm1(AComponent: TComponent);
begin
  with AComponent as TForm1 do
  begin
    Name := 'Form1';
    Caption := ...
  end;
end;
---------

No interface, no intialization. Good for smart linking.

Also if you use a source code management system like SVN or Git, it means your form history is now split over multiple files and not a single file. Though I guess this is not a major issue really.

It's not even a minor issue.

Show quoted text 37 lines
[...] Here is some sample code written by the form designer... ===================================== procedure TSystemLocksForm.AfterCreate; begin SystemLocksForm} Name := 'SystemLocksForm'; SetPosition(310, 242, 397, 256); WindowTitle := 'System Locks'; grdLocks := TfpgStringGrid.Create(self); with grdLocks do begin Name := 'grdLocks'; SetPosition(8, 8, 381, 208); Anchors := [anLeft,anRight,anTop,anBottom]; FontDesc := '#Grid'; HeaderFontDesc := '#GridHeader'; RowCount := 0; RowSelect := False; TabOrder := 0; end; btnRemove := TfpgButton.Create(self); with btnRemove do begin Name := 'btnRemove'; SetPosition(8, 224, 92, 24); Anchors := [anLeft,anBottom]; Text := 'btnRemove'; FontDesc := '#Label1'; Hint := ''; ImageName := 'stdimg.remove'; TabOrder := 1; OnClick := @btnDeleteClicked; end;

How are images and other arbitrary data saved to the source?

Show quoted text 6 lines
===================================== > What about datamodules? I don't use them. I use tiOPF for database applications.
I meant links to other forms/datamodules/frames:
  DBText1.DataSource:=Form2.DataSource1;
Show quoted text 8 lines
[...] > I vote for an include file. This way the reader/writer can work > even if there are errors in the unit. Just imagine, you want to > save your work and the IDE tells you have to first fix your code. True, but fpGUI UI Designer already ignores everything outside the comment markers. So if the rest of your code doesn't compile, you can still edit your forms.

The 'markers' solution is nice for small things. But

*The lfm files can become quite large. Just put 100 components onto a form and add some glyphs. There will be several thousand lines of automatically generated code in your unit.

*When you now use Search/Replace, you will almost always run into trouble.

*Word completion will show you a lot of junk.

*when the IDE searches a component with the name 'Form1' it has to read in worst case all source files in the search path completely. This can take on a slow system a minute. With separate files it can just search for lfm files and read the first line.

Mattias

Reply by email

Graeme Geldenhuys
to Mattias Gaertner
Mattias Gaertner wrote 11 lines
There are ways to use a single include file. For example: --------- {$I unit1.lfm} constructor TForm1.Create(TheOwner: TComponent); begin RegisterComponentInit(@InitTForm1,TForm1); inherited Create(TheOwner); end;

Where is RegisterComponentInit() defined? I search all of Lazarus and FPC 2.2.5 and couldn't find a definition.

How are images and other arbitrary data saved to the source?

Currently they are declared as byte array constant. I have a small little program that convert images using bin2obj

*The lfm files can become quite large. Just put 100 components onto a form and add some glyphs. There will be several thousand lines of automatically generated code in your unit.

Thousand lines in a lfm file compared to a pas file. Doesn't matter to me much - yet.

*Word completion will show you a lot of junk. *when the IDE searches a component with the name 'Form1' it has to read in worst case all source files in the search path completely. This

I'll investigate these two further. But so far it hasn't been an issue for me.

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

Mattias Gaertner
to Graeme Geldenhuys
Show quoted text 17 lines
On Tue, May 5, 2009 at 6:08 PM, Mattias Gaertner wrote: > > There are ways to use a single include file. For example: > > --------- > {$I unit1.lfm} > > constructor TForm1.Create(TheOwner: TComponent); > begin > RegisterComponentInit(@InitTForm1,TForm1); > inherited Create(TheOwner); > end; Where is RegisterComponentInit() defined? I search all of Lazarus and FPC 2.2.5 and couldn't find a definition.

Sorry. It's only pseudo code. The functions do not exists yet. Just to demonstrate how it could look like.

> How are images and other arbitrary data saved to the source? Currently they are declared as byte array constant. I have a small little program that convert images using bin2obj

ok

Show quoted text 6 lines
> *The lfm files can become quite large. Just put 100 components onto > a form and add some glyphs. There will be several thousand lines of > automatically generated code in your unit. Thousand lines in a lfm file compared to a pas file. Doesn't matter to me much - yet.

Well, power users don't scroll, they fly via shortcuts.

Casual users use PgUp/PgDown.

> *Word completion will show you a lot of junk.
If we use numbers instead of strings to store the binary data, then
word completion and search/replace will work properly.
Show quoted text 6 lines
> *when the IDE searches a component with the name 'Form1' it has to > read in worst case all source files in the search path completely. > This I'll investigate these two further. But so far it hasn't been an issue for me.

I guess, the question is not, if the include file should be supported, the question is, if optionally lfm-in-source should be supported.

Mattias

Reply by email

Graeme Geldenhuys
to Mattias Gaertner
Mattias Gaertner wrote 6 lines
> > Where is RegisterComponentInit() defined? I search all of Lazarus and > FPC 2.2.5 and couldn't find a definition. Sorry. It's only pseudo code. The functions do not exists yet. Just to demonstrate how it could look like.

Oops, my bad. ;)

Well, power users don't scroll, they fly via shortcuts. Casual users use PgUp/PgDown.

That's putting it nicely. My business model units are all fairly big. PgUp/PgDn will just take to long. I the "procedure list" feature 1000's of times a day.

Umm, that would make for an interesting study. A statistics gathering feature for Lazarus IDE. See what is the most used keyboard shortcuts or features used. :) I believe Microsoft did that for the build-up to Office 2007.

Regards,
- Graeme -

_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://opensoft.homeip.net/fpgui/

Reply by email

David Emerson
to Graeme Geldenhuys: I'm looking at starting the conversion of fpGUI Toolkit's own Canvas and Image classes,…

Incidentally, while working with the TfpgColor type, I've come up with a rather sloppy, but (for the time being) usable solution. I keep a "fixme" comment in the code, because it may very well blow up in my face sometime.

type
  TfpgIntColor = TfpgColor;
  TfpgRecordColor = record
    blue, green, red, alpha : byte;  // order is important
    end;
operator := (c_in : TfpgRecordColor) : TfpgIntColor;
  var
    p : pointer;
  begin
    p := @c_in;
    result := TfpgIntColor (p^);
  end;
operator := (c_in : TfpgIntColor) : TfpgRecordColor
  var
    p : pointer;
  begin
    p := @c_in;
    result := TfpgRecordColor (p^);
  end;

~David.

Reply by email