How to expand an group box when an button is clicked - c#

I have an.exe and I need to collapse a group_box when it is not used and want to expand when a button is clicked.
As of now, I have created a group-box and its been disabled and if a button is clicked that will be enabled and now I want to change the current process that is instead of disabling I want to collapse and instead of enabling I want to expand that group_box.
As of now, for the page load:
groupboxname.enabled=false;
Button click:
groupboxname.enabled=true;

You Can Also Try Something Like This For Collapse And Expand The groupbox.
public partial class Form1 : Form
{
int height, width;
bool IsFirstClick = false;
public Form1()
{
InitializeComponent();
height = groupBox1.Height;
width = groupBox1.Width;
groupBox1.Height = 0;
groupBox1.Width = 0;
}
private void button1_Click(object sender, EventArgs e)
{
if (!IsFirstClick)
{
IsFirstClick = true;
groupBox1.Width = width;
for (int i = 0; i < height; i++)
{
groupBox1.Height = i;
}
}
else
{
IsFirstClick = false;
for (int i = height; i>0; i--)
{
groupBox1.Height = i;
}
groupBox1.Width = 0;
}
}
}

Related

how can I split a panel to clickable segments in c# winform?

I am trying to simulate a LED display board with c# . I need a control which contains 1536 clickable controls to simulate LEDs (96 in width and 16 in Height). I used a panel named pnlContainer for this and user will add 1536 tiny customized panels at runtime. These customized panels should change their color by click event at runtime. Everything works . But adding this number of tiny panels to the container takes long time ( about 10 secs). What is your suggestion to solve this issue? Any tips are appreciated.
this is my custome panel:
public partial class LedPanel : Panel
{
public LedPanel()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (this.BackColor == Color.Black)
{
this.BackColor = Color.Red;
}
else
{
this.BackColor = Color.Black;
}
}
}
}
and this is piece of code which adds tiny panels to the pnlContainer :
private void getPixels(Bitmap img2)
{
pnlContainer.Controls.Clear();
for (int i = 0; i < 96; i++)
{
for (int j = 0; j < 16; j++)
{
Custom_Controls.LedPanel led = new Custom_Controls.LedPanel();
led.Name = i.ToString() + j.ToString();
int lWidth = (int)(pnlContainer.Width / 96);
led.Left = i * lWidth;
led.Top = j * lWidth;
led.Width = led.Height = lWidth;
if (img2.GetPixel(i, j).R>numClear.Value)
{
led.BackColor = Color.Red;
}
else
{
led.BackColor = Color.Black;
}
led.BorderStyle = BorderStyle.FixedSingle;
pnlContainer.Controls.Add(led);
}
}
}
Is there any better approach or better control instead of panelto do this?
I agree with what #TaW recommends. Don't put 1000+ controls on a form. Use some sort of data structure, like an array to keep track of which LEDs need to be lit and then draw them in the Paint event of a Panel.
Here's an example. Put a Panel on a form and name it ledPanel. Then use code similar to the following. I just randomly set the values of the boolean array. You would need to set them appropriately in response to a click of the mouse. I didn't include that code, but basically you need to take the location of the mouse click, determine which array entry needs to be set (or unset) and then invalidate the panel so it will redraw itself.
public partial class Form1 : Form
{
//set these variables appropriately
int matrixWidth = 96;
int matrixHeight = 16;
//An array to hold which LEDs must be lit
bool[,] ledMatrix = null;
//Used to randomly populate the LED array
Random rnd = new Random();
public Form1()
{
InitializeComponent();
ledPanel.BackColor = Color.Black;
ledPanel.Resize += LedPanel_Resize;
//clear the array by initializing a new one
ledMatrix = new bool[matrixWidth, matrixHeight];
//Force the panel to repaint itself
ledPanel.Invalidate();
}
private void LedPanel_Resize(object sender, EventArgs e)
{
//If the panel resizes, then repaint.
ledPanel.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
//clear the array by initializing a new one
ledMatrix = new bool[matrixWidth, matrixHeight];
//Randomly set 250 of the 'LEDs';
for (int i = 0; i < 250; i++)
{
ledMatrix[rnd.Next(0, matrixWidth), rnd.Next(0, matrixHeight)] = true;
}
//Make the panel repaint itself
ledPanel.Invalidate();
}
private void ledPanel_Paint(object sender, PaintEventArgs e)
{
//Calculate the width and height of each LED based on the panel width
//and height and allowing for a line between each LED
int cellWidth = (ledPanel.Width - 1) / (matrixWidth + 1);
int cellHeight = (ledPanel.Height - 1) / (matrixHeight + 1);
//Loop through the boolean array and draw a filled rectangle
//for each one that is set to true
for (int i = 0; i < matrixWidth; i++)
{
for (int j = 0; j < matrixHeight; j++)
{
if (ledMatrix != null)
{
//I created a custom brush here for the 'off' LEDs because none
//of the built in colors were dark enough for me. I created it
//in a using block because custom brushes need to be disposed.
using (var b = new SolidBrush(Color.FromArgb(64, 0, 0)))
{
//Determine which brush to use depending on if the LED is lit
Brush ledBrush = ledMatrix[i, j] ? Brushes.Red : b;
//Calculate the top left corner of the rectangle to draw
var x = (i * (cellWidth + 1)) + 1;
var y = (j * (cellHeight + 1) + 1);
//Draw a filled rectangle
e.Graphics.FillRectangle(ledBrush, x, y, cellWidth, cellHeight);
}
}
}
}
}
private void ledPanel_MouseUp(object sender, MouseEventArgs e)
{
//Get the cell width and height
int cellWidth = (ledPanel.Width - 1) / (matrixWidth + 1);
int cellHeight = (ledPanel.Height - 1) / (matrixHeight + 1);
//Calculate which LED needs to be turned on or off
int x = e.Location.X / (cellWidth + 1);
int y = e.Location.Y / (cellHeight + 1);
//Toggle that LED. If it's off, then turn it on and if it's on,
//turn it off
ledMatrix[x, y] = !ledMatrix[x, y];
//Force the panel to update itself.
ledPanel.Invalidate();
}
}
I'm sure there can be many improvements to this code, but it should give you an idea on how to do it.
#Chris and #user10112654 are right.
here is a code similar to #Chris but isolates the displaying logic in a separate class. (#Chris answered your question when I was writing the code :))))
just create a 2D array to initialize the class and pass it to the Initialize method.
public class LedDisplayer
{
public LedDisplayer(Control control)
{
_control = control;
_control.MouseDown += MouseDown;
_control.Paint += Control_Paint;
// width and height of your tiny boxes
_width = 5;
_height = 5;
// margin between tiny boxes
_margin = 1;
}
private readonly Control _control;
private readonly int _width;
private readonly int _height;
private readonly int _margin;
private bool[,] _values;
// call this method first of all to initialize the Displayer
public void Initialize(bool[,] values)
{
_values = values;
_control.Invalidate();
}
private void MouseDown(object sender, MouseEventArgs e)
{
var firstIndex = e.X / OuterWidth();
var secondIndex = e.Y / OuterHeight();
_values[firstIndex, secondIndex] = !_values[firstIndex, secondIndex];
_control.Invalidate(); // you can use other overloads of Invalidate method for the blink problem
}
private void Control_Paint(object sender, PaintEventArgs e)
{
if (_values == null)
return;
e.Graphics.Clear(_control.BackColor);
for (int i = 0; i < _values.GetLength(0); i++)
for (int j = 0; j < _values.GetLength(1); j++)
Rectangle(i, j).Paint(e.Graphics);
}
private RectangleInfo Rectangle(int firstIndex, int secondIndex)
{
var x = firstIndex * OuterWidth();
var y = secondIndex * OuterHeight();
var rectangle = new Rectangle(x, y, _width, _height);
if (_values[firstIndex, secondIndex])
return new RectangleInfo(rectangle, Brushes.Red);
return new RectangleInfo(rectangle, Brushes.Black);
}
private int OuterWidth()
{
return _width + _margin;
}
private int OuterHeight()
{
return _height + _margin;
}
}
public class RectangleInfo
{
public RectangleInfo(Rectangle rectangle, Brush brush)
{
Rectangle = rectangle;
Brush = brush;
}
public Rectangle Rectangle { get; }
public Brush Brush { get; }
public void Paint(Graphics graphics)
{
graphics.FillRectangle(Brush, Rectangle);
}
}
this is how it's used in the form:
private void button2_Click(object sender, EventArgs e)
{
// define the displayer class
var displayer = new LedDisplayer(panel1);
// define the array to initilize the displayer
var display = new bool[,]
{
{true, false, false, true },
{false, true, false, false },
{false, false, true, false },
{true, false, false, false }
};
// and finally
displayer.Initialize(display);
}

