Recent

Author Topic: [SOLVED] Component visibility  (Read 1572 times)

pcurtis

  • Hero Member
  • *****
  • Posts: 951
[SOLVED] Component visibility
« on: October 05, 2020, 11:24:52 am »
Hi All,

I have made a simple component, two buttons. I have introduced a property to make the left button visible (boolean). At runtime it works perfectly. The problem how do I make it work at design time?

Code: Pascal  [Select][+][-]
  1. unit MyTest;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls;
  9.  
  10. type
  11.   TTestControl = class(TCustomControl)
  12.   private
  13.     function GetLeftVisible : boolean;
  14.     procedure SetLeftVisible(Value : boolean);
  15.   protected
  16.  
  17.   public
  18.     constructor Create(AOwner : TComponent); override;
  19.   published
  20.     fbtnLEFT : TButton;
  21.     fbtnRIGHT : TButton;
  22.     property LeftVisible : boolean read GetLeftVisible write SetLeftVisible;
  23.  
  24.   end;
  25.  
  26. procedure Register;
  27.  
  28. implementation
  29.  
  30. constructor TTestControl.Create(AOwner : TComponent);
  31. begin
  32.   inherited Create(AOwner);
  33.   Width := 200;
  34.   Height := 50;
  35.   Width  := 200;
  36.  
  37. fbtnLEFT := TButton.Create(self);
  38. with fbtnLEFT do
  39.   begin
  40.     Align := alLeft;
  41.     Parent := self;
  42.   end;
  43.  
  44. fbtnRIGHT := TButton.Create(self);
  45. with fbtnRIGHT do
  46.   begin
  47.     Align := alRight;
  48.     Parent := self;
  49.   end;
  50. end;
  51.  
  52. function TTestControl.GetLeftVisible : boolean;
  53. begin
  54.   result := fbtnLEFT.Visible;
  55. end;
  56.  
  57. procedure TTestControl.SetLeftVisible(Value : boolean);
  58. begin
  59.   If GetLeftVisible <> Value then
  60.     begin
  61.       fbtnLEFT.Visible := Value;
  62.     end;
  63. end;
  64.  
  65. procedure Register;
  66. begin
  67.   RegisterComponents('Misc',[TTestControl]);
  68. end;
  69.  
  70. end.
  71.  

Thanks in advance.
« Last Edit: October 06, 2020, 06:54:51 am by pcurtis »
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

Sieben

  • Sr. Member
  • ****
  • Posts: 310
Re: Component visability
« Reply #1 on: October 05, 2020, 12:16:11 pm »
Always visible? Just try and set visibility of any control on your form to false at designtime.
« Last Edit: October 05, 2020, 12:35:22 pm by Sieben »
Lazarus 2.2.0, FPC 3.2.2, .deb install on Ubuntu Xenial 32 / Gtk2 / Unity7

Handoko

  • Hero Member
  • *****
  • Posts: 5149
  • My goal: build my own game engine using Lazarus
Re: Component visability
« Reply #2 on: October 05, 2020, 12:32:47 pm »
You should not use TButton. Because TButton will not totally not visible on design time even you set the Visible = False. Because it needs to be 'always' visible to allow user to edit it on design time.

You might using workaround to force the button to become hidden on design time. But that will be too much work.

The better solution is don't use TButton but to do the painting yourself.

Here I modified your code:

Code: Pascal  [Select][+][-]
  1. unit MyTest;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Controls, Graphics;
  9.  
  10. type
  11.  
  12.   { TTestControl }
  13.  
  14.   TTestControl = class(TCustomControl)
  15.   private
  16.     FLeftVisible: Boolean;
  17.     FRightVisible: Boolean;
  18.     function GetLeftVisible : Boolean;
  19.     procedure SetLeftVisible(Value : Boolean);
  20.     function GetRightVisible : Boolean;
  21.     procedure SetRightVisible(Value : Boolean);
  22.   public
  23.     procedure Paint; override;
  24.     constructor Create(AOwner : TComponent); override;
  25.   published
  26.     property LeftVisible : Boolean read GetLeftVisible write SetLeftVisible;
  27.     property RightVisible : Boolean read GetRightVisible write SetRightVisible;
  28.   end;
  29.  
  30. procedure Register;
  31.  
  32. implementation
  33.  
  34. constructor TTestControl.Create(AOwner : TComponent);
  35. begin
  36.   inherited Create(AOwner);
  37.   Width         := 200;
  38.   Height        := 50;
  39.   FLeftVisible  := True;
  40.   FRightVisible := True;
  41. end;
  42.  
  43. function TTestControl.GetLeftVisible: Boolean;
  44. begin
  45.   Result := FLeftVisible;
  46. end;
  47.  
  48. procedure TTestControl.SetLeftVisible(Value: Boolean);
  49. begin
  50.   if GetLeftVisible <> Value then
  51.     FLeftVisible := Value;
  52.   Invalidate;
  53. end;
  54.  
  55. function TTestControl.GetRightVisible: Boolean;
  56. begin
  57.   Result := FRightVisible;
  58. end;
  59.  
  60. procedure TTestControl.SetRightVisible(Value: Boolean);
  61. begin
  62.   if GetRightVisible <> Value then
  63.     FRightVisible := Value;
  64.   Invalidate;
  65. end;
  66.  
  67. procedure TTestControl.Paint;
  68. begin
  69.   case csDesigning in ComponentState of
  70.   True:
  71.     begin
  72.       // Draw the left one
  73.       if FLeftVisible then
  74.         Canvas.Pen.Color := clGreen
  75.       else
  76.         Canvas.Pen.Color := clNone;
  77.       Canvas.Rectangle(5, 5, 95, 45);
  78.       // Draw the right one
  79.       if FRightVisible then
  80.         Canvas.Pen.Color := clGreen
  81.       else
  82.         Canvas.Pen.Color := clNone;
  83.       Canvas.Rectangle(105, 5, 195, 45);
  84.     end;
  85.   False:
  86.     begin
  87.       // Draw the left one
  88.       if FLeftVisible then
  89.         Canvas.Brush.Color := clGreen
  90.       else
  91.         Canvas.Brush.Color := clDefault;
  92.       Canvas.Rectangle(5, 5, 95, 45);
  93.       // Draw the right one
  94.       if FRightVisible then
  95.         Canvas.Brush.Color := clGreen
  96.       else
  97.         Canvas.Brush.Color := clDefault;
  98.       Canvas.Rectangle(105, 5, 195, 45);
  99.     end;
  100.   end
  101. end;
  102.  
  103. procedure Register;
  104. begin
  105.   RegisterComponents('Misc',[TTestControl]);
  106. end;
  107.  
  108. end.

- Line #23 is the Paint routine, which you need to provide your code.
- Line #69 csDesigning in ComponentState is for detecting design time or runtime

If you run the code then you will know, result is a bit different if the visible = false on runtime and design time. That is the trick. If TButton detects it is on design time, it still draws the button.

Run the code and modify the Paint procedure. You can draw anything you can imagine inside the procedure. It handles how enable/disable, visible/not_visible, shape, color effects and all the things about the appearance of the component.
« Last Edit: October 05, 2020, 12:50:37 pm by Handoko »

pcurtis

  • Hero Member
  • *****
  • Posts: 951
Re: Component visability
« Reply #3 on: October 05, 2020, 12:37:48 pm »
Thamks Handoko i'll have a look.
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

Handoko

  • Hero Member
  • *****
  • Posts: 5149
  • My goal: build my own game engine using Lazarus
Re: Component visability
« Reply #4 on: October 05, 2020, 12:40:19 pm »
Component writing is fun. I wrote many components for my own use. But as self taught programmer, I might not follow the common rules. But at least, all the components I wrote work as I want how they behave.

pcurtis

  • Hero Member
  • *****
  • Posts: 951
Re: Component visability
« Reply #5 on: October 05, 2020, 02:11:19 pm »
@Handoko -

Quote
You should not use TButton. Because TButton will not totally not visible on design time even you set the Visible = False. Because it needs to be 'always' visible to allow user to edit it on design time.

