C# Enlarge Button When Mouse Cursor Point to it - c#

C#.I have 18 buttons to select, but before I will choose a selection. How to enlarge Button with BackgroundImage when mouse point in it? It's like ToolTip, when you point the cursor it will show the Text. But in my case, it will enlarge the Button. Thanks
Button[] ButtonSelect = new Button[17];
for (i = 1; i <= 18; i++)
{
ButtonSelect[i] = new Button();
ButtonSelect[i].BackgroundImage = Properties.Resources.SelectImages[i];
}

Make the size of the Button grow larger in MouseEnter event:
Button btn = (Button)sender;
int width = btn.Size.Width;
int height = btn.Size.Height;
int larger = 10;
btn.Size = new Size(width + larger, height + larger);
Then in the MouseLeave event do the opposite by shrinking the button size.
You can hook up the events like this:
for (i = 1; i <= 18; i++)
{
ButtonSelect[i] = new Button();
ButtonSelect[i].BackgroundImage = Properties.Resources.SelectImages[i];
ButtonSelect[i].MouseEnter += new System.EventHandler(Btn_MouseEnter);
ButtonSelect[i].MouseLeave += new System.EventHandler(Btn_MouseLeave);
}

Related

Don't know how to get index from button list C# winForms

I am writing a program code for creating graphs from graph theory.
Clicking on a grid generates a graph node with the corresponding index. Buttons are generated on the right. I want the nodes to be connected by an edge when the button is clicked. For example, when you click on the button on line 1 and column 2, an edge will be drawn connecting circles 1 and 2.
enter image description here
Button generation code
List<Button> btnList = new List<Button>();
for (int z = 1; z <= count; z++)
{
for (int x = 1; x <= count; x++)
{
Button btn = new Button();
btn.Text = 0.ToString();
btn.Location = new Point(z*30, x*30);
btn.Size = new System.Drawing.Size(30, 30);
btn.BackColor = System.Drawing.Color.White;
btn.MouseClick += new System.Windows.Forms.MouseEventHandler(btnClick);
panel1.Controls.Add(btn);
btnList.Add(btn);
}
}
The code of the event describing the click of the button
public void btnClick(object sender, EventArgs e)
{
Button button = (Button)sender;
button.Text = (int.Parse(button.Text)+1).ToString();
Graphics g = Graphics.FromImage(bmp);
Pen pen = new Pen(Color.Black);
//g.DrawLine(pen, );
pictureBox1.Image = bmp;
}
Maybe the question is very stupid, but I do not understand how to refer to the indexes of the pressed button in the btnClick function.
You have, for every object in C#, a Tag property which is free. You can use it to store the coordinates of your button.
So, insert before you add the btn to the panel1.Controls, something like:
btn.Tag = new Point(z, x);
Then, in the btnClick delegate, to get back your coordinates, you use something like:
Button button = sender as Button;
Point p = button.Tag;
int z = p.X;
int x = p.Y;
You can keep the Button button = (Button)sender; The only difference is that casting can throw an exception but the keyword 'as' can't.
As I am writing this, I see the new comments and your reply. Tag isn't in the delegates like KeyDown but with the properties like Location, Size, Text, etc.
You already store z and x:
btn.Location = new Point(z*30, x*30);
You can do this in the click handler to retrieve them:
int z = button.Location.X / 30;
int x = button.Location.Y / 30;
Thanks for answers.
I add code when generation buttons
btn.Tag = new Point(z, x);
and i use btn.Tag when click on button
Point p = (Point)button.Tag;
int z = p.X;
int x = p.Y;

How do you make AutoSize happen immediately?

The problem
I'm dynamically adding Buttons to the WinForm. As I do so, I'm repositioning existing Buttons to prevent overlap. The AutoSize property is being used to automatically set Width.
For longer text (that pushes Buttons beyond their default Width), the below code doesn't work.
For example:
b.Width is 75 before AutoSize is set
b.Width is 75 after AutoSize is set
When shifting other Buttons, it shifts them by b.Width + buffer = 83
However after addButton()completes, the AutoSize kicks in and sets the width to 150, overlapping the next Button which is only 83 pixels away instead of 158.
AutoSize appears to change the size of the control too late for it to be of use. How can I make it happen immediately?
Attempt 1 - Code
public void addButton(string text)
{
const int buffer = 8;
//Construct new button
Button b = new Button();
b.Text = text;
b.AutoSize = true;
b.Location = new Point(0, 0);
//Shift over all other buttons to prevent overlap
//b.Width is incorrect below, because b.AutoSize hasn't taken effect
for (int i = 0; i < Controls.Count; i++)
if (Controls[i] is Button)
Controls[i].Location = new Point(Controls[i].Location.X + b.Width + buffer, Controls[i].Location.Y);
Controls.add(b);
}
Attempt 2
Searched Google and StackOverflow for the following:
c# autosize immediately
c# autosize fast
c# autosize not working
Attempt 3
Asking here.
Last Resort
If nothing else works, a timer could be set to reposition Buttons on each tick. However this is very sloppy design, and doesn't aid in learning the intricacies of AutoSize. I'd like to avoid this workaround if possible.
The AutoSize and AutoSizeMode mode are applied only when the control is parented to the another control or form.
So invoke first
Controls.Add(b);
Now the b.Size will the adjusted accordingly and can be used in the calculations.
Alternatively, instead of Size property you can use the GetPreferredSize method to get the correct size without actually applying AutoSize and use it inside the calculations:
var bSize = b.GetPreferredSize(Size.Empty);
//Shift over all other buttons to prevent overlap
//b.Width is incorrect below, because b.AutoSize hasn't taken effect
for (int i = 0; i < Controls.Count; i++)
if (Controls[i] is Button)
Controls[i].Location = new Point(Controls[i].Location.X + bSize.Width + buffer, Controls[i].Location.Y);
The FlowLayoutPanel control does this work for you.
Place one on your form and try adding buttons in the following manner:
Button b = new Button();
b.AutoSize = true;
b.Text = text;
flowLayoutPanel1.SuspendLayout();
flowLayoutPanel1.Controls.Add(b);
flowLayoutPanel1.Controls.SetChildIndex(b, 0);
flowLayoutPanel1.ResumeLayout();
You can subscribe to the Resize event of the last button added. This will allow you to accurately change the locations of all of the buttons because now all of the buttons have been AutoSized.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var button1 = NewButton(0);
button1.Location = new Point(10, 10);
var button2 = NewButton(1);
button2.Location = new Point(button1.Right, 10);
var button3 = NewButton(2);
button3.Location = new Point(button2.Right, 10);
button3.Resize += (s, e) =>
{
button2.Location = new Point(button1.Right, 10);
button3.Location = new Point(button2.Right, 10);
};
Controls.Add(button1);
Controls.Add(button2);
Controls.Add(button3);
}
private Button NewButton(int index)
{
return new Button()
{
Text = "ButtonButtonButton" + index.ToString(),
AutoSize = true
};
}
}

