问题
I am adding various dynamically created controls to a panel, based on what the user selects. If a Groupbox, with associated RadioButtons, is the first control, it looks fine:
...but if it's anything other than that, the associated radio buttons seem right-aligned instead of left-aligned, as seen above, and the groupbox is too wide, to boot.
Here is the pertinent code (RepaintMockupPanel() is called when the user opts to see what his mockup looks like at any time, and getGroupBox() is the method it calls that should be where the problem lies, but I can't see it.
private void RepaintMockupPanel(Control padre)
{
const string BTN = "BUTTON";
const string CKBX = "CHECKBOX";
const string EDTTXT = "EDITTEXT";
const string RADGRP = "RADIOGROUP";
const string SPNR = "SPINNER";
const string TXTVU = "TEXTVIEW";
const int LEFT_STARTING_POINT = 4;
const int STANDARD_PADDING = 4;
int currentLeft = LEFT_STARTING_POINT;
string currentSel;
string currentSettings;
ComboBox cmbx;
Label lbl;
try
{
TabPage tp = padre as TabPage;
string panelName = tp.Name.Replace("tabPage", "panel");
Panel p = tp.Controls[panelName] as Panel;
p.Controls.Clear();
for (int i = 0; i < p.Controls.Count; i++)
{
p.Controls[i].Dispose();
}
//cmbxRow0Element0 and lblRow0Element0 to cmbxRow11Element5 and lblRow11Element5
int rowNum = getRowNum(panelName);
for (int i = 0; i < WIDGETS_PER_TABPAGE; i++)
{
cmbx = tp.Controls[string.Format("cmbxRow{0}Element{1}", rowNum, i)] as ComboBox;
lbl = tp.Controls[string.Format("lblRow{0}Element{1}", rowNum, i)] as Label;
if (cmbx.SelectedIndex < 0) continue;
currentSel = cmbx.SelectedItem.ToString().ToUpper();
currentSettings = lbl.Text;
// Possible vals (Android on left, Windows equivalents on the right:
//Button ""
//CheckBox ""
//EditText TextBox
//RadioGroup GroupBox (w. RadioButtons nested within)
//Spinner ComboBox
//TextView Label
if ((currentSel.Length > 0) && (currentSettings.Length > 0))
{
if (currentSel.Equals(BTN))
{
Button btn = getButton(currentSettings, currentLeft);
p.Controls.Add(btn);
currentLeft += btn.Width + STANDARD_PADDING;
}
else if (currentSel.Equals(CKBX))
{
CheckBox ckbx = getCheckBox(currentSettings, currentLeft);
p.Controls.Add(ckbx);
currentLeft += ckbx.Width + STANDARD_PADDING;
}
else if (currentSel.Equals(EDTTXT))
{
TextBox txtbx = getTextBox(currentSettings, currentLeft);
p.Controls.Add(txtbx);
currentLeft += txtbx.Width + STANDARD_PADDING;
}
else if (currentSel.Equals(RADGRP))
{
GroupBox grpbx = getGroupBox(currentSettings, currentLeft);
p.Controls.Add(grpbx);
currentLeft += grpbx.Width + STANDARD_PADDING;
}
else if (currentSel.Equals(SPNR))
{
ComboBox cmbxDyn = getComboBox(currentSettings, currentLeft);
p.Controls.Add(cmbxDyn);
currentLeft += cmbxDyn.Width + STANDARD_PADDING;
}
else if (currentSel.Equals(TXTVU))
{
Label lblDyn = getLabel(currentSettings, currentLeft);
p.Controls.Add(lblDyn);
currentLeft += lblDyn.Width + STANDARD_PADDING;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private GroupBox getGroupBox(string currentSettings, int curLeftVal)
{
// "apple~orange~peach~True (must look for "enclose group in a black box" as the last val (ignore for the quick-and-dirty mockup, though))
// Adapted from Pierre's answer at http://stackoverflow.com/questions/23944419/why-is-only-the-first-radiobutton-being-added-to-the-groupbox
IList<string> grpbxVals = new List<string>(currentSettings.Split('~'));
GroupBox gb = new GroupBox { Height = 60, Location = new Point(curLeftVal, 0) };
gb.AutoSize = true;
int radButtonYVal = 0;
for (int i = 0; i < grpbxVals.Count() - 1; i++)
{
//gb.Controls.Add(new RadioButton { Text = grpbxVals[i], Location = new Point(curLeftVal, radButtonPosition) });
gb.Controls.Add(new RadioButton { Text = grpbxVals[i], Location = new Point(gb.Location.X+2, radButtonYVal) });
radButtonYVal += new RadioButton().Height;
}
return gb;
}
回答1:
The getGroupBox() method is INDEED where the issue lies.
As a Container, GroupBox has its own canvas upon which its child controls are drawn, so when you create a control with an X value of 5, it means it's 5 from the left of the GroupBox, NOT from the left of the form. It's absolute value on the form would be it's own X value (say in this case 5) plus the X value of the GroupBox (which we'll assume has a Left value of 25) for an absolute positon of being 30 from the Left.
This is why your example shows the radio buttons pushed over so far: if you examine the distance between the left edge of the RadioButtons in relation to the left edge of their containing GroupBox, it should be about the same distance as the left edge of the GroupBox from the left edge of ITS container.
回答2:
Why not use a TableLayoutPanel or FlowLayoutPanel to automatically position the controls, you can insert with fill dock the GroupBox. Then you just need to add the controls to ... LayoutPanel and positioned automatically. You have several options to control the rows and / or columns of the TableLayoutPanel And as other controls to control flow into the FlowLayoutPanel Here a example using layout panel, place a Button docked Top, and a empty TabControl docked Fill, and try this code
private void button1_Click(object sender, EventArgs e)
{
for (int t = 0; t < 4;t++ )
tabControl1.TabPages.Add(CreateTabPage(t));
}
private TabPage CreateTabPage(int t)
{
TabPage result = new TabPage()
{
Text=string.Format("TabPage {0}",t)
};
FlowLayoutPanel flp = new FlowLayoutPanel()
{
Dock = DockStyle.Fill,
AutoScroll = true,
};
for (int i = 0; i < 10; i++)
{
flp.Controls.Add(CreateGroupBox(i));
}
result.Controls.Add(flp);
return result;
}
private Control CreateGroupBox(int i)
{
GroupBox result = new GroupBox()
{
Text = string.Format("GroupBox {0}", i),
Width = 150,
Height = 100
};
FlowLayoutPanel flp = new FlowLayoutPanel()
{
Dock = DockStyle.Fill,
WrapContents = false,
AutoScroll = true,
FlowDirection=FlowDirection.TopDown
};
CreateRadios(flp, i);
result.Controls.Add(flp);
return result;
}
private void CreateRadios(FlowLayoutPanel flp, int i)
{
for (int c = 0; c < 10; c++) {
flp.Controls.Add(new RadioButton()
{
Text = string.Format("RadioButton {0} in {1}", c, i)
});
}
}
回答3:
Tricycle Omnivore was right; this works:
int radButtonYVal = 4;
int leftVal = 4;
for (int i = 0; i < grpbxVals.Count() - 1; i++)
{
gb.Controls.Add(new RadioButton { Text = grpbxVals[i], AutoSize = true, Location = new Point(leftVal, radButtonYVal) });
radButtonYVal += new RadioButton().Height -4; // the "-4" is a kludge to scrunch the radiobuttons together a bit
}
来源:https://stackoverflow.com/questions/23964932/why-does-my-dynamically-created-groupbox-place-its-radiobuttons-too-far-right-on