Does this rule apply to all/most visual components?
« Last Edit: October 05, 2020, 02:16:44 pm by pcurtis »
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

Handoko

  • Hero Member
  • *****
  • Posts: 5149
  • My goal: build my own game engine using Lazarus
Re: Component visability
« Reply #6 on: October 05, 2020, 02:31:43 pm »
I believe they make the Visible property to behave so. It will only hide the component at runtime.

You can make the test. For example, drop a TLabel on the form and set it Visible := False. The label still can be seen at design time. Try it on TCheckBox, TEdit, etc .. they all can be seen.

Because most or maybe all visual components behave like that, we should follow them. But you can make your own-created component less visible by using dim color if you want.

wp

  • Hero Member
  • *****
  • Posts: 11906
Re: Component visability
« Reply #7 on: October 05, 2020, 02:38:05 pm »
Well you CAN use TButton here, but you must live with the consequences, namely that the button does not disappear at designtime when you set it's Visible to false.

The alternative is to mimic the buttons in your component by defining two mouse-sensitive areas. You can even write the Paint procedure such that these pseudo-button look exactly like native button (by calling ThemeServices for drawing). But then you must also override the mouse methods, MouseMove, MouseUp and MouseDown. An (incomoletely untested) example is appended-

So, the decision is yours.

Code: Pascal  [Select][+][-]
  1. unit MyTest;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Controls, Graphics;
  9.  
  10. type
  11.  
  12.   { TTestControl }
  13.  
  14.   TTestControl = class(TCustomControl)
  15.   private
  16.     FLeftVisible: Boolean;
  17.     FRightVisible: Boolean;
  18.     FLeftRect: TRect;
  19.     FRightRect: TRect;
  20.     FMouseDown: Boolean;
  21.     function GetLeftVisible : Boolean;
  22.     procedure SetLeftVisible(Value : Boolean);
  23.     function GetRightVisible : Boolean;
  24.     procedure SetRightVisible(Value : Boolean);
  25.   protected
  26.     procedure MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
  27.     procedure MouseMove(Shift: TShiftState; X,Y: Integer); override;
  28.     procedure MouseUp(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
  29.   public
  30.     procedure Paint; override;
  31.     constructor Create(AOwner : TComponent); override;
  32.   published
  33.     property LeftVisible : Boolean read GetLeftVisible write SetLeftVisible;
  34.     property RightVisible : Boolean read GetRightVisible write SetRightVisible;
  35.   end;
  36.  
  37. procedure Register;
  38.  
  39. implementation
  40.  
  41. uses
  42.   types, Themes;
  43.  
  44. constructor TTestControl.Create(AOwner : TComponent);
  45. begin
  46.   inherited Create(AOwner);
  47.   Width         := 200;
  48.   Height        := 50;
  49.   FLeftVisible  := True;
  50.   FRightVisible := True;
  51.   FLeftRect := Rect(5, 5, 95, 45);
  52.   FRightRect := Rect(105, 5, 195, 45);
  53. end;
  54.  
  55. function TTestControl.GetLeftVisible: Boolean;
  56. begin
  57.   Result := FLeftVisible;
  58. end;
  59.  
  60. procedure TTestControl.SetLeftVisible(Value: Boolean);
  61. begin
  62.   if GetLeftVisible <> Value then
  63.     FLeftVisible := Value;
  64.   Invalidate;
  65. end;
  66.  
  67. function TTestControl.GetRightVisible: Boolean;
  68. begin
  69.   Result := FRightVisible;
  70. end;
  71.  
  72. procedure TTestControl.SetRightVisible(Value: Boolean);
  73. begin
  74.   if GetRightVisible <> Value then
  75.     FRightVisible := Value;
  76.   Invalidate;
  77. end;
  78.  
  79. procedure TTestControl.Paint;
  80. var
  81.   state: TThemedButton;
  82.   details: TThemedElementDetails;
  83.   P: TPoint;
  84. begin
  85.   P := ScreenToClient(Mouse.CursorPos);
  86.  
  87.   if FLeftVisible then begin
  88.     state := tbPushButtonNormal;
  89.     if PtInRect(FLeftRect, P) then
  90.     begin
  91.       if FMouseDown then
  92.         state := tbPushButtonPressed
  93.       else
  94.         state := tbPushButtonHot;
  95.     end;
  96.     details := ThemeServices.GetElementDetails(state);
  97.     ThemeServices.DrawElement(Canvas.Handle, details, FLeftRect);
  98.   end else
  99.   begin
  100.     state := tbPushButtonNormal;
  101.     if PtInRect(FRightRect, P) then
  102.     begin
  103.       if FMouseDown then
  104.         state := tbPushButtonPressed
  105.       else
  106.         state := tbPushButtonHot;
  107.     end;
  108.     details := ThemeServices.GetElementDetails(state);
  109.     ThemeServices.DrawElement(Canvas.Handle, details, FRightRect);
  110.   end;
  111. end;
  112.  
  113. procedure TTestControl.MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y:Integer);
  114. begin
  115.   inherited;
  116.   FMouseDown := true;
  117.   Invalidate;
  118. end;
  119.  
  120. procedure TTestControl.MouseMove(Shift: TShiftState; X,Y: Integer);
  121. begin
  122.   inherited;
  123.   Invalidate;
  124. end;
  125.  
  126. procedure TTestControl.MouseUp(Button: TMouseButton; Shift:TShiftState; X,Y:Integer);
  127. begin
  128.   FMouseDown := false;
  129.   Invalidate;
  130. end;
  131.  
  132. procedure Register;
  133. begin
  134.   RegisterComponents('Misc',[TTestControl]);
  135. end;
  136.  
  137. end.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Component visability