how to navigate among the buttons with the arrow keys

I have some buttons which is created dynamically in my winform , on which the first button should be selected by default and the rest of the buttons should be selected clicking the down and up arrows.
for (int i = 0; (i < 5); i++)
{
Button btn = new Button();
btn.Width *= 2;
btn.Height *= 2;
yPos = yPos + btn.Height + space;
Point p = new Point();
p.X = xPos;
p.Y = yPos;
btn.Location = p;
this.Controls.Add(btn);
}
the buttons is displayed in a row style and clicking on down arrow should select the next immediate button and like that.
Please help me what can i write in the keypress event
Add your Button to a List<Button> BtnList, define a index int current = 0.
When keypress
if(current == BtnList.Length)
{
current = 0;
}
else
{
BtnList[current].Focus();
current += 1;
}

c# changing name of controls in for loop

I'm making a program that will make buttons on the screen from a for loop. This is important because the user needs to have access to the number of buttons, and could change with every run. This is the code i have so far:
public Form1()
{
InitializeComponent();
int top = 5;
int left = 5;
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Height = 50;
button.Left = left;
button.Top = top;
this.Controls.Add(button);
left += button.Width + 2;
}
}
What i want is basically something like this:
Button b+i = new Button();
Its like when combining two strings, i want the name of the button on the first run in the loop to be b0, then b1, then b2, and so on.
I use Visual Studio, and InitializeComponent() goes to the editor generated code to make the window and stuff. nothing but the window is made there.
Thank you for your help!
Worrying about the variable names is the wrong way to approach this problem. There are several alternatives:
Use a list
List<Button> buttons;
public Form1()
{
InitializeComponent();
buttons = new List<Button>();
int top = 5;
int left = 5;
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Height = 50;
button.Left = left;
button.Top = top;
this.Controls.Add(button);
buttons.Add(button);
left += button.Width + 2;
}
}
//now instead of 'b1', it's 'buttons[1]'
Which you could also create with the OfType() method:
var buttons = this.Controls.OfType<Button>().ToList();
These can be done in combination with a FlowLayoutPanel or TableLayoutPanel to simplify the code:
public Form1()
{
InitializeComponent();
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Height = 50;
FlowLayoutPanel1.Controls.Add(button); //panel handles Left/Top location
}
}
The panel also has the advantage of helping your app scale at different dpi's or screen/window sizes.
Any of which could also be adapted to start thinking in terms of connecting to a datasource (and reduce the code):
var buttons = Enumerable.Range(0, 10).Select(b => new Button {
Height = 50,
Left = 5 + ( b * (BUTTONWIDTH + 2) ),
Top = 5,
Name = String.Format("Button{0}", b)
});
//buttons.ToList()
//or
//this.Controls.AddRange(buttons.ToArray())
//or
//FlowLayoutPanel1.Controls.AddRange(buttons.ToArray()) //Remove Left/Top code
But all of this is meaningless until you can get the buttons to actually do something. You need an event handler for (at least) the Click event:
foreach (var b in butons)
{
b.Click += (s,e) =>
{
//click code for all of the buttons goes here
// you can tell the buttons apart by looking at the "s" variable
};
}
since people (rightly) said 'use an array' here is code
public Form1()
{
InitializeComponent();
int top = 5;
int left = 5;
var buttons = new Button[10];
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Height = 50;
button.Left = left;
button.Top = top;
this.Controls.Add(button);
left += button.Width + 2;
buttons[i] = button;
}
}

create buttons Dynamically on a panel

Looking through the way for create buttons dynamically on a panel
I tried this.
int top = 50;
int left = 100;
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Left = left;
button.Top = top;
this.Controls.Add(button);
top += button.Height + 2;
}
but I don't know how to put them on panel
Instead of adding buttons to form controls, add them to panel controls (I believe this is your form or user control):
int top = 50;
int left = 100;
for (int i = 0; i < 10; i++)
{
Button button = new Button();
button.Left = left;
button.Top = top;
panel.Controls.Add(button); // here
top += button.Height + 2;
}
UPDATE: for handling button click events, you should subscribe all buttons for single event handler (when you create button):
button.Click += Button_Click;
And in event handler you can use sender to see which button raised event:
private void Button_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
// you have instance of button
// ...
}

Categories