Recent

Author Topic: Borderless and colored frame around control?  (Read 3659 times)

kapibara

  • Hero Member
  • *****
  • Posts: 610
Borderless and colored frame around control?
« on: October 17, 2018, 03:20:20 am »
How to show a borderless colored frame around a control like TPanel?

For example, lets say there are two panels in a form and you click one of them. The clicked panel should show a frame around itself so the user can see which panel is selected.
« Last Edit: October 17, 2018, 03:23:06 am by kapibara »
Lazarus trunk / fpc 3.2.2 / Kubuntu 22.04 - 64 bit

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Borderless and colored frame around control?
« Reply #1 on: October 17, 2018, 03:34:58 am »
Easiest way may be using a TShape, adapting it manually to the panel's external border. Not, perhaps, the most elegant solution but it should work.

Attached, a quick & dirty example.
« Last Edit: October 17, 2018, 04:13:19 am by lucamar »
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.

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: Borderless and colored frame around control?
« Reply #2 on: October 17, 2018, 04:27:28 am »
I guess the easiest way is to change the background color of the panel.  :D

Yeah, not really a colored frame... I know...  :P
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Borderless and colored frame around control?
« Reply #3 on: October 17, 2018, 04:42:13 am »
I guess the easiest way is to change the background color of the panel.  :D

The problem with that is that it may not be possible, what with themed windows and controls, etc. I found that, to my profound surprise, some time ago with the background of TEdit, which some of my Delphi programs changed precisely for the same reason that the OP wants his colored frame.  :)
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.

RAW

  • Hero Member
  • *****
  • Posts: 868
Re: Borderless and colored frame around control?
« Reply #4 on: October 17, 2018, 05:08:01 am »
Yes, this THEME-thing is something I forget from time to time. I always use a classic theme ...  ;)
Windows 7 Pro (x64 Sp1) & Windows XP Pro (x86 Sp3).

mse

  • Sr. Member
  • ****
  • Posts: 286
Re: Borderless and colored frame around control?
« Reply #5 on: October 17, 2018, 08:43:06 am »
How to show a borderless colored frame around a control like TPanel?
I am sorry that it will not help you but from time to time I dare to commemorate what Free Pascal and MSEide+MSEgui can do for you.
In MSEgui one would set <widget>.frame.colorframeactive to cl_blue, colorframe to cl_transparent and framewidth to 1.
Please see
https://mseide-msegui.sourceforge.io/pics/focusframe.mpeg

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Borderless and colored frame around control?
« Reply #6 on: October 17, 2018, 09:36:26 am »
How to show a borderless colored frame around a control like TPanel?
Just paint it - see code below.

For example, lets say there are two panels in a form and you click one of them. The clicked panel should show a frame around itself so the user can see which panel is selected.
Add a method which determines that one of these panels is the (grand...)parent of the focused control:
Code: Pascal  [Select][+][-]
  1. function TForm1.IsParentOfActiveControl(APanel: TPanel): Boolean;
  2. var
  3.   C: TControl;
  4. begin
  5.   C := ActiveControl.Parent;
  6.   while Assigned(C) do begin
  7.     if C = APanel then exit(true);
  8.     C := C.Parent;
  9.   end;
  10.   Result := false;
  11. end;
In the OnPaint event of the panels check for the active control and set the border pen accordingly. Paint a rectangle around the panel outline with transparent brush:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Panel1Paint(Sender: TObject);
  2. var
  3.   panel: TPanel;
  4. begin
  5.   panel := Sender as TPanel;
  6.   panel.Canvas.Brush.Style := bsClear;
  7.   if IsParentOfActiveControl(panel) then begin
  8.     panel.Canvas.Pen.Color := clRed;
  9.     panel.Canvas.Pen.style := psSolid;
  10.   end else
  11.     panel.Canvas.Pen.Style := psClear;
  12.   panel.Canvas.Pen.Width := 3;
  13.   panel.Canvas.Rectangle(1, 1, panel.Width-1, panel.Height-1);
  14. end;  
Finally establish a handler for the OnEnter/OnExit events of the panels to force repainting when focus changes:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.PanelEnter(Sender: TObject);
  2. begin
  3.   (Sender as TPanel).Invalidate;
  4. end;
  5.  
  6. procedure TForm1.PanelExit(Sender: TObject);
  7. begin
  8.   (Sender as TPanel).Invalidate;
  9. end;
Important note: While the new panel border may be clearly visible to you it may not be visible to all of your users because of theming. Suppose you draw the focused border in black, and the user has selected a black theme, black on black...
« Last Edit: October 17, 2018, 09:38:01 am by wp »

kapibara

  • Hero Member
  • *****
  • Posts: 610
Re: Borderless and colored frame around control?
« Reply #7 on: October 30, 2018, 11:12:47 pm »
Thanks to all for the suggestions!

@wp: Just paint it was a really neat solution. I think the TPanels also need an OnClick event that calls SetFocus. Panel.OnEnter was not triggered otherwise.

Does anyone know why the upper left corner of the blue rectangle is not completely square?

My working test:

Code: Pascal  [Select][+][-]
  1. unit uMain;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Panel0: TPanel;
  16.     Panel1: TPanel;
  17.     Panel2: TPanel;
  18.     Splitter1: TSplitter;
  19.     procedure PanelClick(Sender: TObject);
  20.     procedure PanelExit(Sender: TObject);
  21.     procedure PanelEnter(Sender: TObject);
  22.     procedure PanelPaint(Sender: TObject);
  23.   private
  24.  
  25.   public
  26.     CurrentPanel: TPanel;
  27.   end;
  28.  
  29. var
  30.   Form1: TForm1;
  31.  
  32. implementation
  33.  
  34. {$R *.lfm}
  35.  
  36. { TForm1 }
  37.  
  38. procedure TForm1.PanelClick(Sender: TObject);
  39. begin
  40.   (Sender as TPanel).SetFocus;
  41. end;
  42.  
  43. procedure TForm1.PanelEnter(Sender: TObject);
  44. begin
  45.   CurrentPanel:= Sender as TPanel;
  46.   (Sender as TPanel).Invalidate;
  47. end;
  48.  
  49. procedure TForm1.PanelExit(Sender: TObject);
  50. begin
  51.   (Sender as TPanel).Invalidate;
  52. end;
  53.  
  54. procedure TForm1.PanelPaint(Sender: TObject);
  55. var
  56.   panel: TPanel;
  57. begin
  58.   panel := Sender as TPanel;
  59.   panel.Canvas.Brush.Style := bsClear;
  60.  
  61.   if panel = CurrentPanel then
  62.   begin
  63.     panel.Canvas.Pen.Color := clBlue;
  64.     panel.Canvas.Pen.style := psSolid;
  65.   end
  66.   else
  67.   begin
  68.     panel.Canvas.Pen.Color := clDefault;
  69.     panel.Canvas.Pen.Style := psClear;
  70.   end;
  71.  
  72.   panel.Canvas.Pen.Width := 2;
  73.   panel.Canvas.Rectangle(1, 1, panel.Width-1, panel.Height-1);
  74. end;
  75.  
  76. end.
« Last Edit: October 31, 2018, 02:15:47 am by kapibara »
Lazarus trunk / fpc 3.2.2 / Kubuntu 22.04 - 64 bit

 

TinyPortal © 2005-2018