WARNING: Embedded software delevoper trying to build PC software!
I'm trying to interface a piece of hardware that communicates with the PC via serial interface. The PC software (C#) periodicaly sends a byte array, which I would like to adjust using some trackbars.
Instead of adding 8 trackbars on the design view, I add one to help me align it and then I create a List which I populate on load like so:
public partial class FormDmxTemplate : Form
{
// Controls
// Create a list of tracbars.
List<TrackBar> trackBarDmx = new List<TrackBar>();
public FormDmxTemplate()
{
InitializeComponent();
}
private void FormDmxTemplate_Load(object sender, EventArgs e)
{
// Add first instance on the list
trackBarDmx.Add(trackBarDmx1);
// Generate 7 more, 8 total, of each
// Copy settings, and place them next to each other
for (int i = 1; i < 8; i++)
{
// Trackbars
trackBarDmx.Add(new TrackBar());
trackBarDmx[i].TickStyle = trackBarDmx[0].TickStyle;
trackBarDmx[i].Orientation = trackBarDmx[0].Orientation;
trackBarDmx[i].Minimum = trackBarDmx[0].Minimum;
trackBarDmx[i].Maximum = trackBarDmx[0].Maximum;
trackBarDmx[i].Size = new System.Drawing.Size(trackBarDmx[0].Size.Width, trackBarDmx[0].Size.Height);
trackBarDmx[i].Location = new System.Drawing.Point(trackBarDmx[i-1].Location.X + 60, trackBarDmx[0].Location.Y);
this.Controls.Add(trackBarDmx[i]);
}
}
}
Is it possible to have events for all the List members like this one?
private void trackBarDmx1_Scroll(object sender, EventArgs e)
{
}
Which means I'd like update the relevant byte in my byte array to match the TrackBar value, using events if possible.
NOTE: This is a form template which I load and close via another form.
You can subscribe to the events when creating the TrackBars. All can have the same event handler:
trackBarDmx[i].Scroll += trackBarDmx1_Scroll;
Then in the handler you can find out which is this TrackBar and at which index it is (if necessary)
private void trackBarDmx1_Scroll(object sender, EventArgs e)
{
TrackBar bar = sender as TrackBar;
int trackBarIndex = this.trackBarDmx.IndexOf(bar);
}
Not sure if I understood what you are trying to achieve. Does this do what you need:
for (int i = 0; i < 7; i++)
{
TrackBar trackBar = new TrackBar();
trackBar.Tag = i;
// Other properties
trackBar.Scroll += new EventHandler(trackBar_Scroll);
}
In the handler:
void trackBar_Scroll(object sender, EventArgs e)
{
// Get the trackbar
TrackBar current = sender as TrackBar;
// Do something here. Use tag property to identify which byte array should be changed
}
BTW, do you really need to retain the list of TrackBar?
You can do this :
for (int i = 1; i < 8; i++)
{
// Trackbars
trackBarDmx.Add(new TrackBar());
trackBarDmx[i].TickStyle = trackBarDmx[0].TickStyle;
trackBarDmx[i].Orientation = trackBarDmx[0].Orientation;
trackBarDmx[i].Minimum = trackBarDmx[0].Minimum;
trackBarDmx[i].Maximum = trackBarDmx[0].Maximum;
trackBarDmx[i].Size = new System.Drawing.Size(trackBarDmx[0].Size.Width, trackBarDmx[0].Size.Height);
trackBarDmx[i].Location = new System.Drawing.Point(trackBarDmx[i-1].Location.X + 60, trackBarDmx[0].Location.Y);
this.Controls.Add(trackBarDmx[i]);
// Notice no number in the handler name
trackBarDmx[i].Scroll += trackBarDmx_Scroll;
}
Now in the handler the simplest thing to do would be :
private void trackBarDmx_Scroll(object sender, EventArgs e)
{
var tb = sender as TrackBar;
if(sender == null)
{return;}
switch (sender.Name)
{
case "trackBarDmx1_Scroll" :
// handle changes to bar 1
break;
// and so on
}
}
Related
I´m using WindowsForm and working with flat design. In the program there are 6 buttons, these buttons are made of a label and a panel. The label controls all the actions that the button can do. when i started writing the program i made one function for each button, now i like to use one function that controls all buttons. I have tried to make that work but I´m stuck and can´t find a way to solve it.
Been looking around at the forum for solutions but i think that i might not know what i´m looking for.
This is what i made so far.
Buttons[] cobra = new Buttons[5];
private class Buttons
{
private bool position;
private string name;
public bool Position
{
get { return position; }
set { position = value; }
}
public string Name
{
get { return name; }
set { name = value; }
}
}
private void SetButtons()
{
cobra[0].Name = "label3";
cobra[0].Position = false;
cobra[1].Name = "label4";
cobra[1].Position = false;
}
private void CheckStatusButtons(object import)
{
for (int i = 0; i < cobra.Length; i++)
{
}
}
private class ToggelFunction
{
private bool hawk;
public bool Hawk
{
get { return hawk; }
set { hawk = value; }
}
}
ToggelFunction tiger = new ToggelFunction();
private void label3_Click(object sender, EventArgs e)
{
if (tiger.Hawk == false)
{
button1.BackColor = Color.PaleGreen;
label3.Text = "ON";
if (myport.IsOpen)
{
send(new byte[] { 16, 128, 32, 16, 1 });
}
tiger.Hawk = true;
return;
}
if (tiger.Hawk == true)
{
button1.BackColor = Color.DarkSeaGreen;
label3.Text = "2";
if (myport.IsOpen)
{
send(new byte[] { 16, 128, 32, 8, 1 });
}
tiger.Hawk = false;
return;
}
}
"label3_Click" this is my function for button 1, all buttons look the same just different variables.
As I found on the forum, you can use object sender to i identify which button that made the click and from there use that in the function to make action.
So all buttons will use this functions, i´m not sure how to compare values in the if statement, if button 1 is click then it should check what values button 1 has.
My idea was to make a class "Buttons" and an array to store all the values of each button, it´s not completed yet. When a button is clicked it checks
with the array what values that button has and compare that in the function depending on what the action is. The first action would be to check if the button is on or off. If it´s off then it enters that if statement and there some actions will happen, change of color and the text, these values also have to be stored in the array i guess.
I have tried to compare the array with object sender, but i get some error saying that you can´t compare bool with object i think.
So i wonder if some one might have a solution or suggestions?
I have made a simple example of what i think you want to do. bare in mind this does not abide by all coding best practises but its not a mess either. You will need to put your safety null checks in.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public class ButtonVariables
{
public int value1 { get; set; }
public int value2 { get; set; }
}
Dictionary<string, ButtonVariables> bv = new Dictionary<string, ButtonVariables>();
private void ProcessClick(object sender, EventArgs e)
{
ButtonVariables vars = GetVariables(sender);
//Do stuff with your variable set here
}
private ButtonVariables GetVariables(object sender)
{
ButtonVariables returnValue = new ButtonVariables();
switch (((Button)sender).Name.ToLower())
{
case "buttona":
return bv["A"];
case "buttonb":
return bv["B"];
case "buttonc":
return bv["C"];
default:
break;
}
return null;
}
private void ButtonA_Click(object sender, EventArgs e)
{
ProcessClick(sender, e);
}
private void ButtonB_Click(object sender, EventArgs e)
{
ProcessClick(sender, e);
}
private void ButtonC_Click(object sender, EventArgs e)
{
ProcessClick(sender, e);
}
}
I've basically added two methods to handle your method. One to identify the button and get its related values from a dictionary that you will have to populate with your Buttons class. and one to carry out the logic.
EDIT
As requested in the comments here's an easy (but not the only way) to point your event listeners towards the same method.
Initially you need to set up with one button and double click it or do some other way to create the forms Button_Click() Event Method. At this point an event listener delegate has been added to your Form.Designer.cs File. Open that file and you will see something like this:
//
// ButtonA
//
this.ButtonA.Location = new System.Drawing.Point(12, 12);
this.ButtonA.Name = "ButtonA";
this.ButtonA.Size = new System.Drawing.Size(75, 23);
this.ButtonA.TabIndex = 0;
this.ButtonA.Text = "button1";
this.ButtonA.UseVisualStyleBackColor = true;
this.ButtonA.Click += new System.EventHandler(this.ButtonA_Click);
What you need to do is create your other buttons and add this code in for them with a change to the last line new System.EventHandler(this.ButtonA_Click); This line basically states which method to call when the ButtonA.Click event is invoked. At this point you can add what ever method you want (as long as you name is nicely for good convention). So your example would be this :
//
// ButtonA
//
this.ButtonA.Location = new System.Drawing.Point(12, 12);
this.ButtonA.Name = "ButtonA";
this.ButtonA.Size = new System.Drawing.Size(75, 23);
this.ButtonA.TabIndex = 0;
this.ButtonA.Text = "button1";
this.ButtonA.UseVisualStyleBackColor = true;
this.ButtonA.Click += new System.EventHandler(this.ProcessClick);
//
// ButtonB
//
this.ButtonB.Location = new System.Drawing.Point(12, 12);
this.ButtonB.Name = "ButtonB";
this.ButtonB.Size = new System.Drawing.Size(75, 23);
this.ButtonB.TabIndex = 0;
this.ButtonB.Text = "B";
this.ButtonB.UseVisualStyleBackColor = true;
this.ButtonB.Click += new System.EventHandler(this.ProcessClick);
//
// ButtonC
//
this.ButtonC.Location = new System.Drawing.Point(12, 12);
this.ButtonC.Name = "ButtonC";
this.ButtonC.Size = new System.Drawing.Size(75, 23);
this.ButtonC.TabIndex = 0;
this.ButtonC.Text = "C";
this.ButtonC.UseVisualStyleBackColor = true;
this.ButtonC.Click += new System.EventHandler(this.ProcessClick);
Remember you need to physically create the buttons on the form itself.
Lets say you have three labels and a panel for each label. You can add the event handler to all of them and whenever that event fires the event handler will use that label as the sender. To keep the panel associated with the label, you could add the panel to the label's tag property. Then, in the event handler you can then get the panel from the label.
label1.Click += label_Click;
label2.Click += label_Click;
label3.Click += label_Click;
label1.Tag = panel1;
label2.Tag = panel2;
label3.Tag = panel3;
In the event handler, just cast sender to Label and there you have your label object to do whatever you want with and like I said, the panel is in the Tag property. I did a little refactoring to your code to make it cleaner looking.
private void label_Click(object sender, EventArgs e)
{
// this is what itsme86 was suggesting in the comments
var label = (Label)sender;
var panel = (Panel)label.Tag;
label.BackColor = tiger.Hawk ? Color.DarkSeaGreen : Color.PaleGreen;
label.Text = tiger.Hawk ? "2" : "ON";
if (myport.IsOpen)
send(new byte[] { 16, 128, 32, 8, 1 });
tiger.Hawk = !tiger.Hawk;
}
Let me know if you have any questions about this.
So I was trying to send custom arguments to an event, but it never worked, I tried so many different methods, but I never got it to work,
So basically!
public void CreateEmojiList()
{
CreateAllEmojis();
int btnCount = 0;
foreach(Emoji emoji in emojiList)
{
Button btnEmoji = new Button();
btnEmoji.Size = new Size(40, 36);
btnEmoji.FlatStyle = FlatStyle.Flat;
btnEmoji.FlatAppearance.MouseDownBackColor = Color.Cyan;
btnEmoji.Cursor = Cursors.Hand;
btnEmoji.Font = new Font("Bahnschrift", 6.75f);
btnEmoji.Text = emoji.EmojiText;
btnEmoji.Top = (panel_main.Controls.OfType<Button>().Count<Button>() / 4) * (1 + btnEmoji.Height) + 6;
btnEmoji.Left = (btnEmoji.Width + 1) * btnCount + 6;
panel_main.Controls.Add(btnEmoji);
btnEmoji.Click += //What do I do here?
; btnCount++;
if (btnCount == 4)
btnCount = 0;
}
}
protected virtual void OnEmojiClick(EmojiClickEventArgs e)
{
if (this.EmojiClick != null)
EmojiClick(e);
}
this is the class I want to use to pass my arguments:
public class EmojiClickEventArgs : EventArgs
{
private string emojiText;
private string emojiName;
public EmojiClickEventArgs(string EmojiText, string EmojiName)
{
this.EmojiText = EmojiText;
this.EmojiName = EmojiName;
}
public string EmojiText { get { return emojiText; } set { emojiText = value; } }
public string EmojiName { get { return emojiName; } set { emojiName = value; } }
}
I want to get those two values from
emoji.EmojiText and emoji.EmojiName
You can take advantage of closures to "package up" the additional event data for each button's event handler. Just make sure not to close over the loop variable.
public void CreateEmojiList()
{
CreateAllEmojis();
int btnCount = 0;
foreach(Emoji emoji in emojiList)
{
Button btnEmoji = new Button();
btnEmoji.Size = new Size(40, 36);
btnEmoji.FlatStyle = FlatStyle.Flat;
btnEmoji.FlatAppearance.MouseDownBackColor = Color.Cyan;
btnEmoji.Cursor = Cursors.Hand;
btnEmoji.Font = new Font("Bahnschrift", 6.75f);
btnEmoji.Text = emoji.EmojiText;
btnEmoji.Top = (panel_main.Controls.OfType<Button>().Count<Button>() / 4) * (1 + btnEmoji.Height) + 6;
btnEmoji.Left = (btnEmoji.Width + 1) * btnCount + 6;
panel_main.Controls.Add(btnEmoji);
var emojiCopy = emoji; //don't close on the loop variable!
btnEmoji.Click += (sender,args) => OnEmojiClick(emojiCopy);
btnCount++;
if (btnCount == 4)
btnCount = 0;
}
}
protected virtual void OnEmojiClick(Emoji emoji)
{
//do something
}
One way is to inherit from Button and create a class called EmojiButton. You then declare a delegate that matches the signature of the your event handler. After that, declare an event using the delegate in the EmojiButton class, add property like EmojiText and EmojiName to the button subclass as well. Finally you need to link the button click event with your custom event. Whenever the button is clicked, raise your event and pass your arguments i.e. this.EmojiText, this.EmojiName.
Another way is to assign your Emoji objects to the Tag property. You can then write the event handler with the normal EventHandler signature (object sender, EventArgs e), and look at what the sender's Tag is. You then cast the Tag to an Emoji and access its properties.
The fastest solution that comes to my mind and that doesn't imply the definition of custom UserControl classes, the subclassing of Button and other similar practices is:
btnEmoji.Click += (sender, e) =>
{
Button b = (Button)sender;
// let's suppose that the button name corresponds to the emoji name
String emojiName = b.Name;
// let's suppose that the button tag contains the emoji text
String emojiText = (String)b.Tag;
Emoji_Clicked(sender, e, (new EmojiClickEventArgs(emojiText, emojiName)));
};
private void Emoji_Clicked(Object sender, EventArgs e, EmojiClickEventArgs ee)
{
// Your code...
}
First and foremost thing you need to define delegate ,then create an instance.
class Emojis
{
// public delegate void EmojiClickEventHandler(object sender,EventArgs args);
//public event EmojiEventHandler EmojiClicked;
//you can use above two lines or replace them instead below code.
public event EventHandler<EmojiClickEventArgs> EmojiClicked;
public void CreateEmojiList()
{
CreateAllEmojis();
int btnCount = 0;
//rest of the code
panel_main.Controls.Add(btnEmoji);
btnEmoji.Click += OnEmojiClick(btnEmoji);
btnCount++;
}
protected virtual void OnEmojiClick(Button emoji)
{
//Here null check to handle if no subscribers for the event
if(EmojiClicked!=null)
{
//there is no name property define for emoji but only text hence passing only text.
EmojiClicked(this ,new EmojiClickEventArgs(emoji.Text,emoji.Text){ });
}
}
private void Emoji_Clicked(Object sender, EmojiClickEventArgs args)
{
Button mybutton = sender as Button;
Console.WriteLine("emoji text "+ args.Text);
}
}
Bear with me, I'm new to Stack Overflow, but have used it as a resource for a long time when researching methods of programming that I'm not fond with.
I read up a tutorial on how to create a graph in a C# Windows Forms Application, and was attempting to find out how to make it update itself in real-time if I ever need to use the graph to plot the total amount of data in a sensor. To test it out, I'm using a timer, ticking at every second (1000ms). And before I can use this with a sensor, I'm having two values automatically increment by 1.
The current problem I'm facing is that the chart itself won't update, and only stays the way it was drawn when the form loaded. I thought it was because I have to redraw the chart with chart1.Update();, and I tried using that before/after recreating the chart every second. However, the result is the same regardless. I just wondered if there's something I haven't done or needs to be changed in order to update the chart in real-time.
This is where the code is at currently:
public partial class Form1 : Form
{
int a = 1;
int b = 2;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Data arrays.
string[] seriesArray = { "Cats", "Dogs" };
int[] pointsArray = { a, b };
// Set palette.
this.chart1.Palette = ChartColorPalette.SeaGreen;
// Set title.
this.chart1.Titles.Add("Pets");
// Add series.
for (int i = 0; i < seriesArray.Length; i++)
{
// Add series.
Series series = this.chart1.Series.Add(seriesArray[i]);
// Add point.
series.Points.Add(pointsArray[i]);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
a++;
b++;
// Data arrays.
string[] seriesArray = { "Cats", "Dogs" };
int[] pointsArray = { a, b };
// Set palette.
this.chart1.Palette = ChartColorPalette.SeaGreen;
// Set title.
this.chart1.Titles.Add("Pets");
// Add series.
for (int i = 0; i < seriesArray.Length; i++)
{
// Add series.
Series series = this.chart1.Series.Add(seriesArray[i]);
// Add point.
series.Points.Add(pointsArray[i]);
}
chart1.Update();
}
}
Your code has several problems:
The timer click event is not hooked up. I know that it isn't because otherwise you'd get an exception telling you that..
..you can add a series only once. You were doing it on each timer.Tick. This and all other setup commands should go into an initial method like the form load.
I have corrected the errors in the code below, but, obviously, the data don't make any sense yet.
Also: While I have added code to hook up the timer.Tick, the button.Click is not hooked up. Usually you let the designer do this by double-clicking the control to hook up the standard event of a control or by double-clicking the event in the control's event tab in the property page.
int a = 1;
int b = 2;
string[] seriesArray = { "Cats", "Dogs" };
private void Form1_Load(object sender, EventArgs e)
{
// Set palette.
this.chart1.Palette = ChartColorPalette.SeaGreen;
// Set title.
this.chart1.Titles.Add("Pets");
// Add series
this.chart1.Series.Clear();
for (int i = 0; i < seriesArray.Length; i++)
{
chart1.Series.Add(seriesArray[i]);
}
// hook up timer event
timer1.Tick += timer1_Tick;
}
private void timer1_Tick(object sender, EventArgs e)
{
a++;
b++;
// Data array
int[] pointsArray = { a, b };
for (int i = 0; i < seriesArray.Length; i++)
{
// Add point.
chart1.Series[i].Points.Add(pointsArray[i]);
}
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
The code:
pbs = new PictureBox[8];
for (int i = 0; i < pbs.Length; i++)
{
pbs[i] = new PictureBox();
pbs[i].MouseEnter += Form1_MouseEnter;
pbs[i].MouseLeave += Form1_MouseLeave;
pbs[i].Size = new Size(100, 100);
pbs[i].Margin = new Padding(0, 0, 0, 60);
pbs[i].Dock = DockStyle.Top;
pbs[i].SizeMode = PictureBoxSizeMode.StretchImage;
Panel p = i < 4 ? panel1 : panel2;
p.Controls.Add(pbs[i]);
pbs[i].BringToFront();
}
I did:
pbs[i].MouseEnter +=
And when i clicked TAB it did: Form1_MouseEnter
It's not what i wanted.
I want that when i move with the mouse over each of the pictureBoxes area it will do something.
One event for all the pictureBoxes.
If i moved over pictureBox1 do something...pictureBox2 the same...
How can i do it ? I don't want to create 8 events for each pictureBox but one enter event for all.
You need simply write
pbs[i].MouseEnter += globalMouseEnterEvent;
of course you need to have a globalMouseEnterEvent somewhere in your code
public void globalMouseEnterEvent(object sender, System.EventArgs e)
{
....
}
However, another piece of information is needed when your work with event shared between numerous controls. You need to recognize the control that triggers the event. The control instance is passed using the sender parameter that you can cast to your appropriate control type, but what is needed is to give a unique identifier to your control. Like setting the Tag or Name properties when you build the control
for (int i = 0; i < pbs.Length; i++)
{
.....
pbs[i].Tag = "PB" + i.ToString()
...
}
so in the MouseEnter code you could write
public void globalMouseEnterEvent(object sender, System.EventArgs e)
{
PictureBox p = sender as PictureBox;
if(p.Tag.ToString() == "PB1")
.....
else if ......
}
dont use form1_event , copy it's code and rename it
pbs[i].MouseEnter += yourEventName
it's enough
What you're doing is absolute correct, you attach the handler to the event of each control in
turn, so that the same handler works for every PictureBox.
I guess your problem is that the method VS creates is named Form1_MouseEnter. This is completely irrelevant, what determines what a method will handle is the += operator, not its name. Just try to run your original code and it will do what you want.
It seems to be a bug in the C# editor though, as it should have named the automatically generated handler something more appropriate, but anyway, you can rename the method afterwards to reflect its true meaning.
I've tried to apply the tips from the others to your code:
pbs = new PictureBox[8];
for (int i = 0; i < pbs.Length; i++)
{
pbs[i] = new PictureBox();
pbs[i].MouseEnter += Picturebox_MouseEnter;
pbs[i].MouseLeave += PictureBox_MouseLeave;
pbs[i].Name = string.Concat("PB", i); //Added to identify each picturebox
pbs[i].Size = new Size(100, 100);
pbs[i].Margin = new Padding(0, 0, 0, 60);
pbs[i].Dock = DockStyle.Top;
pbs[i].SizeMode = PictureBoxSizeMode.StretchImage;
Panel p = i < 4 ? panel1 : panel2;
p.Controls.Add(pbs[i]);
pbs[i].BringToFront();
}
And the handlers:
private void Picturebox_MouseEnter(object sender, EventArgs e)
{
PictureBox pb = sender as PictureBox;
if (pb != null)
{
if (pb.Name == "PB2")
{
//Do PB2 specific task
}
//Your code when mouse enters one of the pictureboxes
//Use Name property to determine wich one, if needed
}
}
private void PictureBox_MouseLeave(object sender, EventArgs e)
{
//Your code when mouse leaves one of the pictureboxes
//Use Name property to determine wich one, if needed
}
I create array:
TextBox[] textarray = new TextBox[100];
Then in cycle set this params, all items array situated in uniformGrid1
textarray[i] = new TextBox();
textarray[i].Height = 30;
textarray[i].Width = 50;
uniformGrid1.Children.Add(textarray[i]);
How create events Click or DoubleClick that all items array?
Sorry my English.
public static void blah()
{
TextBox[] textarray = new TextBox[100];
List<TextBox> textBoxList = new List<TextBox>();
for (int i = 0; i < textarray.Length; i++)
{
textarray[i] = new TextBox();
textarray[i].Height = 30;
textarray[i].Width = 50;
// events registration
textarray[i].Click +=
new EventHandler(TextBoxFromArray_Click);
textarray[i].DoubleClick +=
new EventHandler(TextBoxFromArray_DoubleClick);
}
}
static void TextBoxFromArray_Click(object sender, EventArgs e)
{
// implement Event OnClick Here
}
static void TextBoxFromArray_DoubleClick(object sender, EventArgs e)
{
// implement Event OnDoubleClick Here
}
EDIT:
A better / recommended way of event registration as per #Aaronaugh: advice:
textarray[i].Click += TextBoxFromArray_Click;
textarray[i].DoubleClick += TextBoxFromArray_DoubleClick;
Just add in your click or double click event handler. For example, to trap double click events:
textarray[i] = new TextBox();
textarray[i].Height = 30;
textarray[i].Width = 50;
textarray[i].MouseDoubleClick += this.OnMouseDoubleClick;
uniformGrid1.Children.Add(textarray[i]);
For the above to work, you class will need a method like:
void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// Do something
}
Create a click event handler and then use it to subscribe to the click events of your textboxes, like so:
textarray[i].Click += new EventHandler(textbox_Click);
...
void textbox_Click(object sender, EventArgs e)
{
// do something
}
If the actions you want to take are the same for each textbox, then one click handler will suffice.