I am working on a piano in C#. I have encountered a small problem.
I have a piano keyboard which, when pressed, displays the relevant note on the staff.
The notes created are stored in an array of type PictureBox, called picBox. I have constructed the following event handler, however it is not working.
private void pictureBox_Click(object sender, MouseEventArgs e)
{
picBox[0].MouseDown += new MouseEventHandler(pic_Click); //testing for first location
}
private void pic_Click(object sender, MouseEventArgs e)
{
ClickedTextBox.Text = "I was clicked";
}
I am just testing to see if the first note was clicked. Why is this not working?
Here is the method which adds the picturebox (containing the note) to the staff (panel3).
public void addPictureBox(int x, int y, Image image)
{
picBox[cnt] = new PictureBox();
picBox[cnt].Image = image;
picBox[cnt].Location = new Point(x, y);
picBox[cnt].BackColor = Color.Transparent;
panel3.Controls.Add(picBox[cnt]);
picBox[cnt].BringToFront();
cnt++;
}
What is wrong with my event handler please? Also, what can I do to identify the location in the array of the picturebox clicked? Thank you
As said in the first comment, you subscribe to the event in a wrong location.
Also use the sender parameter of your event handler to know which picturebox is clicked (it'll contain an instance of the picturebox).
Related
Visual Studio C #
I made a calculator, and now I have to make a calculator memory (event).
There are 4 components other than the calculator: one Textbox for the answer of the calculator, two Buttons for "M" and "M+", and one Lable to display the answer again.
When the user clicks the “M” button, the contents of the Answer TextBox should be copied to a memory variable. Also make it so that when the user moves the mouse over the label, the value in the memory variable will appear in this label, and then disappear, when the mouse moves away from the label. Also add one more button, an “M+” button. When the user clicks this button, the contents of the Results box will be added to Memory. You will need to use a Global Variable to store this data.
My problem is that the label doesn't appear when the mouse over the label, and also it doens't disappear when the mouse leave the label. How can I fix it?
And also, is this way the right way to use the Global variable?
Below is my code (I just put the code for "M" and "M+" buttons, not the code for the calculator).
private String ans;
private Double answer;
private Double answerPlus;
private void btnM_Click(object sender, EventArgs e)
{
ans = txtDisplay.Text;
answer = double.Parse(ans);
lblblank.Text = answer.ToString();
}
private void lblblank_MouseEnter(object sender, EventArgs e)
{
lblblank.Show();
lblblank.Text = answer.ToString();
}
private void lblblank_MouseLeave(object sender, EventArgs e)
{
lblblank.Hide();
}
private void btnMplus_Click(object sender, EventArgs e)
{
answerPlus = answer + double.Parse(ans);
lblblank.Text = answerPlus.ToString();
}
Storing variables
The way you store your values is fine.
Events
Once you call .Hide() the next MouseEnter/MouseLeave-event will not be triggered anymore. What you could do is to take a panel, or any layout element as a wrapper/parent-element for the label and then adjust your event-callbacks to something like that:
private void panel_MouseEnter(object sender, EventArgs e)
{
lblblank.Show();
lblblank.Text = answer.ToString();
}
private void panel_MouseLeave(object sender, EventArgs e)
{
lblblank.Hide();
}
Edit
~~~
What does it mean that any layout element as a parent-element for the
label? Could you explain more?
What I meant was to just create a new panel (or layout-element) and put the label into it as a child. See the picture below:
If you set that up correctly, the code snippet I posted above will work just fine. This solution does not prevent the MouseLeave event from triggering when your mouse enters the label. Therefore you could use an alternative solution using the MouseMove event.
Alternative
using System;
using System.Windows.Forms;
using System.Drawing;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
this.InitializeComponent();
// Subscribe to the MouseMove event
this.panel.MouseMove += this.panel_MouseMove;
}
private void panel_MouseMove(object sender, MouseEventArgs e)
{
// Checks if current mouse position is within the panel
if (this.panel.Bounds.Contains(new Point(e.X, e.Y)))
{
// Current mouse position within the panel
this.label.Show();
return;
}
// Current mouse position outside the panel
this.label.Hide();
}
}
}
First - I'm a graphics designer - not a programmer :/
I'm trying create simple aplication (C# windows Form application) with option to add some objects (PictureBox) and allow user to drag those PicturesBoxes on form (change their positon after adding to form).
I can do it for one PictureBox, but can't add function to all dinamic created objects :/
I have something like that for standard Picturebox4
public bool moveDetect = false;
private void pictureBox4_MouseDown(object sender, MouseEventArgs e)
{
moveDetect = true;
}
private void pictureBox4_MouseUp(object sender, MouseEventArgs e)
{
if (moveDetect)
{
Point pozycja = new Point();
this.Cursor = new Cursor(Cursor.Current.Handle);
pozycja = this.PointToClient(Cursor.Position);
pictureBox4.Location = pozycja;
}
}
Does anyone know any tutorial showing how to add function like above to my simple class "myPictureBox : Picturebox"
My class is:
class myPictureBox : PictureBox
{
public bool moveDetect = false;
// constructor
public myPictureBox(int w, int h, string name)
{
this.Width = w;
this.Height = h;
this.Image = Image.FromFile("../../Resources/" + name + ".png");
Debug.WriteLine("Created ...");
}
}
Constructor works good and show "Created..." in output. Cant add function to all objects :/
Thanks and Regards ;)
If I understand correctly, your code works fine with the event handlers MouseUp and MouseDown when you are working with PictureBoxes that you create at design time using the designer.
You can add these same event handlers to controls that are created dynamically when you instantiate them:
MyPictureBox dynamicPicBox = new MyPictureBox(800, 600, "JustATest");
dynamicPicBox.MouseDown += pictureBox_MouseDown;
this adds an event handler that maps to the method pictureBox_MouseDown
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
moveDetect = true;
}
Since your custom class is derived from PictureBox, it should recognize this type of event handler.
I have a Picture Box with a picture loaded and I want to read the location (as in x,y inside the Picture Box) when I click the image; is this possible ? Even more, can i read these coordinates (Points) when i mouse over ?
I know i have to use the events given (Mouse Click and Mouse Over) but don't know how to read the coordinates where the mouse pointer happens to be.
Though other answers are correct let me add my point to it.
You've pointed that you need to hook up MouseClick or MouseOver events for this purpose. Actually that is no need to hook those events to get Coordinates, you can get the Coordinates in just Click event itself.
private void pictureBox1_Click(object sender, EventArgs e)
{
MouseEventArgs me = (MouseEventArgs)e;
Point coordinates = me.Location;
}
The above code works since Click event's e argument wraps MouseEventArgs you can just cast it and make use of it.
You can get the X and Y coordinates as follows,
this.Cursor = new Cursor(Cursor.Current.Handle);
int xCoordinate = Cursor.Position.X;
int yCoordinate = Cursor.Position.Y;
If you want to get the coordinate within the picture box, use the following code,
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
int xCoordinate = e.X;
int yCoordinate = e.Y;
}
i'll just sum up the answers:
in MouseClick, MouseUp and a lot of other events you have the MouseEventArgs which contains Location of the mouse.
in MouseHover however you don't have MouseEventArgs and therefor, if you need the cursor's location, use Coder example:
private void Form1_MouseHover(object sender, EventArgs e)
{
this.Cursor = new Cursor(Cursor.Current.Handle);
int xCoordinate = Cursor.Position.X;
int yCoordinate = Cursor.Position.Y;
}
What about hooking up the MouseUp event and then getting the location from the MouseEventArgs?
Like this:
private void pictureBox_MouseUp(object sender, MouseEventArgs e)
{
Point mousePointerLocation = e.Location;
}
The program should draw a rectangle on click. But it does not. Maybe some problem with my understanding of delegates. What's the catch?
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace forms1
{
public partial class MainForm : Form
{
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//this.Paint+= new PaintEventHandler(MujPaintHandler);
this.Click += new EventHandler(MujClickHandler);
}
public void MujPaintHandler(object sender,PaintEventArgs e)
{
Graphics gfx=e.Graphics;
gfx.FillRectangle(new SolidBrush(Color.DarkViolet),100,100,200,200);
}
public void MujClickHandler(object sender,EventArgs e)
{
this.Text="aaaaa";
this.Paint+= new PaintEventHandler(MujPaintHandler);
}
}
}
The code you've written works for me, but your form's window has to be big enough to show the rectangle.
Diagnostically, the first thing I'd check is whether the title of the form changes to "aaaaa". If it does, then you know the click handler is being called - but maybe you've got a problem with the paint handler. If it doesn't, then for some reason your click handler isn't being called.
Note that this isn't the normal way you'd draw a rectangle on a click in Windows Forms, but I'm assuming this is just a learning exercise.
Try forcing a redraw after assigning the event handler:
public void MujClickHandler(object sender,EventArgs e)
{
this.Text="aaaaa";
this.Paint+= new PaintEventHandler(MujPaintHandler);
this.Invalidate();
}
Also, if you click twice, the event handler gets assigned twice, which is not something you want.
Maybe you have to force a redraw. Does the rect appear if you move the window? Just call the PaintHandler after click.
I think you are only attaching the Paint event handler. You are not invoking the Paint event.
Try this
public void MujClickHandler(object sender,EventArgs e)
{
this.Text="aaaaa";
this.Paint+= new PaintEventHandler(MujPaintHandler);
this.Invalidate();
}
It will only draw the rectangle if it happens to be inside the area that is invalidated to update the text that you change.
When you change the text, it creates a message that the text has to be redrawn, which will call the Paint event to do the drawing. The event will have a Graphics object that is clipped to the rectangle that needs to be redrawn to update the text, so only the part of the rectangle that intersects with the text will be drawn.
You have to cause a redraw that covers the entire rectangle, so the easiest is to cause the whole window to be redrawn:
this.Invalidate();
Note that you should not hook up the Paint event from the Click event handler. That means that the event will be hooked up one more time each click, so after five clicks the Paint event handler will be called five times every time something needs to be redrawn.
Looking at your code, I understand that you are trying to add an eventhandler for paint event on Click... You would also need to invoke the paint event.. Here is a sample code where I am assigning the Paint EventHandler on a button click and raising the paint event on the click as you are doing
public Form1()
{
InitializeComponent();
this.Click += new EventHandler(MujClickHandler);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.ControlKey)
{
MessageBox.Show(e.KeyCode.ToString());
}
}
private void Form1_Load(object sender, EventArgs e)
{
//this.Paint += new PaintEventHandler(MujPaintHandler);
}
public void MujPaintHandler(object sender,PaintEventArgs e)
{
Graphics gfx=e.Graphics;
gfx.FillRectangle(new SolidBrush(Color.DarkViolet),100,100,200,200);
}
public void MujClickHandler(object sender,EventArgs e)
{
this.Text="aaaaa";
this.RaisePaintEvent(this, new PaintEventArgs(this.CreateGraphics(), this.RectangleToClient(new Rectangle())));
}
private void button1_Click(object sender, EventArgs e)
{
this.Paint += new PaintEventHandler(MujPaintHandler);
}
OR - How To Shave A Koala To Stop It Looking Squashed. (But I didn't think that would make a suitably techy title)
The Problem: You have three preview images derived from a main image. The preview images are resized for standardised picture spaces on a company website, the main image can be any size image from anywhere.
Example: The main image is a hi-res image of a koala bear measuring 2000x2250. Your previews want to render the koala at 200x200, 200x50 and 250x150.
Your utility program resizes and stretches the original image to the size of your three "actual size" previews but obviously each preview looks a bit squashy and you know everyone hates to see a squashed koala.
To resolve this you add a little cropping method to your program which shaves five pixels from the preview on the desired side. This means you should be able to resize your image and unsquash your koala by shaving off the unnecessary parts of the image.
You add four buttons to each preview image picture box and create four generic methods for sending the correct shaving instructions to the crop method. You want to associate each specific button with a specific picturebox on the form, but you want to send all the click events to four generic functions.
How do you tell the generic function which of the three preview picturebox images you want it to shave in an elegant and wonderful way?
Example Code:
//cropPict=method for cropping the picture in the relevant picturebox.
//CropSide=a little enum which tells the method which side to crop.
private void btnT_Click(object sender, EventArgs e)
{
cropPict(/*Reference to PictureBox Goes Here*/, CropSide.Top);
}
private void btnB_Click(object sender, EventArgs e)
{
cropPict(/*Reference to PictureBox Goes Here*/, CropSide.Bottom);
}
private void btnR_Click(object sender, EventArgs e)
{
cropPict(/*Reference to PictureBox Goes Here*/, CropSide.Right);
}
private void btnL_Click(object sender, EventArgs e)
{
cropPict(/*Reference to PictureBox Goes Here*/, CropSide.Left);
}
EDIT: As it happens, inspired by Hans below, rather than just stuffing the PictureBox into the tag. Which was a great idea I actually put a KeyValuePair into the tag for each button like so:
btnCCB.Tag = new KeyValuePair<CropSide,PictureBox>(CropSide.Bottom,pbxKoala);
btnCCL.Tag = new KeyValuePair<CropSide, PictureBox>(CropSide.Left, pbxKoala);
btnCCR.Tag = new KeyValuePair<CropSide, PictureBox>(CropSide.Right, pbxKoala);
btnCCT.Tag = new KeyValuePair<CropSide, PictureBox>(CropSide.Top, pbxKoala);
Then I could just wire all the buttons up to a single event handler like so:
private void btnC_Click(object sender, EventArgs e)
{
Button btnSend = (Button)sender;
KeyValuePair<CropSide, PictureBox> kvCrop = (KeyValuePair<CropSide, PictureBox>)btnSend.Tag;
cropPict(kvCrop.Value,kvCrop.Key);
}
Of course, there's still plenty more to do but that pretty much sorted out my problem. Thanks Hans!
Use the Button.Tag property to store a reference to its associated PictureBox. Cast sender to Button:
public Form1()
{
InitializeComponent();
button1.Tag = pictureBox1;
button1.Click += btnT_Click;
// etc..
}
private void btnT_Click(object sender, EventArgs e)
{
var btn = (Button)sender;
cropPict((PictureBox)btn.Tag, CropSide.Top);
}