« Reply #8 on: October 05, 2020, 04:34:59 pm »
Another possibility is to look how it's done in TButtonPanel, which is similar, in this respect, to what you're doing.

It's probably done by re-creating/freeing the butttons as needed but I haven't looked into it and it might be using some other way about which I know nothing ... :-[
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

wp

  • Hero Member
  • *****
  • Posts: 11906
Re: Component visability
« Reply #9 on: October 05, 2020, 04:57:26 pm »
Good idea. There seems to be a special ControlStyle (csNoDesignVisible) which allows hiding a control at design time. This is a snippet of TButtonPanel:

Code: Pascal  [Select][+][-]
  1.      if btn in FShowButtons
  2.     then begin
  3.       if csDesigning in ComponentState then
  4.         aButton.ControlStyle:=aButton.ControlStyle-[csNoDesignVisible];
  5.       aButton.Visible := True;
  6.     end
  7.     else begin
  8.       if csDesigning in ComponentState then
  9.         aButton.ControlStyle:=aButton.ControlStyle+[csNoDesignVisible];
  10.       aButton.Visible := False;
  11.     end;
  12.   end;
       

pcurtis

  • Hero Member
  • *****
  • Posts: 951
Re: Component visability
« Reply #10 on: October 05, 2020, 05:07:09 pm »
Looks good. How would I add this to my openingg code?
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Component visability
« Reply #11 on: October 05, 2020, 05:20:43 pm »
Looks good. How would I add this to my openingg code?

This should be enough:

Code: Pascal  [Select][+][-]
  1. procedure TTestControl.SetLeftVisible(Value : boolean);
  2. begin
  3.   If GetLeftVisible <> Value then
  4.   begin
  5.     if csDesigning in ComponentState then
  6.       if Value then
  7.         fbtnLEFT.ControlStyle := fbtnLEFT.ControlStyle-[csNoDesignVisible]
  8.       else
  9.         fbtnLEFT.ControlStyle := fbtnLEFT.ControlStyle+[csNoDesignVisible];
  10.     fbtnLEFT.Visible := Value;
  11.   end;
  12. end;
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

pcurtis

  • Hero Member
  • *****
  • Posts: 951
Re: Component visability
« Reply #12 on: October 05, 2020, 05:49:43 pm »
@lucamar - Job done. Thanks.
Windows 10 20H2
Laz 2.2.0
FPC 3.2.2

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: [SOLVED] Component visability
« Reply #13 on: October 05, 2020, 06:52:56 pm »
Glad to help ;)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

 

TinyPortal © 2005-2018