Lazarus

Programming => General => Topic started by: Ericktux on November 21, 2020, 10:31:39 pm

Title: pagecontrol tabsheet tabs button close
Post by: Ericktux on November 21, 2020, 10:31:39 pm
Hello friends, I just found this code on a Russian website where it is possible to place a close button (image) for the pagecontrol tabs.

here I share the code and example

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls,
  9.   LCLIntf, LCLType, StdCtrls;
  10.  
  11. type
  12.   {$IFDEF WINDOWS}
  13.   { TPageControl }
  14.   TPageControl = class(ComCtrls.TPageControl)
  15.   private
  16.     const btnSize = 10;
  17.  
  18.   protected
  19.     procedure MouseDown(Button: TMouseButton;
  20.       Shift: TShiftState; X, Y: Integer); override;
  21.     procedure PaintWindow(DC: HDC); override;
  22.   end;
  23.   {$ENDIF}
  24.  
  25.   { TForm1 }
  26.   TForm1 = class(TForm)
  27.     ImageList1: TImageList;
  28.     PageControl1: TPageControl;
  29.     TabSheet1: TTabSheet;
  30.     TabSheet2: TTabSheet;
  31.     TabSheet3: TTabSheet;
  32.   private
  33.  
  34.   public
  35.  
  36.   end;
  37.  
  38. var
  39.   Form1: TForm1;
  40.  
  41. implementation
  42.  
  43. {$R *.lfm}
  44.  
  45. {$IFDEF WINDOWS}
  46. procedure TPageControl.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  47.   Y: Integer);
  48. var R : TRect;
  49. begin
  50.   inherited MouseDown(Button, Shift, X, Y);
  51.   if Button = mbLeft then
  52.   begin
  53.     R := TabRect(ActivePageIndex);
  54.     if PtInRect(Classes.Rect(R.Right - btnSize - 4, R.Top + 2,
  55.                              R.Right - 4, R.Top + btnSize + 2),
  56.                 Classes.Point(X, Y))
  57.     then ActivePage.Free;
  58.   end;
  59. end;
  60.  
  61. procedure TPageControl.PaintWindow(DC: HDC);
  62. var
  63.   i : integer;
  64.   R : TRect;
  65.   bm : TBitmap;
  66. begin
  67.   inherited PaintWindow(DC);
  68.  
  69.   bm := TBitmap.Create;
  70.   try
  71.     bm.SetSize(16, 16);
  72.     Images.GetBitmap(0, bm);
  73.  
  74.     for i := 0 to Pred(PageCount) do
  75.     begin
  76.       R := TabRect(i);
  77.       // Код привязан к размеру ImageList-а = 16
  78.       StretchBlt(DC, R.Right - btnSize - 4, R.Top + 2,
  79.                  btnSize, btnSize, bm.Canvas.Handle, 0, 0, 16, 16, cmSrcCopy);
  80.     end;
  81.   finally
  82.     bm.Free;
  83.   end;
  84. end;
  85. {$ENDIF}
  86.  
  87. end.

It works perfect.   :)  :)
In turn, I ask for your help on how to improve it, for example, how can I place a button to add tabs, move tabs and change order, how to link a popupmenu, etc.

any help or improvement is welcome.



