Drawing in C# winform is fairly slow - c#

I'm creating a custom DataGridView, in which the CheckBox Shows a border when MouseHover is raised.
Here is what I've done so far.
void checkBox_MouseLeave(object sender, EventArgs e)
{
//showBorder defines whether the border is drawn.
this.showBorder = false;
this.DataGridView.InvalidateCell(this);
}
void CheckBoxMouseHover(object sender, EventArgs e)
{
this.showBorder = true;
this.CheckBox.BringToFront();
this.DataGridView.InvalidateCell(this);
}
protected override void Paint(...........)
{
..........
if (showBorder)
{
GraphicsPath border=new GraphicsPath();
border.AddRectangle(new Rectangle(checkBoxPosition.X-1,checkBoxPosition.Y-1,checkBoxSize.Width+1,checkBoxSize.Height+1));
graphics.DrawPath(new Pen(borderColor,1),border);
}
}
But is comes so slow that I have to wait for about half a second to see do border show.
Anyway, MouseLeave works fine.
So how can I improve the performance here?
In addition, how can I customize the checkbox? for example, the background color, etc.

You're using MouseHover event for the Mouse going over the control. Try MouseEnter instead. MouseHover is triggered after the mouse stays over the control for a little bit of time. MouseEnter is instant

Related

Check time after a mousebuttondown before the mousebuttonup

I think that must be only a little problem, but I can't get a clear thought on that. Someone an idea?
I have some borders on a canvas (filled with images) and i want to click the border (i do this with the OnMouseLeftButtonDown) where the border gets red (so the user knows for sure which object he had clicked) and then, after 1 or 2 seconds, when the mousebutton is still pushed down, a drag'n'drop should start.
At first I had the borders inside buttons, but the clickevent seems to conflict with the dragevent. So I got rid of the buttons and did everything inside the borders directly, which works well also. But how can I start the drag after the mousebuttondown and stop it when the mousebuttonup happens before the time runs out.
Someone an idea for a clean solution?
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_source = sender as Border;
Mouse.Capture(_source);
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_source = null;
Mouse.Capture(null);
}
and in event OnMouseMove you can modify border margins depends on mouse position but after checking if _source is type of Border.
var position = e.GetPosition(Canvas);
EDIT:
For that time you can add property Stopwatch _watch, and inside OnMouseLeftButtonDown event handler you can do it:
_watch = Stopwatch.StartNew();
in OnMouseLeftButtonUp:
_watch.Stop();
and in OnMouseMove before your code:
while (_watch.ElapsedMilliseconds < 2000 && _watch.IsRunning)
{
Thread.Sleep(100);
}

How to change the background color on multiple labels using a "drawing gesture" in C#?

my Question is how to "draw" on multiple labes. I have a form containing a matrix of labels. Now I want to click on one Label drag over some others and all these Labels should change the background color. I have a method which changes the color with the Click-Event, but I can't find an Event for this Problem. I also tried the Mous_Enter Event and checked if the left button was down, but it looks like, that the Event Trigger was stuck in the first label.
So at first I have this, where each number is in a different label:
And then I want to "draw" on the labels, so that the Background Color changes and so I have something like the following:
Connect the MouseClick and MouseMove event of all your labels to the following event handler:
private void MouseClickedOrMoved(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
ChangeLabelBackColor(this.PointToClient(MousePosition));
}
}
and add this function to your code:
private void ChangeLabelBackColor(Point Location)
{
foreach (Label l in this.Controls.OfType<Label>()) {
if (l.Bounds.Contains(Location))
{
l.BackColor = Color.Black;
}
}
}

MouseWheel event issues on Controls

I need to get MouseWheel events on a PictureBox Control and according to another SO answer, getting MouseWheel stuff should be done like this:
void pic_MouseWheel(object sender, MouseEventArgs e)
{
if(e.Delta != 0)
{
MessageBox.Show(e.Delta.ToString());
}
}
But this does not work. Now messagebox is displayed and no breakpoints are being hit.
How do I capture the MouseWheel event on a PictureBox and also determine if the user scrolled the wheel UP or DOWN?
Nevermind, I figured it out. I need to Focus the PictureBox first:
void pic_Click(object sender, EventArgs e)
{
((PictureBox)sender).Focus();
}

change cursor over a pictureBox

