Sizing form to Control.Bounds.Bottom creates unexpected result - c#

I have a windows form, in which I have a Tab Control in which I have other controls.
Since the amount of controls is dynamic and I want to size the Form just right I have this piece of code:
int w = 0;
int h = 0;
foreach (Control x in Tab_Control.Controls)
{
if (x.Bounds.Right > w) w = x.Bounds.Right;
if (x.Bounds.Bottom > h) h = x.Bounds.Bottom;
}
Tab_Control.Size = new Size(w, h);
Form1.Size = new Size(w, h);
While this sets the form width just right its height crops two controls on the bottom. I thought it might be because the positions are relative to the parent control, but when I used "PointToScreen(Point.Empty)" to get some real coordinates I found the difference to be 21 pixels, which didn't help much.
So I am wondering why setting the form height to h ends up being too short.

The discrepancy is due to the size of the form's title bar.
You are calculating the size required by the controls correctly, but you are then setting the overall size of the window - which includes the title bar - to that height.
You'll need to add on the height of the title bar to the size you are calculating.
You can get the height of the title bar from the CaptionHeight property in System.Windows.Forms.SystemInformation
If that doesn't cover all of the discrepancy then look at the form's border thickness to see if you need to take that into account as well

Simply set the ClientSize property instead.
Better yet is to write no code at all. Set the form's AutoSize property to True, AutoSizeMode to GrowAndShrink. You surely prefer setting the Margin property on control(s) at the bottom and the right so there's a decent space between the control and the border.

Related

How to determine if control is outside of Form?

I am trying to determine if a dynamically added control is outside of the form.
At first, I thought it might be possible to calculate it by getting the height of the form, and location of the dynamically added control.
But I noticed that the Control.Location and Form.Height have "nothing" in common.
I don't think I really understand what the correlation is between Height and Location.
For example:
I thought that if your form has a height of 500, and I put the control at the bottom of the form, it should give the Location: X, 500 (X is width, not relevant here). But this is not correct, it shows me for example: X, 465. Am I missing something?
So I need to be able to recognize if the control is outside of the form, even if it's just one pixel.
I've found several similar questions here on SO, yet this does not really give me the answer that I need, unfortunately.
So, is there any way to do this? Is it possible to calculate it?
The Height of the form also includes the height of the title bar and borders.
You can use the ClientSize of the form:
From the documentation on MSDN:
The size of the client area of the form is the size of the form excluding the borders and the title bar. The client area of a form is the area within a form where controls can be placed. You can use this property to get the proper dimensions when performing graphics operations or when sizing and positioning controls on the form. To get the size of the entire form, use the Size property or use the individual properties Height and Width.
The position of the control is relative to its container, so (0,0) is the left upper corner inside the form.
I know this is an older thread, but you can try using this method:
public static bool IsOutofBounds(Form form, Control control)
{
int controlEnd_X = control.Location.X + control.ClientSize.Width;
int controlEnd_Y = control.Location.Y + control.ClientSize.Height;
if (form.ClientSize.Width < controlEnd_X || form.ClientSize.Height < controlEnd_Y)
{
return true;
}
else
{
return false;
}
}
It works for checking whether a control is out of bounds of its parent form.
You could use this code to check if controls is inside form:
var Inside = frm.ClientRectange.Intersect(ctrl.Bounds) == ctrl.Bounds;
the top left corner of a form is (0,0) lower right corner is (formHeight, fromWidth).
to check this place two text boxes on a form and write this code in the mouse move event to see how x and y change.
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
textBox1.Text = e.X.ToString();
textBox2.Text = e.Y.ToString();
}
Note that there is an difference between the number returned from the edge of the form and the size chosen by you. In my 500*500 form it is actually 460*483. the difference is always the same for any border style and any resolution.
To place a control on your form use the location structure in the form or use the top and left properties for the control; top = x, left = y.
Remember your offset from the actual height and width you measured and the dimension of the control.
To add a button with the following dimensions 80*30 in the bottom right corner I would right something like this:
button1.Location = new System.Drawing.Point(402, 430);
bottom left corner:
button1.Location = new System.Drawing.Point(0, 430);

GroupBox autosize

