This question already has an answer here:
Alignment of Items in GroupBox
(1 answer)
Closed 4 years ago.
I've created window applications and would like to center elements in the groupbox. Can I do this with a code?
groupbox
This code assumes you will be creating the additional controls entirely in code and not using the Designer.
If you do use the Designer, just remove the line
Button button = new Button() { Text = "Button1" };
and put the name of the button control in the next line.
private void AddControlsToGroupBox()
{
Button button = new Button() { Text = "Button1" };
CentreControlInGroupBox(this.groupBox1, button);
}
private void CentreControlInGroupBox(GroupBox theGroupBox, Control theControl)
{
// Find the centre point of the Group Box
int groupBoxCentreWidth = theGroupBox.Width / 2;
int groupBoxCentreHeight = theGroupBox.Height / 2;
// Find the centre point of the Control to be positioned/added
int controlCentreWidth = theControl.Width / 2;
int controlCentreHeight = theControl.Height / 2;
// Set the Control to be at the centre of the Group Box by
// off-setting the Controls Left/Top from the Group Box centre
theControl.Left = groupBoxCentreWidth - controlCentreWidth;
theControl.Top = groupBoxCentreHeight - controlCentreHeight;
// Set the Anchor to be None to make sure the control remains
// centred after re-sizing of the form
theControl.Anchor = AnchorStyles.None;
// Add the control to the GroupBox's Controls collection to maintain
// the correct Parent/Child relationship
theGroupBox.Controls.Add(theControl);
}
The code also assumes you will place only a single control in the Group Box. I don't think you will find it too hard to adjust the sample accordingly if there are multiple controls.
Related
first time poster, sorry if something isn't as it should be.
I'm new to Winforms and am trying to build a simple application that will display multiple features of an item (like Size, Composition, etc.). Each Characteristic has a Name, can have a Descritpion, and some can have sub-characteristics (having also a name and sometimes a descritpion).
I want to display them one under the other, with the Name of the feature on a blue background that span the whole width of the container, with the description underneath. The name will be (or have) a button (or similar) that when clicked collapse or expand the description. This must be created at run time because I don't know how many feature an object has until the user generate it.
The issues I'm running in are that either I can't span the blue background the whole width of the container (if using a FlowLayoutPanel), or I have some issue with the Description text being not the right size (either it wraps but is too big, or it doesn't wrap and then I can't see the whole text).
Some things are fixed, mainly the number of main sections (like Size, Composition, Weather, etc.), so I can prepare the skeleton before runtime.
The closest i've been to making it work gives this. This issue here is that the height of the Panel which the description label is embded in is fixed, and if I put in in Autosize, the text don't show (probably because the label is in Fill dock style). Just as information, this is what it looks like when collapsed (this is indeed what I'm looking for)
I know some library exists with collapsible panels, but I'd rather try to make it work without external libraries. Thanks in advance for any help !
This is the code that produces the results in the screenshots :
Panel SizeDescrPanel = new Panel();
SizeDescrPanel.Dock = DockStyle.Top;
//SizeDescrPanel.AutoSize = true;
SizeDescrPanel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
SizeDescrPanel.BackColor = Color.Bisque;
SizePanel.Controls.Add(SizeDescrPanel);
Label SizeDescrLbl = new Label();
SizeDescrLbl.Text = Lorem;
SizeDescrLbl.AutoSize = false;
SizeDescrLbl.Dock = DockStyle.Fill;
SizeDescrLbl.BackColor = Color.BurlyWood;
SizeDescrPanel.Controls.Add(SizeDescrLbl);
/*using(Graphics g = CreateGraphics())
{
SizeF size = g.MeasureString(SizeDescrLbl.Text, SizeDescrLbl.Font, SizePanel.Width);
SizeDescrPanel.Height = (int) Math.Ceiling(size.Height);
}*/
Panel SizeNamePanel = new Panel();
SizeNamePanel.Dock = DockStyle.Top;
SizeNamePanel.BackColor = Color.Cyan;
SizeNamePanel.AutoSize = true;
SizePanel.Controls.Add(SizeNamePanel);
Button SizeNameBtn = new Button();
SizeNameBtn.Text = "<Size Name> ..." + SizeDescrLbl.Height;
SizeNameBtn.TextAlign = ContentAlignment.MiddleLeft;
SizeNameBtn.FlatStyle = FlatStyle.Flat;
SizeNameBtn.AutoSize = true;
SizeNamePanel.Controls.Add(SizeNameBtn);
SizeNameBtn.Click += delegate { HideShowPanel(SizeDescrPanel); };
It,s a test project, so later I'll put that in different methods. What isn't shown here :
I have a main panel set to Fill containing everything.
The text "SIZE" is a label set to Top
Under it is another Panel (SizePanel) that is set to Top and Autosize is at True. This is the Panel inside which I'm puttin my size name and my size description. If I had a subfeature, it would be included (ideally) inside descritpion with the same configuration (button expanding/collapsing the descritpion of the SubFeature)
I created a template panel to go by when my form loads that holds a record. When adding a new record I have a method that duplicates that template panel and then adds it to my list of panels for each record. Somehow controls are getting deleted from my template panel when I am duplicating it and I have no idea how this is happening. The portion of code doing this is listed below
Panel pn = new Panel()
{
Width = _PNTemp.Width,
Height = _PNTemp.Height,
Left = 0,
Top = 0,
BackColor = _PNTemp.BackColor,
ForeColor = _PNTemp.ForeColor,
AutoScroll = true,
Name = _PNTemp.Name,
Tag = _PrgPanels.Count.ToString()
};
MessageBox.Show(_PNTemp.Controls.Count.ToString());
foreach (Control c in _PNTemp.Controls)
{
pn.Controls.Add(c);
MessageBox.Show(_PNTemp.Controls.Count.ToString());
}
MessageBox.Show(_PNTemp.Controls.Count.ToString());
_PrgPanels.Add(pn);
I put the messagebox.show() in at 3 points to narrow down where it is happening. The first one shows the correct number of controls, the second and third shows a 1/2 the total amount of controls. why is this?
This is because each control can be added to only one parent control. All controls in your template panel are already a child of the template panel. When you try to add these controls to a new panel, the controls will get removed from the template panel.
As per the docs:
A Control can only be assigned to one Control.ControlCollection at a
time. If the Control is already a child of another control it is
removed from that control before it is added to another control.
Which means that you need to create new controls instead of adding those in the template.
An alternative approach is to create a method that returns the template panel. When you need the template panel, just call the method and a new panel will be created:
public static Panel CreateTemplatePanel() {
Panel pn = new Panel();
// set properties, add controls...
return pn;
}
A control can only be on one panel at once. I've added comments inline in your code to help explain whats happening.
Panel pn = new Panel()
{
Width = _PNTemp.Width,
Height = _PNTemp.Height,
Left = 0,
Top = 0,
BackColor = _PNTemp.BackColor,
ForeColor = _PNTemp.ForeColor,
AutoScroll = true,
Name = _PNTemp.Name,
Tag = _PrgPanels.Count.ToString()
};
MessageBox.Show(_PNTemp.Controls.Count.ToString());
//all the controls are still inside _PNTemp
foreach (Control c in _PNTemp.Controls)
{
pn.Controls.Add(c);
MessageBox.Show(_PNTemp.Controls.Count.ToString());
//Each time this runs you remove a control from _PNTemp to pn.
}
//All the controls moved from _PnTemp to pn
MessageBox.Show(_PNTemp.Controls.Count.ToString());
_PrgPanels.Add(pn);
I have tried to create a radiobutton dynamically and add it to groupbox/form, but the whole text associated with the radiobutton is not getting displayed. When the radiobutton is added from the designer, the whole text is getting displayed. For dynamically adding radio button am I missing anything or are there any ways to do it?
Please find the sample code below:
public partial class Form1 : Form
{
private void SelectMicrophone_Load(object sender, EventArgs e)
{
System.Windows.Forms.RadioButton r1 = new System.Windows.Forms.RadioButton(); //created a radiobutton
r1.Name = "Microphone(RealTex";
r1.Text = "Microphone(RealTex";
r1.Location = new System.Drawing.Point(15, 15);
this.groupBox1.Controls.Add(r1);
When you set the text property in the designer, it adjust the radio button to the new size to cover the width of the text. By default I think the width is 90 and with the text above it is resized to a width of 124. So when you create the object at runtime, it is probably just keeping the width to 90. You can however just set r1.Width = 124 before adding it to your controls collection.
Keep in mind that you may not know the length each time so you could either set the width to the maximum size that you need or use the TextRender's .MeasureText method to get the size of the text and then just add 20 to that to cover the graphic of the radio button circle that also appears and set the result of the X property to your width before adding the radiobutton to the collection.
RadioButton r1 = new RadioButton();
r1.Text = "This is short text";
//Measure the Text property and get the width and add 20 to accomodate the circle
r1.Width = (TextRenderer.MeasureText(r1.Text, r1.Font)).Width + 20;
r1.Location = new Point(15, 15);
this.Controls.Add(r1);
//Just another RB with even longer text.
r1 = new RadioButton();
r1.Text = "This is even longer text that we want to show";
r1.Width = (TextRenderer.MeasureText(r1.Text, r1.Font)).Width + 20;
r1.Location = new Point(15, 35);
this.Controls.Add(r1);
I have a custom Tabs Control I created. It works as a coloured Label for the tab itself and as a Panel to hold the contents. My application reads UI parameters from config files. Take this line as an example from the controls config:
RTFBOX=(ID - rtf1) (BOUNDS - 0,0,100,100) (MULTILINE - enable) (FILE - email_rules.rtf)
This line tells the application to create an instance of my custom RichTextBoxPlus class and the important thing to take from this is that it is set up to read rich text from the FILE parameter. If I don't add this RichTextBoxPlus to another Control it shows it's rich text formatting absolutely fine.
I have another config that reads actions at runtime, this can be simple stuff like telling a Button created with the controls config that when it is clicked, it should fire off an email using content from a TextBox control. I have an action that pairs controls to each tab in the Tabs custom control. For example:
ADDTOTABS=(OBJECT - tabsControl1) (CONTROLS - panel1, panel2)
This finds tabsControl1 and adds panel1 to the 1st tab and panel2 to the 2nd tab. In this example, Panels are being added to each tab instead of individual controls as the Panels could hold multiple controls, handled at runtime through the ADDTOPANEL action.
ADDTOPANEL=(OBJECT - rtf1) (TARGET - panel1) (TRIGGER - onload)
So the rtf1 instance of RichTextBoxPlus is added to panel1 which is then added to the respective Panel of the Tabs control's 1st tab.
What I have found is rtf1 displays with rich text formatting absolutely fine if added to panel1 but not adding panel1 to Tabs.
The ADDTOTABS action executes this method:
private void TabContents_Action(Tabs tabpanel, string[] ctrls)
{
string[] tabs = tabpanel.GetTabNames();
for(int i = 0; i < tabs.Length; i++)
{
Control control = this.Controls.Find(ctrls[i], true).FirstOrDefault();
tabpanel.SetTaggedObject(control, tabs[i]);
}
tabpanel.SetTabActive(tabs[0]);
}
The SetTaggedObject method of the Tabs class finds the Panel control that corresponds with the tab name provided:
public void SetTaggedObject(Control ctrl, string tab)
{
Control container = this.Controls.Find(tab, false).FirstOrDefault();
container.Controls.Add(ctrl);
}
Doesn't seem to be anything untoward about this method.
The SetTabActive method of the Tabs class has a little more bulk. This handles changing the appearance of all tabs so that inactive tabs look different to the active tab. It is also hides and shows the panels for each tab based on whether the tab is active.
public void SetTabActive(string tab)
{
LabelPlus activeTab = this.tabs.Find(x => x.Name.Equals(tab));
List<LabelPlus> inactiveTabs = new List<LabelPlus>(this.tabs.FindAll(x => !x.Name.Equals(tab)));
activeTab.BackColor = this.ActiveColor;
activeTab.ForeColor = this.ActiveForeColor;
string panelName = tab.Remove(tab.Length - this.tabSuffix.Length);
Panel activeTabPanel = (Panel)this.Controls.Find(panelName, true).FirstOrDefault();
activeTabPanel.Bounds = new Rectangle(
new Point(this.tabStart, this.originalLocation.Y + this.TabTotalHeight), this.Size);
ControlCollection activeTabCtrls = activeTabPanel.Controls;
foreach(LabelPlus inactiveTab in inactiveTabs)
{
inactiveTab.BackColor = this.InactiveColor;
inactiveTab.ForeColor = this.InactiveForeColor;
string inactivePanelName = inactiveTab.Name.Remove(inactiveTab.Name.Length - this.tabSuffix.Length);
Panel inactiveTabPanel = (Panel)this.Controls.Find(inactivePanelName, true).FirstOrDefault();//
inactiveTabPanel.Bounds = new Rectangle(
new Point(this.tabStart, this.originalLocation.Y + this.TabTotalHeight), this.Size);
ControlCollection inactiveTabControls = inactiveTabPanel.Controls
foreach (Control ctrl in inactiveTabControls) { ctrl.Location = new Point(0, ctrl.Location.Y); ctrl.Hide(); }
}
foreach (Control ctrl in activeTabCtrls)
{ ctrl.Location = new Point(0, ctrl.Location.Y); ctrl.Show(); }
}
Not sure but I'd say the issue must be in this method. Any thoughts?
In my project I wanted to order controls at run-time, like in DataGridView how we'll use display-index to order fields in the grid.
In design level I added 3 TextBoxs and 1 ComboBox next to each other & in run time i wanted to order them, for example, first 2 TextBoxs should show, then the ComboBox and then the other TextBox.
Is it possible to rearrange the controls in run-time?
Every Control in Windows Forms has a Location property. You can easily change the location of the control by changing this property:
textBox1.Location = new Point(10, 50); // Puts the TextBox at coordinates (10,50)
The coordinates are relative to upper-left corner of the control container (the form itself for example).
In your case, you can easily arrange the controls like this:
Control[] controls = new Control[] { textBox1, textBox2, comboBox3, textBox3 }; // These are your controls
int left = 20, top = 50; // or any other value
foreach (c in controls)
{
c.Location = new Point(left, top);
left += c.Width + 10; // space 10 pixels between controls
}