Jump to content

Centered Panels (Once Again)


Recommended Posts

Hello,
 
As I have seen, the centered panel topic is being discussed many times in the forum but it is still a confusion, at least for me.
 
Let me place this screenshot to show what I'm talking about first:
 
eoDMIOk.png
 
 
This is probably the most common Web layout nowadays. A panel at the centers which keeps its central position even if the browser window resizes.
 
How do we do this:
 
- Let's start with the Main Form: 
 
This is the MainForm
 

WindowState : wsMaximized
BorderStyle : bsNone

In the server module, we should have this line:
 

  MainFormDisplayMode = mfPage

I have placed an UniContainerPanel on the form. There is something we need to do with this panel first. We should clear all Anchors :
 

akTop: false
akLeft: false
akBottom: false
akRight: false

And there is a an UniImage in the ContainerPanel with the following properties:

Alignment : alClient
Autosize : true
Center : true
Stretch : false  (we don't want to distort the image)

And as a visual control example, I have placed a button in the ContainerPanel. There is nothing special with its properties. Just place it as you like. This button will show another form:

procedure TMainForm.UniBitBtn1Click(Sender: TObject);
begin
  subForm1.showmodal;
end;

 
Ok, these are enough to place our image which is going to be the background of our panel at the center of the form. But what happens if the browser window resizes?
Well, we need to dynamically adjust the ContainerPanel's position. Luckly Unigui has an event which triggers whenever the browser window resizes. It even reports the last width and height values. We will use this event to move the ContainerPanel to the window center. Calculation is simple. For the left value, just subtract panel's half width from window's half width. Then calculate the top value similarly.




procedure TMainForm.UniFormScreenResize(Sender: TObject; AWidth,  AHeight: Integer);
begin
  mainform.UniContainerPanel1.Left := (AWidth  - mainform.UniContainerPanel1.Width) div 2;
  mainform.UniContainerPanel1.Top  := (AHeight - mainform.UniContainerPanel1.Height) div 2;
end;

Everything is nice and clean so far. This works as we wish.
 
 
- Secondary Form: 
 
 
But what if we have more than one Form in our application? The UniFormScreenResize event is being fired for only MainForm. Secondary forms in the application will not receive this event. So even if we do everything explained above exactly the same for the secondary forms, the ContainerPanel won't keep it's central position.
 
 
 
There are some other tricks to do for secondary forms as well. First of all,  "MainFormDisplayMode = mfPage" this is just for the MainForm. So, if you want your secondary forms to be displayed borderless, you should change following properties and add following code to extEvents to remove border and rounded corners:
 
 

WindowState : wsMaximized
BorderStyle : bsNone

 //Removes border and round edges
extEvents - windows.afterRender:

Ext.get(sender.id).el.setStyle("padding", 0);
Ext.get(sender.id).el.setStyle("border-width", 0);
Ext.get(sender.id).el.setStyle("margin", 0);

We will replicate the same procedures for ContainerPanel and UniImage for the second page too. And when we click the button on the MainForm, we'll see the secondary form as we planned to see. This could be a login form, information form, control panel etc.
 

But the ContainerPanel on this form will not stay at the center of the window when we resize the browser window. It is probably because of the intent of the application form's is totally different by philosophy.
 
 
l5OLJen.png

 
 
Well I have tried to implement some tricks to fix this. For instance I thought, even if the secondary form is shown as Modal, the main form should be receiving ScreenResize events and since they are in the same window, I have tried to use main form's event for secondary form too. 
 

procedure TMainForm.UniFormScreenResize(Sender: TObject; AWidth,  AHeight: Integer);
begin
  mainform.UniContainerPanel1.Left := (AWidth  - mainform.UniContainerPanel1.Width) div 2;
  mainform.UniContainerPanel1.Top  := (AHeight - mainform.UniContainerPanel1.Height) div 2;
  if ( subForm1.visible ) then
  begin

    subForm1.UniContainerPanel1.Left := (AWidth  - mainform.UniContainerPanel1.Width) div 2;
    subForm1.UniContainerPanel1.Top := (AHeight - mainform.UniContainerPanel1.Height) div 2;
  end;
end;

 

 

 
well, actuall this works. But of course since we try to access subForm1 even before it is being created, it raises exceptions at the startup then it looks like working. I have tried to use an if condition like this:
 
 

if Assigned( subForm1 ) then
begin

   
end;

 
 
but this Assigned( TUniform) test raises and error:
 

[dcc32 Error] Main.pas(51): E2036 Variable required

Anyway, I'll update this post when I learn how to do this correctly.

 

 

In the attachment you can find the sample project (Unigui 0.99.0 + XE6) I have added TUnimemos to the forms as a reminder of properties to change.

centered_forms_.zip

 

 

 

Best

  • Upvote 1
Link to comment
Share on other sites

I have added a boolean variable to keep track of if the subform is already created. As unigui recommends, I have added this variable to mainmodue.

 

In mainmodule.pas :

 

  public
    { Public declarations }
    subform1_created : boolean;
  end;

 

Subform's OnCreate and OnClose events update this boolean variable :

 

procedure TsubForm1.UniFormClose(Sender: TObject; var Action: TCloseAction);
begin
  mainmodule.UniMainModule.subform1_created := false;
end;


procedure TsubForm1.UniFormCreate(Sender: TObject);
begin
  mainmodule.UniMainModule.subform1_created := true;
end;

And this is how MainForm's OnScreenResize event looks like:

procedure TMainForm.UniFormScreenResize(Sender: TObject; AWidth,
  AHeight: Integer);
begin
  mainform.UniContainerPanel1.Left := (AWidth  - mainform.UniContainerPanel1.Width) div 2;
  mainform.UniContainerPanel1.Top  := (AHeight - mainform.UniContainerPanel1.Height) div 2;


 // Check if we have already created the subform1
 if mainmodule.UniMainModule.subform1_created = true then
  if ( subForm1.visible ) then
  begin


     // Update the size of the subform1 with the new window dimensions
     subForm1.Width  := Awidth;
     subForm1.Height := AHeight;


     // Adjust containerpanel's position to the center of the window
     subForm1.UniContainerPanel1.Left := (AWidth  - mainform.UniContainerPanel1.Width) div 2;
     subForm1.UniContainerPanel1.Top  := (AHeight - mainform.UniContainerPanel1.Height) div 2;
  end;


end;

 

 

This is working fine except, when we create subForm with subForm.Showmodal,  the ContainerPanel will appear at designated position. Then if we rezise the browser window, it'll be placed at calculated location.

 

 

So I'm updating subForm's dimensions and ContainerPanel's coordinates using the mainform's dimensions. 

procedure TsubForm1.UniFormShow(Sender: TObject);
begin
     subForm1.Width  := mainform.width;
     subForm1.Height := mainform.height;


     subForm1.UniContainerPanel1.Left := (subForm1.Width  - mainform.UniContainerPanel1.Width) div 2;
     subForm1.UniContainerPanel1.Top  := (subForm1.Height - mainform.UniContainerPanel1.Height) div 2;


end;

 

 

 

Fmu9oAt.png

 

 

 

 

This is the updated project. Hope it helps someone out there.

 

centered_forms_v2.zip

  • Upvote 3
Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...