Recent

Author Topic: [solved] TTabControl / TPageControl  (Read 20245 times)

kapibara

  • Hero Member
  • *****
  • Posts: 656
[solved] TTabControl / TPageControl
« on: October 23, 2013, 10:59:47 pm »
I use the TPageControl to show different TFrames and their content.

But I also need to set the TabHeight to somewhat smaller and there is no such property. Delphi has it, and if I look into the laz sources for TPageControl there is a stub, but its commented out and not implemented. Maybe there is a good reason for that? Will it be implemented in the future? I checked the Delphi sources and it seems to be just a few lines of code.

The TTabControl has TabHeight, and I'm thinking of using that component instead. Any reason not to do this?
« Last Edit: October 28, 2013, 05:02:34 pm by kapibara »
Lazarus trunk / fpc 3.2.2 / Kubuntu 24.04 - 64 bit

wp

  • Hero Member
  • *****
  • Posts: 13328
Re: TTabControl / TPageControl
« Reply #1 on: October 23, 2013, 11:19:10 pm »
I think you cannot use TTabControl for your purpose because it does not have multiple pages, just one.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12011
  • Debugger - SynEdit - and more
    • wiki
Re: TTabControl / TPageControl
« Reply #2 on: October 24, 2013, 12:45:18 am »
It may not be possible cross platform... But then it could still be done for those platforms that work.

Probably a case of nobody had the time to do it.

----
One note: Please do *NOT* post a copy of the Delphi code, as a proposed solution!!

All our code is done "clean room". That is by a developer who does not know how it is implemented in Delphi. Any Developer who gets exposed to the "Delphi code" therefore can not fix this any more.

Avishai

  • Hero Member
  • *****
  • Posts: 1021
Re: TTabControl / TPageControl
« Reply #3 on: October 24, 2013, 01:39:22 am »
You can use TTabControl.  You just use the change of TabIndex as a trigger to execute other code.  It may be as simple as BringToFront or much more complicated code.
Lazarus Trunk / fpc 2.6.2 / Win32

kapibara

  • Hero Member
  • *****
  • Posts: 656
Re: TTabControl / TPageControl
« Reply #4 on: October 26, 2013, 02:15:55 am »
The TabControl question now boils down to:

How to hook an Object to a Tab?
Or just anyhow connect it to a TabIndex?

I thought TabControl.Tabs.Objects could be used for that. But I seem to get a Tabsheet back whatever I store in Objects.

Laz sources say this about Tabs, which I dont understand, but might be the reason:

FTabs: TStrings;  // this is a TTabControlNoteBookStrings

In the meantime I have put a TObjectList and a TTabControl together in a TFrame to make it look like a PageControl without borders. Works, but it would feel more natural to store the objects in the TabControl itself.

Also, is it possible to remove the border of the TabControl or PageControl, while the tabs remain normal?

@Martin_fr: Point taken about delphi code.
Lazarus trunk / fpc 3.2.2 / Kubuntu 24.04 - 64 bit

Avishai

  • Hero Member
  • *****
  • Posts: 1021
Re: TTabControl / TPageControl
« Reply #5 on: October 26, 2013, 09:02:09 am »
I'm almost sure that I am not understanding what you want to do, BUT:

I have prepared a small example.  Maybe it will help.  I have used TPanels in place of TFrames to keep it small so that I can upload it.

Note that I set TTabControl.Height to just enough to fully show the tabs.  The TPanels are borderless, but I colored them only so that you can see them change.
« Last Edit: October 26, 2013, 09:08:56 am by Avishai »
Lazarus Trunk / fpc 2.6.2 / Win32

kapibara

  • Hero Member
  • *****
  • Posts: 656
Re: TTabControl / TPageControl
« Reply #6 on: October 26, 2013, 09:29:33 pm »
Thanks for the clever example, Avishai:
- You slim down the TabControl Height to show only the Tabs,
- Then you attach the TPanels to the TabControl programmatically.
- Visible panels are switched using the TabControls OnChange event.

The extra thing with my problem is that I must create the panels at runtime and STORE them somewhere else than on the form. Where should I store them? I dont know in advance how many panels the user will create. So every panel has to be stored in a list of some sort, and linked to a tab.

I now have my app working, using a separate list that stores the dynamically created panels. But if the tabcontrol could store them instead then I wouldnt have to create and maintain this list.

TabControl.Tabs.Objects[TabIndex] doesnt seem to return stored objects like TListBox Items.Objects[ItemIndex] does.
Lazarus trunk / fpc 3.2.2 / Kubuntu 24.04 - 64 bit

jwhitten

  • Jr. Member
  • **
  • Posts: 61
Re: TTabControl / TPageControl
« Reply #7 on: October 27, 2013, 02:33:53 pm »
I would think you could use the TTabControl. Just for the heck of it I plopped one down on a form and started playing with it. You can set the TabHeight, the Font.Size, and the Height of the control which solves your size issue. You *can* add multiple tabs, I'm not sure I understand the previous response saying it only had one..?? And it looks like you could use the OnChanging event to control a separate Notebook or PageControl component. EDIT: I missed the part about the Frames, however, if you had your frames on tab pages within a page control or notebook, it would be as simple as flipping to the right page. If that can't work for you, you could always toggle the frame's visibility.

John
« Last Edit: October 27, 2013, 02:36:39 pm by jwhitten »
Some programmers seem Blaise about Pascal...

wp

  • Hero Member
  • *****
  • Posts: 13328
