Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

DELPHI: Resizing and dividing panels?

2,255 views
Skip to first unread message

Russell Turpin

unread,
Apr 14, 1995, 3:00:00 AM4/14/95
to

-*-----
Let me pose two, related "how-to" problems.


PROBLEM 1: a Panel that the user can resize at run-time, i.e.,
one wants the Panel to act like a resizable subwindow. (Ignore
any springs or bars controlling alignment of the panel in the
window or w.r.t. other components in the window.)

This is a problem because none of the components that I have
investigated support dynamically changing the size of the
component as a whole. Clearly, one could do a lot of programming
to capture mouse events on the containing window and then
updating the component's size, but this is not the idea in
Delphi.


PROBLEM 2: to divide a Panel into two horizontally adjacent
subpanels so that the user, at run-time, can move the
division between the two, making one smaller and the other
larger.

Idea the first: Dividing panels is easy. Place two subpanels,
one aligned left, the other aligned client. This doesn't work,
because changing panel size is difficult. (See Problem 1.)

Idea the second: Use the Header component. This doesn't work
because I want to put other components in the subpanels, and
align those components to the subpanels. Headers aren't
containers the way panels are. (Again, I can always program
it by hand, but this is NOT the idea of Delphi.)

Idea the third: Put a small Header just below or just above the
two Panels and link their sizes to its sections. This works and
is easy (the way it OUGHT to be in Delphi). But it is not the
interface I want. I do not want a control header above or below.
I want the user to be able to resize the panel division by
moving, very naturally, the border between subpanels. (Why
should I waste precious interface real estate for a user function
that should be tacit and automatic rather than explicit and
intrusive?)


Discussion welcome.

Russell


--
"Why does our innate subjective spacing of qualities accord so well with the
functionally relevant groupings in nature as to make our inductions come out
right? ... Creatures inveterately wrong in their inductions have a pathetic
but praiseworthy tendency to die before reproducing." -- W. V. O. Quine

Brian Badger

unread,
Apr 15, 1995, 3:00:00 AM4/15/95
to
tur...@cs.utexas.edu (Russell Turpin) wrote:
>
> PROBLEM 1: a Panel that the user can resize at run-time, i.e.,
> one wants the Panel to act like a resizable subwindow. (Ignore
> any springs or bars controlling alignment of the panel in the
> window or w.r.t. other components in the window.)

Solution 1:
Use drag and drop.
Make the panel you want to resize be a automatic d&d object, and
then set the dragover events for all the surrounding objects (and
itself, assuming you want to be able to shrink ;-) to resize
the panel according to the x and y parameters of the event.

>
> PROBLEM 2: to divide a Panel into two horizontally adjacent
> subpanels so that the user, at run-time, can move the
> division between the two, making one smaller and the other
> larger.

Solution 2: Use solution 1, and make the other panel align client.

By changing the drag and drob events, you can make it do anything
"visually" that you want.

I struggled with this one myself, but it isn't too hard. I was
able to have 2 panels, a picture an editfield and a listbox all
resizing dynamically in 2 dimensions with almost no coding. Here's a
bonus solution: try putting panels within panels and doing the same
thing. Or panels within panels within panels.

Brian "4 days of Delphi" Badger


Anders Ohlsson

unread,
Apr 16, 1995, 3:00:00 AM4/16/95
to
In article <3mm3gv$i...@peaches.cs.utexas.edu> tur...@cs.utexas.edu (Russell Turpin) writes:
>
>PROBLEM 1: a Panel that the user can resize at run-time, i.e.,
>one wants the Panel to act like a resizable subwindow. (Ignore
>any springs or bars controlling alignment of the panel in the
>window or w.r.t. other components in the window.)

I didn't check this one out, but read on...

One idea could be to put one panel inside another with the outside
one behaving as a resize frame like I do below...

>PROBLEM 2: to divide a Panel into two horizontally adjacent
>subpanels so that the user, at run-time, can move the
>division between the two, making one smaller and the other
>larger.

A very easy way is to do like this:

Drop a panel on your form. This panel will not be visible but only
act as a container for your subpanels.

Now, drop three new panels inside the first one. Let's call these
panels LEFT, MIDDLE and RIGHT.

Then, align LEFT to the left, MIDDLE to the left (i.e. immediately
to the right of LEFT) and lastly RIGHT to client.

Then, set the width of MIDDLE to 1 pixel and set the cursor of
MIDDLE to crHSplit.

All you have to do now is to write four lines of code...

In MIDDLE's MouseDown event handler set a flag:

Resizing := True;

In MIDDLE's MouseUp event handler unset it:

Resizing := False;

And now for some magic...

In MIDDLE's MouseMove event handler:

if Resizing then
LEFT.Width := LEFT.Width+X;

It's as simple as that... It may not look too good, but it does
the job and I did it in five minutes...

/Anders

-----------------------------------------------------------------------------
! The Windoze program you want is at http://www.it.kth.se/~ao/yacpu20.zip !
! !
! Anders Ohlsson - a...@sto.foa.se - http://www.it.kth.se/~ao !
-----------------------------------------------------------------------------

