In our current project, we have a TPanel with a menu on every TTabSheet in a TPageControl element, and that panel is identical on most of them.

In our current project, we have a TPanel with a menu on every TTabSheet in a TPageControl element, and that panel is identical on most of them.

Is there a way to make it so that we are not having 15 different panels, but the exact same one on each of them? Not just identical looking, but literally the same.

As it stands, we have to duplicate it every time we make another, and that's really annoying, and it's bloating our code.

I'm trying to reduce the number of redundant members of our main form, and this seemed like an obvious start.

Comments

  1. Two offhand suggestions:

    1) Design/Create the panel once in one place (so it's visible at designtime for you to work on somewhere at least) , and then re-parent at runtime when and where required e.g.

    pnlMenu.Parent := MyPageControl.ActivePage;
    pnlMenu.BringToFront;   // ensure visible and in front as well 
    pnlMenu.Align := alClient;
    pnlMenu.Visible := True;  

    This is basically what you asked for and will cause literally the same panel to show up where required.  (I've used this approach in the past quite successfully.) 

    2) Create a frame and (re)-use the frame everywhere where required. This still causes separate instances to be created at runtime, but again you only have one copy in your source to maintain and also gives the benefit of still giving you the ability to see your interface at design time.

    ReplyDelete
  2. I was going to suggest a frame too - they're a great way to create a UI layout and the reuse that class (so writing the code once, and design / layout once) in several spots.  The situation you describe seems pretty much exactly the situation they are designed for :)

    ReplyDelete
  3. Use one panel and put it above the page control and give it the target on page change.

    ReplyDelete
  4. OK, I've now implemented the procedure that changes the Parent, and everything is swell.

    Except that the menu "flickers" when I change tabs now. I guess that's because the tab is changed and the form gets painted before the panel is moved.

    Is there a way make sure that repainting only occurs after tab change and update of panelMenu.Parent?

    ReplyDelete
  5. TPageControl.OnDrawTab (normally used to customise painting of tabs) should be sufficient for you to make the parent change and allow flicker-free operation. It fires when a tab is about to be drawn.

    ReplyDelete
  6. I tried that, and the code didn't fire :-/

    ReplyDelete
  7. Hmm maybe that comment was not quite good advice.

    Firstly, you need to set OwnerDraw to true on the pagecontrol for the event to fire.  

    But then you you have to then render the tab yourself. (Note, the tab is the bit at the top, not the contents of the tab page.)

    Which reminds me that this is probably bad advice as DrawTab refers to the tab itself, not the contents of the tab and so will likely be called sort of unpredictably.  

    Edit: (Removed code that wasn't quite right for now.)

    What event are you using currently?

    ReplyDelete
  8. If the contents of each tab are the same (UI-wise) don't use a page control - use a tab control instead.  It visually changes the tab and calls an event, but it doesn't have separate pages per tab - the idea is you implement that yourself in the event handler, much as you're doing already.

    No luck using a frame?

    ReplyDelete
  9. +1 to David Millington.

    Nevertheless to add, if you set the parent of the panel to be the pagecontrol (as opposed to a page in the pagecontrol) then you don't need any special handling anywhere -- the panel ends up showing up automatically inside all the pages in the page control.  Try putting e.g. 

      Panel1.Parent := PageControl1;

    in the form constructor to see what I mean.  (Not sure how good of an idea this is, seems a bit hackish, but it does provide what you want with no discernible flicker.)

    ReplyDelete
  10. David Millington The point is to convert it to a frame later, when this works as intended.

    ReplyDelete

Post a Comment