c# Dynamic panel on mouse

I am making a N*M size SUDOKU game. Every number are on a button.
When the program start all button is empty and I would like if I click to a button it is make a little panel on it with buttons for each number to choose one.
private void adatB_Click(object sender, EventArgs e)
{
Button button = sender as Button;
int[] hely = button.Tag.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(Int32.Parse).ToArray();
Panel szamok = new Panel
{
Location = MousePosition,
Size = new Size(100, 100)
};
Controls.Add(szamok);
TableLayoutPanel minitabla = new TableLayoutPanel
{
Dock = DockStyle.Fill,
ColumnCount = szorzat,
RowCount = szorzat,
};
for (int i = 0; i < szorzat; i++)
{
minitabla.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
minitabla.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
}
szamok.Controls.Add(minitabla);
Button[,] szamokB = new Button[meret[0], meret[1]];
int d = 1;
for (int i = 0; i < meret[0]; i++)
{
for (int j = 0; j < meret[1]; j++)
{
szamokB[i, j] = new Button();
szamokB[i, j].Tag= hely[0]+","+hely[1];
szamokB[i, j].Text = d.ToString();
szamokB[i, j].Dock = DockStyle.Fill;
szamokB[i, j].Click += szamokB_Click;
minitabla.Controls.Add(szamokB[i, j], i, j);
d++;
}
}
}
private void szamokB_Click(object sender, EventArgs e)
{
Button button = sender as Button;
int[] hely = button.Tag.ToString().Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(Int32.Parse).ToArray();
adatB[hely[0], hely[1]].Text = button.Text;
}
The problem with it when I click a button the pane isn't created.
meret[0] variable is the N, meret[1] is M, adatB is the arry of buttons with the positons in tag.
And If I choosed the number how can I close that panel?
First of all, you should calculate the mouseposition correctly.
From MSDN:
Gets the position of the mouse cursor in screen coordinates.
You should use something like this:
Location = new Point(MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y)
You will probably need this, to bring your panel to the front:
Controls.Add(szamok);
szamok.BringToFront();
To close the panel you can store the chooser panel and you can remove it from the controls later, use something like this:
public partial class Form1 : Form
{
private Panel myPanel = null;
private void adatB_Click(object sender, EventArgs e)
{
...
Panel szamok = new Panel
{
Location = new Point(MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y),
Size = new Size(100, 100)
};
if (this.myPanel != null)
{
this.Controls.Remove(this.myPanel);
}
this.myPanel = szamok;
Controls.Add(szamok);
szamok.BringToFront();
...
}
private void szamokB_Click(object sender, EventArgs e)
{
if (this.myPanel != null)
{
this.Controls.Remove(this.myPanel);
this.myPanel = null;
}
...
}
}

