How to add scrollbar to groupbox? C# 4.0 - c#

So... did someone know how to make it?...
In a panel is easy, because we can set the "AutoScroll" property, to true... but groupbox doesn't have it.
Anyways... exists some way for it?, thanks in advance ;-).

Quite simple... Add a panel inside a group box.

Declare Group box object and Panel object which will contain the scroll bar by default and some of my Check box objects;I read somewhere that Group box's don't have scroll bar for aesthetic reasons(i hope it's not true, why not let the user make that call). Solution is simple, once you know that you will create a panel that will lay on top of your group box just to get your scroll bar.
private System.Windows.Forms.GroupBox grpDR;//GROUPBOX IN WHICH PANEL WILL OVERLAY
private System.Windows.Forms.Panel grpScrlDR;//PANEL WHICH WILL HAVE SCROLL BAR AND CONTAIN CHECK BOXES
private System.Windows.Forms.CheckBox chkDr2;
private System.Windows.Forms.CheckBox chkDr1;
private void InitializeComponent()
{
this.grpScrlDR = new System.Windows.Forms.Panel();
this.chkDr2 = new System.Windows.Forms.CheckBox();
this.chkDr1 = new System.Windows.Forms.CheckBox();
this.grpDR = new System.Windows.Forms.GroupBox();
this.grpScrlDR.SuspendLayout();
this.grpDR.SuspendLayout();
//
// grpScrlDR
// PANEL DETAILS ADDING CHECKBOX CONTROLS AND ENABLING AUTO SCROLL
this.grpScrlDR.AutoScroll = true;
this.grpScrlDR.Controls.Add(this.chkDr2);
this.grpScrlDR.Controls.Add(this.chkDr1);
this.grpScrlDR.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpScrlDR.Location = new System.Drawing.Point(5, 336);
this.grpScrlDR.Name = "grpScrlDR";
this.grpScrlDR.Size = new System.Drawing.Size(175, 230);
this.grpScrlDR.TabIndex = 0;
//
// chkDr2
//
this.chkDr2.AutoSize = true;`
this.chkDr2.Location = new System.Drawing.Point(13, 45);
this.chkDr2.Name = "chkDr2";
this.chkDr2.Size = new System.Drawing.Size(54, 20);
this.chkDr2.TabIndex = 1;
this.chkDr2.Text = "Permit#";
this.chkDr2.UseVisualStyleBackColor = true;
this.chkDr2.CheckedChanged += new System.EventHandler(this.chkDr_CheckedChanged);
//
// chkDr1
//
this.chkDr1.AutoSize = true;
this.chkDr1.Checked = true;
this.chkDr1.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkDr1.Location = new System.Drawing.Point(13, 22);
this.chkDr1.Name = "chkDr1";
this.chkDr1.Size = new System.Drawing.Size(54, 20);
this.chkDr1.TabIndex = 0;
this.chkDr1.Text = "Account";
this.chkDr1.UseVisualStyleBackColor = true;
this.chkDr1.CheckedChanged += new System.EventHandler(this.chkDr_CheckedChanged);
//
// grpDR
// GROUP BOX DETAILS - GROUP BOX IS ADDING PANEL CONTROLS
this.grpDR.Controls.Add(this.grpScrlDR);
this.grpDR.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.grpDR.Location = new System.Drawing.Point(5, 336);
this.grpDR.Name = "grpDR";
this.grpDR.Size = new System.Drawing.Size(175, 230);
this.grpDR.TabIndex = 46;
this.grpDR.TabStop = false;
this.grpDR.Text = "Report by";
this.grpDR.Visible = false;
}

The GroupBox cannot display a scroll bar. If you need a control similar to a GroupBox that can contain a scroll bar, see the Panel control
Read This Article - Find (The GroupBox cannot display a scroll bar) Text

If you need to add a panel inside of your GroupBox, Dock a Panel inside of the GroupBox and set the AutoScroll property on the docked Panel to true. You can then place any controls you need inside of the GroupBox on the Panel, which will scroll when necessary.
If you don't like the way that looks as you stated above, then you have two possible options:
There may be a way to hack (more like "abuse" in this situation) the GroupBox control by making calls into the native Win32 API to add a scrollbar. I rarely use native calls on managed controls, but I've done this in situations where, for instance, I need to disable the scroll bar on a ListView as ListView doesn't expose this property. Below I expose the native Win32 function for use in C#, just call SetScrollBarVisible to enable or disable the scrollbar as needed from your code (I have not tested this on a GroupBox):
If aesthetics is THAT important to you (not a bad thing, user experience is greatly underappreciated in many areas of the application development world) and adding a scroll bar to the GroupBox doesn't work/look good to you, you will need to find another solution. I would imagine the best solution would be to make your own control from the ground up that meets your expectations (or modify the scrollbar itself, no idea how to do this), though this is can be a lot more work than it might be worth.
Here is how I expose and call the Win32 function SetScrollBar from my C# code (sorry, the DllImport won't format as a code block for some reason):
[DllImport ("user32")]
private static extern long ShowScrollBar (long hwnd , long wBar, long bShow);
long SB_HORZ = 0;
long SB_VERT = 1;
long SB_BOTH = 3;
private static void SetScrollBarVisible (Control control, long sb, bool enable)
{
if (control != null) return;
if (enable)
ShowScrollBar(control.Handle.ToInt64(), sb, 1);
else
ShowScrollBar(control.Handle.ToInt64(), sb, 0);
}

To do this you would have to add 1 panel to the groupbox and set the autoscroll property to true.
Then you would add a second panel which would be large then the first panel.
On this second panel (StringPanel in the beleow code) you would add controls.
System.Windows.Forms.GroupBox StringsGroup;
System.Windows.Forms.Panel StingPanel;
System.Windows.Forms.Panel StringPanel2;
StringsGroup = new System.Windows.Forms.GroupBox();
StingPanel = new System.Windows.Forms.Panel();
StringPanel2 = new System.Windows.Forms.Panel();
//Add your controls to StringPanel
StingPanel.Size = new System.Drawing.Size(300, 800);
StringPanel2.Size = new System.Drawing.Size(325, 345);
StringPanel2.AutoScroll = true;
this.StringPanel2.Controls.Add(StingPanel);
this.StringsGroup.Controls.Add(this.StringPanel2);

Horizontal Scroll Bar Tip
If you have a panel where all the controls contained within it are anchored to the top (so that they are centered) you will never see the horizontal scroll bar. You need to have at least one control that is anchored left & top that disappears when the panel is too small to show it in order for the horizontal scroll bar to appear. I put a label with hidden text on the panel to accomplish this.
This little tidbit took me quite a while to discover! Hope it's helpful!

If you dont want scrollbars, but want your GroupBox to grow, you can edit these below properties from the Layout section as shown below.
AutoSize = true;
AutoSizeMode = GrowOnly;

Related

How to reproduce a forum/twitter-like UI on Winform

As a classic forum, threads and replys are displayed on a page, with dark and light and dark and light backcolor.
I am trying to write a client of a forum on windows using winform. It is
At first, I have tried this way:
Add a big panel to the form, let's call it the PARENT PANEL.
Add small panels to the big panel like this:
panel1.Visible = false;
for (int i=0; i<5;i++)
{
Panel parent = new Panel();
parent.Height = 800;
Random ra = new Random();
TextBox p = new TextBox();
p.Text = "fehsuifq";
p.Multiline = true;
p.WordWrap = true;
p.Dock = DockStyle.Fill;
parent.BackColor = Color.FromArgb(ra.Next(0, 254), ra.Next(0, 254), ra.Next(0, 254));
p.BorderStyle = BorderStyle.None;
p.ReadOnly = true;
p.TabStop = false;
p.BackColor = this.BackColor;
parent.Controls.Add(p);
parent.Dock = DockStyle.Top;
panel1.Controls.Add(parent);
}
panel1.Visible = true;
Every panel(tenicially, a control) displays a thread's text and images and others details(like authors or avator).
Images are not shown until it is clicked.
when the image is clicked, it is loaded and the controls's height will change as result.
The PARENT PANEL will contains hundreds of these controls since there will be so many threads. It is and have to be scrollable, obviously.
But if I put a textbox in the control, the scroll wheel no longer work on the PARENT PANEL.If I use a label, it is not selectable.
I think this way can't be more stupid, completely.
So I am looking for a better to do this job, to display hundreds or even thousands threads/replys on winform, which is:
the height is dynamic, because the images inside will not load until it is clicked.
The text inside is selectable (I edited this just to disambiguate)
the PARENT PANEL can response to the mouse's wheel, just like twitter, forums.
So that I can use my scroll wheel to browse all the replys at one time. The loading is a background work.
Look at the picture, when the text is selected, the whole panel is still response to the wheel(just like normal webPage). This is a uwp app and I am not sure if winform can do this.

Align dynamically added controls horizontally and vertically within a control in c# winforms

I have this program that dynamically adds pictureboxes referring to the number of president in the database. How do i put them inside the groupbox and align the pictureboxes inside the groupbox? And the groupbox should stretch if the pictureboxes are many.
I have this codes now :
private void Form1_Load(object sender, EventArgs e)
{
conn.Open();
try
{
cmd = new SqlCommand("SELECT COUNT(Position) FROM TableVote WHERE Position='" + "President" + "'", conn);
Int32 PresCount = (Int32)cmd.ExecuteScalar();
TxtPresCount.Text = PresCount.ToString();
for (int i = 0; i < PresCount; ++i)
{
GroupBox PresGB = new GroupBox();
{
PresGB.Size = new Size(491, 152);
PresGB.Location = new Point(12, 12);
PresGB.Text = "President";
this.Controls.Add(PresGB);
PresGB.SendToBack();
PictureBox PresPB = new PictureBox();
PresPB.Location = new Point(80 + (150 * i) + 20, 50);
PresPB.Size = new Size(75, 75);
PresPB.BorderStyle = BorderStyle.Fixed3D;
PresPB.ImageLocation = "imgPath";
this.Controls.Add(PresPB);
PresPB.BringToFront();
};
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Close();
}
}
I would want the pictureboxes to be inside the groupbox and align it inside.
Maybe the FlowLayoutPanel control already does what you are trying to do. Just create your picture boxes and add them to a FlowLayoutPanel instead of a GroupBox.
FlowLayoutPanel automatically arranges controls in rows and/or columns depending on the value of its FlowDirection property. Set myFlowLayoutPanel.FlowDirection = FlowDirection.TopDown to get a vertical arranged list.
If you don't want multiple rows or columns set the WrapContents property to false. You can also set the AutoScroll property to true to automatically get scrollbars if the controls don't fit.
If you prefer to have the border of a GroupBox you can still put the FlowLayoutPanel into a GroupBox.
To adjust the space between the picture boxes you can use the Margin property.
This gives you a lot of control over the layout and you don't need to calculate the control positions. Also, if the size of the FlowLayoutPanel changes everything is rearranged automatically.
UPDATE:
I have a few comments on your code:
The curly braces make this look like the syntax of an object initializer - but it isn't.
GroupBox PresGB = new GroupBox(); // this line ends with a semicolon
{
// therefore this is just a block of code not related to new GroupBox()
};
You should remove the curly braces.
The creation of the group box is inside the loop. I doubt that you want a new group box for each picture box. This is the reason why you only see a single picture. Each new group box hides all the previous ones.
You add the picture boxes to the form instead of the group box.
You use "cryptic" names. PresGB and PresPB are very likely to be swapped accidentally. Abbreviations are usually a bad choice for names.
You don't need to call SendToBack or BringToFront since you don't want the controls to overlap anyway.
I don't think GroupBox is a good choice. Of course you can make it bigger if the number of pictures increases but you are limited by the screen and you don't get scollbars if the picture boxes don't fit. Use a FlowLayoutPanel. It has all the "magic" that you are looking for.
Replace your for loop with this piece of code:
var panel = new FlowLayoutPanel();
panel.SuspendLayout(); // don't calculate the layout before all picture boxes are added
panel.Size = new Size(491, 152);
panel.Location = new Point(12, 12);
panel.BorderStyle = BorderStyle.Fixed3D;
panel.FlowDirection = FlowDirection.LeftToRight;
panel.AutoScroll = true; // automatically add scrollbars if needed
panel.WrapContents = false; // all picture boxes in a single row
this.Controls.Add(panel);
for (int i = 0; i < PresCount; ++i)
{
var pictureBox = new PictureBox();
// the location is calculated by the FlowLayoutPanel
pictureBox.Size = new Size(75, 75);
pictureBox.BorderStyle = BorderStyle.FixedSingle;
pictureBox.ImageLocation = "imgPath";
panel.Controls.Add(pictureBox);
}
panel.ResumeLayout();
You can always drop a control on your form, do what you want to do then look at the designer generated code to see how the designer does it (in the "Designer.cs" file). Behind the scenes it is loading all controls and setting all properties via code.
That being said.
Keep in mind that once you put your picturebox inside the groupbox all location coordinate are in relation to the groupbox. So "0,0" is the upper-left corner of the groupbox, not the form.
To anchor your picturebox use the following code (this is just a straight copy-paste from my designer generated code, so you can clean it up a bit):
this.PresPB.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
To dock your picture box (so it fills the entire containing control):
this.PresPB.Dock = System.Windows.Forms.DockStyle.Fill;
You also need to change this line:
this.Controls.Add(PresPB);
to this:
PresGB.Controls.Add(PresPB);

How do you resize a form to fit its content automatically?

I am trying to implement the following behaviour:
On a form there is a tabcontrol. On that tabcontrol there is a treeview. To prevent scrollbars appearing, I would like the form to change its size according to the contents of the treeview when displayed for the first time.
If the treeview has too many nodes to be displayed on the default size of the form, the form should change it's size so that there is no vertical scrollbar on the treeview (up to a maximum size allowed by the size of the screen).
What I need to know is, if it is possible to achieve this behaviour through the properties of the controls. I'm sure this can be achieved by calculating and settings the sizes of the elements programmatically, but I would like to know if there is a way to achieve this by settings like AutoSizeMode etc.
[UPDATE]
It's the first dialog a user of my application sees: It's a dialog to select the database to work with. It's a list of databases, with a tabcontrol, buttens etc. If the list is too long, scrollbars appear and a colleague of mine wants them to disappear.
Use the AutoSize and AutoSizeMode properties.
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.autosize.aspx
An example:
private void Form1_Load(object sender, EventArgs e)
{
// no smaller than design time size
this.MinimumSize = new System.Drawing.Size(this.Width, this.Height);
// no larger than screen size
this.MaximumSize = new System.Drawing.Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, (int)System.Windows.SystemParameters.PrimaryScreenHeight);
this.AutoSize = true;
this.AutoSizeMode = AutoSizeMode.GrowAndShrink;
// rest of your code here...
}
By using the various sizing properties (Dock, Anchor) or container controls (Panel, TableLayoutPanel, FlowLayoutPanel, etc.) you can only dictate the size from the outer control down to the inner controls. But there is nothing (working) within the .Net framework that allows to dictate the size of a container through the size of the child control. I also missed this a few times and tried the AutoSize property, but it never worked.
So all you can do is trying to get this stuff done manually, sorry.
From MSDN:
To maximize productivity, the Windows Forms Designer shadows the
AutoSize property for the Form class. At design time, the form
behaves as though the AutoSize property is set to false,
regardless of its actual setting. At runtime, no special
accommodation is made, and the AutoSize property is applied as
specified by the property setting.
This might be useful.
It resizes a new form to a user control, and then anchors the user control to the new form:
Form f = new Form();
MyUserControl muc = new MyUserControl();
f.ClientSize = muc.Size;
f.Controls.Add(muc);
muc.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
f.ShowDialog();
You could calculate the required height of the TreeView, by figuring out the height of a node, multiplying it by the number of nodes, then setting the form's MinimumSize property accordingly.
// assuming the treeview is populated!
nodeHeight = treeview1.Nodes[0].Bounds.Height;
this.MaximumSize = new Size(someMaximumWidth, someMaximumHeight);
int requiredFormHeight = (treeView1.GetNodeCount(true) * nodeHeight);
this.MinimumSize = new Size(this.Width, requiredFormHeight);
NB. This assumes though that the treeview1 is the only control on the form. When setting the requiredFormHeight variable you'll need to allow for other controls and height requirements surrounding the treeview, such as the tabcontrol you mentioned.
(I would however agree with #jgauffin and assess the rationale behind the requirement to resize a form everytime it loads without the user's consent - maybe let the user position and size the form and remember that instead??)
This technique solved my problem:
In parent form:
frmEmployee frm = new frmEmployee();
frm.MdiParent = this;
frm.Dock = DockStyle.Fill;
frm.Show();
In the child form (Load event):
this.WindowState = FormWindowState.Maximized;
If you trying to fit the content according to the forms than the following will help. It helps me while I was trying to fit the content on the form to fit when ever the forms were resized.
this.contents.Size = new Size(this.ClientRectangle.Width,
this.ClientRectangle.Height);
I User this Code in my project, Useful for me.
private void Form1_Resize(object sender, EventArgs e)
{
int w = MainPanel.Width; // you can use form.width when you don't use panels
w = (w - 120)/4; // 120 because set 15px for each side of panels
// and put panels in FlowLayoutPanel
// 4 because i have 4 panel boxes
panel1.Width = w;
panel2.Width = w;
panel3.Width = w;
panel4.Width = w;
}
I used this code and it works just fine
const int margin = 5;
Rectangle rect = new Rectangle(
Screen.PrimaryScreen.WorkingArea.X + margin,
Screen.PrimaryScreen.WorkingArea.Y + margin,
Screen.PrimaryScreen.WorkingArea.Width - 2 * margin,
Screen.PrimaryScreen.WorkingArea.Height - 2 * (margin - 7));
this.Bounds = rect;

Scrollbar location is moving visible/nonvisible changing controls

I have a form with a scrollable panel and two controls sitting right on top of each other - one visible one not. Based on a certain condition when that form is activated I might swap the visible properties of the two controls. These controls are at the bottom of the scrollable panel. If when I leave that form I leave it scrolled to the bottom, go change the condition that will cause the controls' visibility to swap and go back to that form the visible control will have dropped about 200px down the page leaving a large gap. Anyone know what could be causing this? I tried resetting the scrollbar position to the top on form close but that just causes a smaller gap and sometimes the control to move higher into other controls. Any ideas?
Here is an example that reproduces the problem. If the mouse is moved over the red label, the visibility of button2 is changed to true which causes the scroll jumps back up to Button1.
public class Form123456 : Form {
public Form123456() {
Controls.Add(new UC1());
}
public class UC1 : UserControl {
Button b1 = new Button { Text = "Button1" };
Label lb = new Label { Text = "_", AutoSize = true, BackColor = Color.Red };
Button b2 = new Button { Text = "Button2", Visible = false };
Button b2b = new Button { Text = "x" };
Button b3 = new Button { Text = "Button3" };
public UC1() {
AutoScroll = true;
Dock = DockStyle.Fill;
b1.Location = new Point(0, 200);
b2.Location = new Point(0, 600);
lb.Location = new Point(70, 600);
b2b.Location = new Point(90, 600);
b3.Location = new Point(0, 800);
Controls.Add(b1);
Controls.Add(b2);
Controls.Add(lb);
Controls.Add(b2b);
Controls.Add(b3);
lb.MouseEnter += delegate {
b2.Visible = true;
};
lb.MouseLeave += delegate {
b2.Visible = false;
};
}
}
}
To fix it, one solution is to add this code:
protected override Point ScrollToControl(Control activeControl) {
return this.AutoScrollPosition;
}
Solution from:
Why does clicking in a text box cause an AutoScroll panel to scroll back to the top?
No repro. Sounds to me that you are doing more than just changing the Visible property. Whenever you assign the Location property, you have to add the AutoScrollPosition to compensate for the scroll state. Post code if this doesn't help.
Have you verified the order that you change visibility of the two controls?
The scroll bars on a container with auto scroll set to true will appear and disappear depending on the position of controls that are outside of the visible area of the control. Controls that are invisible do not count.
So in your case if you make both controls invisible at anytime, the scroll bars will disappear. They will come back when one control is made visible. So to make sure you don't have a jump in scroll bar position and controls position you should make sure that at no time are both controls invisible. Another solution is to have a pseudo-visible control on the container. That is a control that has its visibility set to true but it is not actually visible for the user (for example a dot of the color of the background, a label with no text ...). Position this control in the furthest position x,y and the scroll bars will never disappear..

Winforms, creating padding when using Dock properties

How do I add padding, or some space between the textboxes when using dockstyle.top property?
for(int i =0; i< 10; i++) {
textboxes[i] = new TextBox();
textboxes[i].Dock = DockStyle.Top;
mypanel.Controls.Add(textboxes[i]);
}
The code above puts textboxes right beneath each other. Can't figure this out without using mass panels or fixed positioning. How to do the following?
1) I would like to add around 10-20pixels between boxes.
2) How to change size (height,width) of the textboxes, since when using dockstyle.top it ignores the size commands ?
With DockStype.Top you can't change the width of your TextBoxes, cause they are docked. You can only change the height. But to change the height of a TextBox you have to set the Multiline = true beforehand.
To get the space between the different boxes you have to put each TextBox within a panel, set the TextBox.Dock = Fill, the Panel.Dock = Top and the Panel.Padding = 10. Now you have some space between each TextBox.
Sample Code
for (int i = 0; i < 10; i++)
{
var panelTextBox = CreateBorderedTextBox();
this.Controls.Add(panelTextBox);
}
private Panel CreateBorderedTextBox()
{
var panel = CreatePanel();
var textBox = CreateTextBox();
panel.Controls.Add(textBox);
return panel;
}
private Panel CreatePanel()
{
var panel = new Panel();
panel.Dock = DockStyle.Top;
panel.Padding = new Padding(5);
return panel;
}
private TextBox CreateTextBox()
{
var textBox = new TextBox();
textBox.Multiline = true;
textBox.Dock = DockStyle.Fill;
return textBox;
}
What i forgot, you can also give a try to the FlowLayoutPanel. Just remove the DockStyle.Top from the panels and put them into the FlowLayoutPanel. Also you should set the FlowDirection to TopDown. Maybe this can also help you to solve your problem, too.
Another work around that suits smaller layouts is to just add a Label control afterwards also docked to the Top, which is not AutoSized, Text=" ", Height=your padding. This is quite useful for the odd bit of padding when using the designer.
I know where you're coming from, this is especially frustrating after returning to WinForms from WPF.
I would suggest using a TableLayoutPanel, in which each TextBox would get its own cell, and adjusting the properties of the cells. This should solve both your padding and size problems.
Another alternative would be to use some more complex layout controls, such as the DevExpress ones (not free).

Categories

Resources