Re: TTabControl / TPageControl
« Reply #8 on: October 27, 2013, 04:00:51 pm »
Quote
You *can* add multiple tabs
Yes, you can, but there is only one page. The tabs have the same effect as a combobox, selecting a different tab still shows the same page. The only way to show multiple pages is by the way discussed by Avishai

jwhitten

  • Jr. Member
  • **
  • Posts: 61
Re: TTabControl / TPageControl
« Reply #9 on: October 27, 2013, 04:43:08 pm »
Yes agreed, I think I was saying essentially the same thing.
Some programmers seem Blaise about Pascal...

Avishai

  • Hero Member
  • *****
  • Posts: 1021
Re: TTabControl / TPageControl
« Reply #10 on: October 27, 2013, 04:56:35 pm »
Just a couple of small points.

A. He said that he wanted it to be borderless, and putting it on the *single* page would give him a border.

B.  My choice would also be to use TNoteBook, but he already had the Frames built.  TNoteBook wouldn't accomplish much.  I used TPanel only as a 'cheap and dirty' substitute for the Frames so I could keep the size small enough to upload.
Lazarus Trunk / fpc 2.6.2 / Win32

kapibara

  • Hero Member
  • *****
  • Posts: 656
Re: TTabControl / TPageControl
« Reply #11 on: October 27, 2013, 11:57:11 pm »
Hi wp, its true that the TabControl has only one page to show things in. But my thought and hope was that Tabs.Objects could be used just as with combobox Items.Objects for example. Then each TFrame could be associated with a Tab and the frame could be made visible with some code in the OnChange event. But whatever I store in the Tabs.Objects I dont get it back. And that puzzles me.

So now the question is simply: Is it possible to store a control in Tabs.Objects and have it back again?



Quote
You *can* add multiple tabs
Yes, you can, but there is only one page. The tabs have the same effect as a combobox, selecting a different tab still shows the same page. The only way to show multiple pages is by the way discussed by Avishai
Lazarus trunk / fpc 3.2.2 / Kubuntu 24.04 - 64 bit

wp

  • Hero Member
  • *****
  • Posts: 13328
Re: TTabControl / TPageControl
« Reply #12 on: October 28, 2013, 12:32:32 am »
The TabControl.Tabs is something like a stringlist. So your idea should work in principle. If nothing shows up you possibly forgot to assign the parent of the frames. Maybe this code works (not tested):

Code: [Select]
procedure TForm1.AddTab(ATabname: String; AFrame: TFrame);
begin
  TabControl.Tabs.AddObject(ATabName, AFrame);
end;

function TForm1.GetTabFrame(AIndex: Integer): TFrame;
begin
  Result := TFrame(TabControl.Tabs.Objects[AIndex]);
end;

procedure TForm1.TabControlChange(Sender: TObject);
{ This is called AFTER the frame is changed. TabIndex points to the new active tab. We
  need to insert and show the new frame. }
var
  frame: TFrame;
begin
  frame := GetTabFrame(TabControl.TabIndex);
  if frame <> nil then begin
    frame.Parent := TabControl;
    frame.Align := alClient;
    frame.Show;
  end;
end;

procedure TForm1.TabControlChanging(Sender: TObject; var AllowChange: Boolean);
{ This is BEFORE the active tab is changed. TabIndex points to the old active tab. We
  need to hide and remove the old frame from this tab. }
var
  frame: TFrame;
begin
  frame := GetTabFrame(TabControl.TabIndex);
  if frame <> nil then begin
    frame.Hide;
    frame.Parent := nil;
  end;
end;

kapibara

  • Hero Member
  • *****
  • Posts: 656
Re: TTabControl / TPageControl
« Reply #13 on: October 28, 2013, 03:50:01 am »
wp's code looks promising. I prepared and attached a test app.

If you run it, Click Add a few times and you see the Tabs coming up. But for some reason the frames are still not being returned when Tabs are switched.

At first there was a SIGSEGV. I then changed the cast from

  Result := TFrame(TabControl.Tabs.Objects[AIndex]);

to:

  Result := TabControl.Tabs.Objects[AIndex] as TFrame;

Laz then informed: Exception, Runerror 219

Looked it up and it means "Invalid typecast".
"Thrown when an invalid typecast is attempted
on a class using the as operator. This error is also thrown when
an object or class is typecast to an invalid class or object and
a virtual method of that class or object is called. This last
error is only detected if the -CR compiler option is used."

Question is why this happens? If it worked, TabControl could be used for effortlessly creating tabbed interfaces without borders, like in the demo app here. The frames could be shown aligned to client in the Form instead of in the TabControl.
Lazarus trunk / fpc 3.2.2 / Kubuntu 24.04 - 64 bit

wp

  • Hero Member
  • *****
  • Posts: 13328
Re: TTabControl / TPageControl
« Reply #14 on: October 28, 2013, 10:09:56 am »
I have to correct myself: the Tabs.Objects are not freely available. In TTabControl.Create the Tabs are created as TTabControlNotebookStrings (you already noted that in some postings above). The GetObject method of this class returns a TCustomPage item of the "Pages" of the Notebook. Therefore, when we call for the fame in our GetTabFrame function the Objects are occupied by a TCustomPage object, not our TFrame causing the observed crash due to type mis-match.

At the moment I don't see a simple way to store the frames in the Tabs.Objects of the TabControl. But what is the problem of using a separate list for the frames?

 

TinyPortal © 2005-2018