Title: Re: pagecontrol tabsheet tabs button close
Post by: lucamar on November 21, 2020, 11:13:42 pm
It's worth noting that this might only needed for Windows (as the IFDEFs show); Linux-gtk2 honors nboShowCloseButton in Options. What doesn't seem to work is nboShowAddButton :(

About the pop-up menu ... again, it's handled automatically (in Linux) and it shows by default a list of tabs, though you can add your own using the PopupMenu property and, IIRC, works.

Dragging tabs might be done through drag-drop events but I've never tried it yet :-[
Title: Re: pagecontrol tabsheet tabs button close
Post by: Ericktux on November 21, 2020, 11:27:51 pm
Thank you very much for your advice friend, actually I currently work with windows, I have tried gtk and qt to enable "nboShowCloseButton" but I would necessarily have to put all the dll that gtk or qt asks me, another aside that when I got all the dll I had to modify the original code because errors that did not occur before, anyway I will continue investigating, thanks for your advice.  :)
Title: Re: pagecontrol tabsheet tabs button close
Post by: winni on November 21, 2020, 11:35:00 pm
It's worth noting that this might only needed for Windows (as the IFDEFs show); Linux-gtk2 honors nboShowCloseButton in Options. What doesn't seem to work is nboShowAddButton :(


If you want a Win-only-solution then you might continue.

If you want a  platform independend solution: hands off.

If you activate the option "nboShowCloseButton" in gtk2 the close cross is shown in the tabs.
But you have to write your own code.

But "nboShowAddButton" has no effect  with gtk2.
So the closing with the help of nboShowCloseButton is a "Never-Come-Back-Airline".

You have to write  a lot of ifDefs to get it plattform-independend.

Proposal: don't use this two options. Write your own stuff.
Perhaps with two buttons (outside the Tabs).

Winni
Title: Re: pagecontrol tabsheet tabs button close
Post by: Ericktux on November 21, 2020, 11:43:26 pm
Thank you very much for your advice friends, the "nboShowAddButton" option I managed to activate it by installing the "customdrawn" package and modifying the widget, but for it to work I must use another pagecontrol that comes in the "customdrawn" tab which is slow to design and hangs when trying to select it, which is why I'm trying to use the original pagencontrol that comes in "common controls".

About using two buttons, one to close and the other to add more tabs, I have it as a last option, what I hope is that it resembles the tabs like a web browser.
Title: Re: pagecontrol tabsheet tabs button close
Post by: Ericktux on November 22, 2020, 04:46:36 am
hello friends, I just improved the project, now you can:
* add new tabs with a button +
* remove tabs except button +
* the last tab to close closes the program (as a browser)
* the close tab image is drawn, except for the button +
 
I share the code and the project, greetings  :)

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls,
  9.   LCLIntf, LCLType, StdCtrls;
  10.  
  11. type
  12.   {$IFDEF WINDOWS}
  13.   { TPageControl }
  14.   TPageControl = class(ComCtrls.TPageControl)
  15.   private
  16.     const btnSize = 10;
  17.  
  18.   protected
  19.     procedure MouseDown(Button: TMouseButton;
  20.       Shift: TShiftState; X, Y: Integer); override;
  21.     procedure PaintWindow(DC: HDC); override;
  22.   end;
  23.   {$ENDIF}
  24.  
  25.   { TForm1 }
  26.   TForm1 = class(TForm)
  27.     ImageList1: TImageList;
  28.     PageControl1: TPageControl;
  29.     TabSheet1: TTabSheet;
  30.     TabSheet2: TTabSheet;
  31.     TabSheet3: TTabSheet;
  32.     TabSheet4: TTabSheet;
  33.     TabSheet5: TTabSheet;
  34.     procedure PageControl1Change(Sender: TObject);
  35.   private
  36.  
  37.   public
  38.  
  39.   end;
  40.  
  41. var
  42.   Form1: TForm1;
  43.  
  44. implementation
  45.  
  46. {$R *.lfm}
  47.  
  48. { TForm1 }
  49.  
  50. procedure TForm1.PageControl1Change(Sender: TObject);
  51. var
  52.   TabSheet: TTabSheet;
  53.   ID_addtab: integer;
  54. begin
  55.     if trim(PageControl1.ActivePage.Caption)='+' then
  56.   begin
  57.   ID_addtab:=PageControl1.PageIndex;  // guardamos el ID de la pestaña +
  58.  
  59.   // creamos una nueva pestaña
  60.   TabSheet := TTabSheet.Create(PageControl1);
  61.   TabSheet.Caption := 'New Tab Sheet    ';
  62.   TabSheet.PageControl := PageControl1;
  63.  
  64.   PageControl1.TabIndex:=PageControl1.PageCount-1; // abrir pestaña ultima
  65.   pagecontrol1.Pages[ID_addtab].PageIndex := PageControl1.PageCount-1; // movemos la pestaña + hacia el final, pero abierto la ultima pestaña creada
  66.   end;
  67. end;
  68.  
  69. {$IFDEF WINDOWS}
  70. procedure TPageControl.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  71.   Y: Integer);
  72. var R : TRect;
  73. begin
  74.   inherited MouseDown(Button, Shift, X, Y);
  75.   if Button = mbLeft then
  76.   begin
  77.     if ActivePageIndex<>PageCount-1 then // aqui evitar cerrar la ultima pestaña
  78.     begin
  79.     R := TabRect(ActivePageIndex);
  80.     if PtInRect(Classes.Rect(R.Right - btnSize - 4, R.Top + 2,
  81.                              R.Right - 4, R.Top + btnSize + 2),
  82.                 Classes.Point(X, Y))
  83.     then
  84.     begin
  85.          if PageCount=2 then // si solo hay dos pestañas entoces cerrar form sino cerrar pestaña
  86.          begin
  87.               Form1.Close;
  88.          end
  89.               else
  90.                   begin
  91.                        if PageIndex=PageCount-2 then  // si estas en la penultima pestaña cerrar y foco a la nueva penultima pestaña
  92.                           begin
  93.                           ActivePage.Free;
  94.                           Repaint; // yo lo agregue para que repinte sino pone la x en +
  95.  
  96.                           PageIndex:=PageCount-2;
  97.                           end
  98.                              else  // de otra manera cerrar normal
  99.                              begin
  100.                              ActivePage.Free;
  101.                              Repaint; // yo lo agregue para que repinte sino pone la x en +
  102.                              end;
  103.                   end;
  104.     end;
  105.     end;
  106.   end;
  107. end;
  108.  
  109. procedure TPageControl.PaintWindow(DC: HDC);
  110. var
  111.   i : integer;
  112.   R : TRect;
  113.   bm : TBitmap;
  114. begin
  115.   inherited PaintWindow(DC);
  116.  
  117.   bm := TBitmap.Create;
  118.   try
  119.     bm.SetSize(16, 16);
  120.     Images.GetBitmap(0, bm);
  121.  
  122.     //for i := 0 to Pred(PageCount) do  // original
  123.     for i := 0 to Pred(PageCount-1) do  // pintar todo menos la ultima pestaña
  124.     begin
  125.       R := TabRect(i);
  126.       // Код привязан к размеру ImageList-а = 16
  127.       StretchBlt(DC, R.Right - btnSize - 4, R.Top + 2,
  128.                  btnSize, btnSize, bm.Canvas.Handle, 0, 0, 16, 16, cmSrcCopy);
  129.     end;
  130.   finally
  131.     bm.Free;
  132.   end;
  133. end;
  134. {$ENDIF}
  135.  
  136. end.


Title: Re: pagecontrol tabsheet tabs button close
Post by: lucamar on November 22, 2020, 06:56:47 am
If you activate the option "nboShowCloseButton" in gtk2 the close cross is shown in the tabs.
But you have to write your own code.

Well, of course. The program has no way of knowing what you might want to do unless you tell it: you might want to update a database, or save some file, or add a URL to a history list, or whatever, before freeing the tab sheet. That's why there is an OnCloseTabClicked event, for you to respond to it. By itself it's nothing more than a UI element, like a button without OnClick handler.

Quote
So the closing with the help of nboShowCloseButton is a "Never-Come-Back-Airline".

Well, depends on what you do in the cited event handler: you can, for example, save somewhere the state of all controls in the sheet and restore it later if needed. Adding a new tab (or "reopening" an old one) is fairly easy, yo just have to write some code. Which is what we, as programmers, do: write some code. ;)

Quote
Proposal: don't use this two options. Write your own stuff.
Perhaps with two buttons (outside the Tabs).

I rather prefer to make use of what is already there and, if and when needed, write workarounds for what is not and for platforms where it doesn't work. Saves a lot of headaches and hair-pulling :D

But to each his own, I guess ...
TinyPortal © 2005-2018