Clearing a form of controls for more to be added

I have a standard panel which I add controls too, when the number of controls exceeds the panels size I want to clear the panel ready for the "next page" of controls which just is a clear and location reset of the buttons. Problem is when ever I clear the controls new ones will not add. Here is what I have:
// MDButList is the collection of controls
ButPosX = 2; // x position of button on panel
ButPosY = 2; // y position of button on panel
PageCount = 1; // page number
for (int i = 0; i <= MDButList.Count - 1; i++)
{
NewPOBut = MDButList[i]; // as cant ref a collection for some reason..
if (i % 14 == 0) // panel can only hold 14
{
if (i < 13) // for first item (0)
SetPOButPos(ref ButPosX, ref ButPosY, ref NewPOBut);
//sets the buttons point value and increments x & y
else
{
panMDItems.Controls.Clear();
ButPosX = 2;
ButPosY = 2;
PageCount++;
SetPOButPos(ref ButPosX, ref ButPosY, ref NewPOBut);
btnPrevPage.Visible = true;
btnNextPage.Visible = true;
labPageNum.Visible = true;
labPageNum.Text = PageCount.ToString() + " / " + PageCount.ToString();
}
}
else
{
SetPOButPos(ref ButPosX, ref ButPosY, ref NewPOBut);
}
}
Controls are being added to the collection and the code steps through as expected but after 14 controls I just get a blank panel nothing above a 14 control count will add? Ask if you need more info, thanks!
I was kind of bored, so i've made a sample of how i would do what you are asking for. This is my code, see if it fits you.
public partial class Form1 : Form
{
private int page = 1;
private int pageCount = 0;
List<Button> MDButList = new List<Button>();
public Form1()
{
InitializeComponent();
GenerateButtons(60);
SetButtons(page);
}
private void GenerateButtons(decimal number)
{
for (int i = 0; i < number; i++)
{
Button a = new Button();
a.Text = "But" + i;
MDButList.Add(a);
}
pageCount = Convert.ToInt32(Math.Ceiling(number / 14));
}
private void SetButtons(int page)
{
labPageNum.Text = page.ToString() + " / " + pageCount.ToString();
int ButPosX = 2;
int ButPosY = 2;
for (int i = panMDItems.Controls.Count - 1; i >= 0; --i)
panMDItems.Controls[i].Dispose();
int upperlimit=(page * 14) - 1;
if (upperlimit>MDButList.Count-1) upperlimit=MDButList.Count-1;
for (int i = (page-1) * 14; i <=upperlimit ; i++)
{
Button NewPOBut = MDButList[i];
SetPOButPos(ref ButPosX, ref ButPosY, ref NewPOBut);
if (i % 2 != 0)
{
ButPosX = 2;
ButPosY += NewPOBut.Height + 10;
}
else
{
ButPosX += NewPOBut.Width + 10;
}
}
}
private void SetPOButPos(ref int ButPosX, ref int ButPosY, ref Button NewPOBut)
{
NewPOBut.Location = new Point(ButPosX, ButPosY);
panMDItems.Controls.Add(NewPOBut);
}
private void btnPrevPage_Click(object sender, EventArgs e)
{
if (page > 1) page--;
SetButtons(page);
}
private void btnNextPage_Click(object sender, EventArgs e)
{
if (page < pageCount) page++;
SetButtons(page);
}
}