i was trying to implemet an image button in winforms application as i can ...easy when using asp.net
the problem seem to be(i suspect) that when the mouse is over the image inside the picturebox
it is not responding or not triggering the mouseEnter event
it looks like if i had a picture that is smaller than the pictureBox Size it will accept the reason to trigger the event but over the image within the pictureBox it would Not ?
the trick was to set pictureBox to sizeMode=zoom. then do 2 things when the mouse is over the "imageButton" : change the size of PictureBox a little larger + change cursor to hand
so i will get a kind of mouse over effect as i could with asp.net
did anyone have that problem ?
at first i tried mouseHover, then i thought enter would do better as it only requiers the mouse to pass the borders of the picture box... both enter and hover events did not work for me ...
Edit :
the event does trigger , i can see that if i initially set sizemode to CenterImage and inside the event
i ask for sizemode=zoom, so the effect dose occur ..but cursor.current=Cursors.Hand will not change.
This should work
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox1.Cursor = Cursors.Hand;
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
pictureBox1.Cursor = Cursors.Default;
}
seem like i should have known better how to use Cursors class .
cursor=Cursors.hand;
rather than
cursor.current=Cursors.hand;
that was embarrassing ..
only add MouseMove event on pictureBox and set a Cursor for this
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
pictureBox1.Cursor = Cursors.Hand;
}

.NET C# MouseEnter listener on a Control WITH Scrollbar

As long as the mouse is over a specific control, we show some form. When the mouse leaves the control, we hide the control after a small timeout. This is standard hover behavior.
However, when a control (for example a Treeview) has a scrollbar, and the mouse is ON or OVER the scrollbar, the events don't fire ...
If we could get a reference to the scrollbar control, this would solve our problem, as we would add the same listener events to the scrollbar. However, the scrollbar isn't accessible as far as I know ...
How can we solve this problem ?
The scrollbar is in the tree view's non-client area. When the mouse moves there, it starts generating non-client messages like WM_NCMOUSEMOVE and WM_NCMOUSELEAVE. You would have to sub-class the TreeView and override WndProc() to detect these message.
This doesn't really solve your problem though, you'll still have a hard time with edge cases. A low-tech approach with a Timer always works:
private Form frmPopup;
private void treeView1_MouseEnter(object sender, EventArgs e) {
timer1.Enabled = true;
if (frmPopup == null) {
frmPopup = new Form2();
frmPopup.StartPosition = FormStartPosition.Manual;
frmPopup.Location = PointToScreen(new Point(treeView1.Right + 20, treeView1.Top));
frmPopup.FormClosed += (o, ea) => frmPopup = null;
frmPopup.Show();
}
}
private void timer1_Tick(object sender, EventArgs e) {
Rectangle rc = treeView1.RectangleToScreen(new Rectangle(0, 0, treeView1.Width, treeView1.Height));
if (!rc.Contains(Control.MousePosition)) {
timer1.Enabled = false;
if (frmPopup != null) frmPopup.Close();
}
}
I think there are several different ways to do this, but the key is your desire to have a timeout on the action. I think a combination of two techniques might work:
Put the control on a panel, docked to fill, and use the MouseEnter of the panel to turn on your behavior -- this will include the control's scrollbar. You can use the MouseLeave event of the panel as well, but you'll have to check the cursor's position to ensure it hasn't moved into the contained control. This method is mostly reliable, but moving the mouse quickly can confuse it.
If you combine this with a timer that starts when your shown/hidden control is shown and check the cursor position periodically. This will work, but your timeout before hiding the control won't necessarily be consistent (because the timer starts when they enter the control). You could stop/start the timer on mousemoves in the control to alleviate this somewhat.
I put together a project of the different methods I tried here: http://lovethedot.s3.amazonaws.com/100609StackoverflowScrollbarQuestion.zip
By docking the control you want to track in the panel, it essentially wraps it and you'll get MouseEnter at the very edge of the tracked control:
private void panel1_MouseEnter(object sender, EventArgs e)
{
this.Text = "in";
}
private void panel1_MouseLeave(object sender, EventArgs e)
{
if (!new Rectangle(new Point(0, 0), panel1.Size).Contains(panel1.PointToClient(Control.MousePosition)))
this.Text = "out";
}
You're tracking entry into the panel surrounding the control, and exit from that panel provided the cursor isn't inside the tracked control.
To get a better "leave" experience, it's combined with a Timer that checks to see where the cursor is as well:
private void listBox3_MouseEnter(object sender, EventArgs e)
{
button1.Visible = true;
visibleTimer.Stop();
visibleTimer.Start();
}
void visibleTimer_Tick(object sender, EventArgs e)
{
if (!new Rectangle(new Point(0, 0), listBox3.Size).Contains(listBox3.PointToClient(Control.MousePosition)))
{
visibleTimer.Stop();
button1.Visible = false;
}
}

Categories