Take a GroupBox, put let say Label inside and then set AutoSizeMode = GrowAndShrink and AutoSize = true.
Two problems will arise:
There is a huge gap between Label and bottom of GroupBox (almost enough to fit another Label lol);
AutoSize doesn't respect the GroupBox.Text property.
Question is how to make GroupBox.AutoSize working properly? Properly means: minimum Width should be enough to fit GroupBox.Text, there should be no gaps below for unknown reason (it's not Margin, nor Padding and it looks pretty ugly).
I've tried to measure string length in OnPaint and setting MinimumSize right there. It works, but I have doubts about this, as if I would want to actually set MinimumSize later - it will be lost after repaint.
Update, here is screenshot:
You can get rid of the unwanted yellow space at the bottom by deriving a new class from GroupBox that adjusts the bottom edge a bit. In VB something like ...
Public Class BetterGroupBox
Inherits GroupBox
Public Overrides Function GetPreferredSize(ByVal proposedSize As Size) As Size
Dim ns = MyBase.GetPreferredSize(proposedSize)
Return New Size(ns.Width, ns.Height - 15)
End Function
End Class
It's simple that the location of your Label is fixed at some point other than (0,0), try this:
label1.Location = Point.Empty;
You may also want to try setting the Padding of your GroupBox to 0 for all (default is 3):
groupBox1.Padding = new Padding(0);
It seems as though the GroupBox control has a predefined padding of sorts when growing the control if AutoSize = true. That is, once a control (inside the GroupBox) gets within 20 pixels or so of the bottom of the GroupBox, the GroupBox starts growing. This causes a 20 pixel or so padding from the bottom of the bottom-most control to the bottom of the GroupBox (as highlighted in yellow by #Sinatr's attached image).
Based on my observations, the padding seems to be less when growing the Width of the GroupBox.
At any rate, you can do something like the following "get around" the issue:
public void MyFunction()
{
groupBox1.AutoSize = true;
// Do stuff (e.g., add controls to GroupBox)...
// Once all controls have been added to the GroupBox...
groupBox1.AutoSize = false;
// Add optional padding here if desired.
groupBox1.Height = myBottomMostControl.Bottom;
}

Panel with fixed size

I have a homework, where I need to create a winforms game using C#. I have the following components:
Panel subclass with custom paint event
Panel with default windows UI elements.
I want them to arrange like this:
Because I draw on the center panel manually, I want to set it's Width, and Height fixed, so the Form subclass, what will contain it, would show the whole panel.
I tried setting the size manually in the panel subclass:
Width = someFixedWidth;
Height = someFixedHeight;
Then adding it to the containing Form:
GamePanel panel = new GamePanel(...);
panel.Dock = DockStyle.Center;
this.AutoSize = true;
this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
this.Controlls.Add(panel);
Using this, I thought, that the form will respect the size of the Panel, but it just shrinks the window to so small, that nothing is visible, only the title.
So my question is, how would I be able to set the size of the GamePanel manually, and then dock it in the center of the form, so that the Form will respect the size I set, and doesn't makes it smaller/bigger?
The Dock property is used to define the behavior of the component during resizing Container (Form) The way you did the screen is not centralized but is resized according to the screen changes, the ideal is to use a method to reposition the control and set its size. See this:
SuspendLayout();
Width = someFixedWidth;
Height = someFixedHeight;
panel.Size = new Size(panelWidth, panelHeight);
panel.Location = new Point( ClientSize.Width / 2 - panelWidth / 2, ClientSize.Height / 2 - panelHeight / 2);
panel.Anchor = AnchorStyles.None;
panel.Dock = DockStyle.None;
ResumeLayout();
In my case, I edited minimum height/width of the panel and it worked.
I tried to edit the code which related to design but it was not recommended to rewrite auto-generated code.
Thank you.

Winforms autoscroll getting lost when controls resize

I have a user control that display a passenger car seating layout.
It simple draws several "SeatControl" in a matrix like fashion, depending on the passenger car size.
For better viewing, the main control resizes the "SeatControl" for fitting all space available, that means that the SeatControls will get bigger or smaller depending on the space available.
This works perfect.
But, when the client area gets too small, we avoid shrinking the controls too much, or they became deformed and impossible to read.
In this case we turn on auto scroll so the user can scroll around to see the entire layout.
But, if we start with a small screen (with scroll bar), maximize it (the scroll bar will hide and the seat controls increase size) and restore the window size back (scroll will come back and seat controls will shrink to minimum size), the scroll gets lost.
To make it clear, the same operation in images:
Maximize the window (only partial screen show to avoid a big image):
And restore it back (notice the scroll bar and the layout position on client area):
This resize is controlled by the code below:
private void FixSizes()
{
if (mModel == null)
return;
this.SuspendLayout();
Size clientSize = this.ClientSize;
Size minimumSize = new Size(SeatUserControl.MinimumDescentSize.Width, SeatUserControl.MinimumDescentSize.Height);
//Here we try to find the best size for the seat user control to fit all the client area
Size controlSize = new Size(
Math.Max(clientSize.Width / mModel.Length, minimumSize.Width),
Math.Max(clientSize.Height / mModel.Width, minimumSize.Height)
);
AutoScrollMinSize = new Size(controlSize.Width * mModel.Length, controlSize.Height * mModel.Width);
this.SetDisplayRectLocation(0, 0);
for (int row = 0; row < mModel.Width; ++row)
{
for (int col = 0; col < mModel.Length; ++col)
{
Control control = this.Controls[(row * mModel.Length) + col];
control.Location = new Point(col * controlSize.Width, row * controlSize.Height);
control.Size = controlSize;
}
}
this.ResumeLayout();
}
And this method is simple called by the OnClientSizeChanged method:
protected override void OnClientSizeChanged(EventArgs e)
{
base.OnClientSizeChanged(e);
this.FixSizes();
}
I was able to determine that if I keep the SeatControl on a fixed size, the problem goes away, but the output is not so good, as we prefer the SeatControl to use the maximum space available.
So it looks like I am missing or forgetting to do something with autoscroll settings so it does not get lost. Any ideas?
Solution from comments:
Assuming you are using a parent container of some sort, such as a panel, or something that would restrict the maximized size of the SeatControl, use dock "Fill" (the center one). This will auto adjust the scrollbar for you in regards to the control.
For future readers, the result would look like this when using a Dock: Fill property:
Note the scrollbar that was auto-generated due the gridview control being larger than its parent container.

What's the best way to design a full screen application in C#?

I want to know the best way to design a full screen form, like positioning controls in a way that they won't get messed up if the user's resolution is different.
This is my fullscreen code:
int w = Screen.PrimaryScreen.Bounds.Width;
int h = Screen.PrimaryScreen.Bounds.Height;
this.Location = new Point(0, 0);
this.Size = new Size(w, h);
Anchors and Docks.
The Anchor will bind the control. The Dock property sets how it expands/shrinks.
So if you assign a button anchor to "Top, left" it's size and position stay locked on those sides. So if you dragged the Form window wider, the object would expand to towards the right and towards the bottom.

Categories

Resources