Russell Turpin

unread,
Apr 16, 1995, 3:00:00 AM4/16/95
to
-*-----

In article <3mqnd8$k...@news.kth.se>, Anders Ohlsson <a...@spirou.e.kth.se> wrote:
> Now, drop three new panels inside the first one. Let's call these
> panels LEFT, MIDDLE and RIGHT.
> Then, align LEFT to the left, MIDDLE to the left (i.e. immediately
> to the right of LEFT) and lastly RIGHT to client.
> Then, set the width of MIDDLE to 1 pixel and set the cursor of
> MIDDLE to crHSplit.

Very good! I should have thought of this myself (but didn't).

> All you have to do now is to write four lines of code...
> In MIDDLE's MouseDown event handler set a flag:

I tried a variation, making MIDDLE auto drag-drop and putting
the resize code into the drop events of LEFT and RIGHT. The
advantage to this is that the app doesn't have to do resizing
on the fly; the disadvantage is that it burdens the LEFT and
RIGHT drag-drop events.

In any case, this works very well. Kudos to Anders Ohlsson.
(Though I would still like springs and rods. Until you've used
this system, you cannot 1imagine how easy it is to control how
complex visual objects resize with components growing and
shrinking as desired, some things in alignment, some not, and
just the right limits on how much the user can move things at
run-time.)

Frank Heyne

unread,
Apr 17, 1995, 3:00:00 AM4/17/95
to
On: 16.04.95
wrote: Anders Ohlsson - a...@spirou.e.kth.se

> Drop a panel on your form. This panel will not be visible but only
> act as a container for your subpanels.
>

> Now, drop three new panels inside the first one. Let's call these
> panels LEFT, MIDDLE and RIGHT.
>
> Then, align LEFT to the left, MIDDLE to the left (i.e. immediately
> to the right of LEFT) and lastly RIGHT to client.
>
> Then, set the width of MIDDLE to 1 pixel and set the cursor of
> MIDDLE to crHSplit.
>

> All you have to do now is to write four lines of code...
>
> In MIDDLE's MouseDown event handler set a flag:
>

> Resizing := True;
>
> In MIDDLE's MouseUp event handler unset it:
>
> Resizing := False;
>
> And now for some magic...
>
> In MIDDLE's MouseMove event handler:
>
> if Resizing then
> LEFT.Width := LEFT.Width+X;
>
> It's as simple as that... It may not look too good, but it does
> the job and I did it in five minutes...

Right, it pretty good works :-)

There is only one problem: If the cursor leaves the window and the mouse
gets up outside the window you can not resize the panels anymore :-(
This problem occures only if the cursor leaves the window on its right
border.
Any ideas?

Frank


Dion Kurczek

unread,
Apr 17, 1995, 3:00:00 AM4/17/95
to
Here's the source code for a resizable panel. Give the panel an align
property of alClient, throw some controls on it, and watch them resize
at run time when you resize the form. There is some code that prohibits
resizing during design time, but this can be taken out. This may not be
perfect, because I threw it together in a few minutes, but it's worked
for me so far.

unit Elastic;

interface

uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, ExtCtrls;

type
TElasticPanel = class( TPanel )
private
FHorz, FVert: boolean;
nOldWidth, nOldHeight: integer;
bResized: boolean;
protected
procedure WMSize( var message: TWMSize ); message WM_SIZE;
public
nCount: integer;
constructor Create( AOwner: TComponent ); override;
published
property ElasticHorizontal: boolean read FHorz write FHorz default
TRUE;
property ElasticVertical: boolean read FVert write FVert default
TRUE;
end;

procedure Register;

implementation

constructor TElasticPanel.Create( AOwner: TComponent );
begin
inherited Create( AOwner );
FHorz := TRUE;
FVert := TRUE;
nOldWidth := Width;
nOldHeight := Height;
bResized := FALSE;
end;

procedure TElasticPanel.WMSize( var message: TWMSize );
var
bResize: boolean;
xRatio: real;
i: integer;
ctl: TWinControl;
begin
Inc( nCount );
if Align = alNone then
bResize := TRUE
else
bResize := bResized;
if not ( csDesigning in ComponentState ) and bResize then
begin
if FHorz then
begin
xRatio := Width / nOldWidth;
for i := 0 to ControlCount - 1 do
begin
ctl := TWinControl( Controls[i] );
ctl.Left := Round( ctl.Left * xRatio );
ctl.Width := Round( ctl.Width * xRatio );
end;
end;
if FVert then
begin
xRatio := Height / nOldHeight;
for i := 0 to ControlCount - 1 do
begin
ctl := TWinControl( Controls[i] );
ctl.Top := Round( ctl.Top * xRatio );
ctl.Height := Round( ctl.Height * xRatio );
end;
end;
end
else
begin
nOldWidth := Width;
nOldHeight := Height;
end;
bResized := TRUE;
nOldWidth := Width;
nOldHeight := Height;
end;

procedure Register;
begin
RegisterComponents('Additional', [TElasticPanel]);
end;

end.


0 new messages