Why does my dynamically created GroupBox place its RadioButtons too far right on subsequent usages?

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;
}
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.
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)
});
}
}
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
}

C# How to define event for dynamically created control?

I have written a code that create buttons dynamically. The code works well, and create controls when I click on a button. Now the next task is, I want to define click event for these dynamically created controls. How can I do this ? Below is the code, Please modify this code and paste in a reply, so that I can understand easily.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// create controls dynamically on form
int n = 4;
private void btnDisplay_Click_1(object sender, EventArgs e)
{
Button[] button = new Button[n];
int previousButtonPositionY;
int previousButtonHeight;
for (int i = 0; i < n; i++)
{
button[i] = new Button();
button[i].Name = "btnButton" + i;
button[i].Text = "btnButton" + i;
if (i > 0)
{
previousButtonPositionY = button[i - 1].Location.Y;
previousButtonHeight = button[i - 1].Height;
}
else
{
previousButtonPositionY = 50;
previousButtonHeight = 0;
}
button[i].Location = new Point(0, previousButtonPositionY + previousButtonHeight);
}
for (int i = 0; i < n; i++)
{
panel1.Controls.Add(button[i]);
}
}
}
After you have initialized your button you can add an onclick event to it with
button[i].Click += new EventHandler(button_Click);
More here: http://msdn.microsoft.com/en-us/library/ms743596%28v=vs.110%29.aspx

Categories