6

I have several TPanel's on my main form that I show/hide depending on options a user selects. The problem is that at design time I have to constantly move them around to edit them. Is there an easier/better way that others handle this situation?

Christopher Chase
  • 2,840
  • 6
  • 36
  • 57
Mick
  • 13,248
  • 9
  • 69
  • 119

7 Answers7

10

If only one panel is visible at a time, then you might want to use a TPageControl to organize things. You can click the tabs to select which one to work on at design time, and then hide the tabs at run time, or hide the tabs all the time and select pages by setting the ActivePage property.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • 1
    +1 second this. It is by far a better way to organize controls. If you dont need the tab headings, you could create your own decendant, or use some already developed and set the Tabheight = 0 at runtime. – Simon Apr 27 '11 at 15:01
  • The downside of this, if I understand correctly, is that there will be more space in the container at runtime than at design time. So if you have a fixed size layout then it won't work well. Or have I got hold of the wrong end of the stick? – David Heffernan Apr 27 '11 at 15:18
  • Yes, @David, that's definitely a side effect of this. I don't consider it much of a problem, though, since resizable forms, anchors, and alignment have always made it irrelevant to whatever form I was designing. – Rob Kennedy Apr 27 '11 at 15:24
  • @Rob It all depends. Lots of my forms are non resizable forms. – David Heffernan Apr 27 '11 at 15:27
  • @david, you can hide the tabs at design time as well, and select the active page in the ActivePage propery. – Jørn E. Angeltveit Apr 27 '11 at 15:31
  • @Jørn how do you select a page? From the structure view? – David Heffernan Apr 27 '11 at 15:42
  • @david, use the activepage property in the object inspector. – Jørn E. Angeltveit Apr 27 '11 at 15:57
  • @Jørn Nice one. You should edit Rob's answer to include this option too. – David Heffernan Apr 27 '11 at 16:01
5

Use the Structure Pane to find the one you want, and then bring it to the front.

Structure pane
(source: embarcadero.com)

(But don't follow Embarcadero's example above; give your controls meaningful names so your controls are easier to tell apart.)

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • 1
    +1; I like this way mostly with fully overlapped controls. You simply select the item, right click and press O + F keys to bring the control to the front. –  Apr 27 '11 at 15:03
3

If the panels are stacked, you can reorder them by right-clicking on one and choosing Control->Bring to Front or Control->Send to Back from the context menu.

Ken White
  • 123,280
  • 14
  • 225
  • 444
3

A caveat I've found when doing Panel1.Visible:= false in runtime is that it messes up with layout.
The solution I've found works is to do:

//Design time
//-----------
Panel1.BevelOuter:= bvNone; //Make the panel look flat.

//Run time when hiding the panel
//------------------------------
procedure HidePanel(APanel: TPanel);
var
  H,W: integer;
begin
  case APanel.Align of 
    alTop, alBottom: begin
      APanel.Tag:= Max(APanel.Tag, APanel.Height);
      APanel.Height:= 1;
    end; {alTop, alBottom:}
    alLeft, alRight: begin
      APanel.Tag:= Max(APanel.Tag, APanel.Width);
      Panel1.Width:= 1;
    end; {alLeft, alRight:}
    alNone: begin
      H:= Max(APanel.Tag and $FFFF, APanel.Height);
      W:= Max((APanel.Tag shl 16) and $FFFF0000, APanel.Width shl 16);
      APanel.Tag:= (H or W);
      APanel.Height:= 1;
      APanel.Width:= 1;
    end; {alNone} 
    //alClient: do nothing
  end;
end;

//Run time when restoring the panel
//---------------------------------
procedure UnhidePanel(APanel: TPanel);
var
  H,W: integer;
begin
  case APanel.Align of 
    alTop, alBottom: begin
      APanel.Height:= APanel.Tag;  
      APanel.Tag:= 0;
    end; {alTop, alBottom:}
    alLeft, alRight: begin
      APanel.Width:= APanel.Tag;
      APanel.Tag:= 0;
    end; {alLeft, alRight:}
    alNone: begin
      H:= APanel.Tag and $FFFF;
      W:= APanel.Tag shr 16;
      APanel.Height:= H;
      APanel.Width:= W;
      APanel.Tag:= 0;
    end; {alNone}
    //alClient: do nothing
  end; {case}
end;

Simply hiding the panels can mess up the careful alignment you've constructed in Designtime
(esp. when using splitters).
This code prevents that from happening.
It really only works visually when the panel has no Bevels set and the panelcolor equals the color of the control it's on top of.

Johan
  • 74,508
  • 24
  • 191
  • 319
2

I select the Frame or Panel using the Object inspector Combo then on the main menu click Edit--> bring to front

(which is similar to opening the structure view)

Despatcher
  • 1,745
  • 12
  • 18
1

I also have used a TPageControl, and I kept the tabs visible at designtime. This gave me a designtime usability (via clicking on the tabs I want). Then at runtime, I hide the page tabs, and switch active pages on the page control using code, as a way of switching which pane is visible. However, this lead to some horrifically huge and complicated forms, which was in turn, the cause of many problems.

For your case, I would suggest that you consider refactoring each pane into its own Form or Frame. My preference would be to use Forms, not frames, and the reasons for this are well known and well documented in the Delphi world.

In my most well-structured applications, each "pane" (implementing using TForm, though, not TFrame) is separated into different units, and this solves both your design-time control problems, and also results in a more well structured overall solution.

While I think that the Structure Pane (someone else pointed out) is a great help to you, when you want to work with forms that are so complex that the regular designer visual tools start getting harder to use, it is also a good idea to consider breaking your form up, when you reach this point of "diminishing returns" of using the form Designer, on what is becoming one super-super complicated form.

Warren P
  • 65,725
  • 40
  • 181
  • 316
1

It is much easier to use frames for this purpose. I usually create them at runtime and add them to the form as needed. It also tends to make the code much more readable because you can use the same component names (e.g. ed_Name or l_Welcome) on different frames without having name clashes rather than having ed_NameForPanel1, ed_NameForPanel3 etc.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158