Mousewheel scroll down event in C# winform programmatically done - c#

I am trying do image slide show with picturebox Control and a trackbar. The trackbar gets minimum and maximum value corresponds to the number of images to show. I use a timer to get interval period for the slide along with trackbar valuechange.
Now, here is the main thing for each image in the picturebox I'm drawing a rectangle box over the image.
I am not able to draw on the first image when the form get load with first image. But I could do if I scroll the mouse wheel.
I need help to trigger the mouse wheel scroll event once after the first image get loaded.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace test
{
public partial class Form1 : Form
{
public event MouseEventHandler MouseWheel;
//MouseEventArgs k = new MouseEventArgs(MouseButtons.Middle,0,0,-1);
string[] pics = { "C:\\Downloads\\folder_picture_green.png", "C:\\Downloads\\Aetherpal.ico", "C:\\Downloads\\folder_picture_green.png" };
public Form1()
{
InitializeComponent();
this.trackBar1.Minimum = 0;
this.trackBar1.Maximum = (pics.Count() - 1);
//this.trackBar1.Maximum = 0;
imageupdate(0);
timer1.Start();
timer1.Interval = 3000;
this.MouseWheel += test;
this.MouseWheel(null, null);
}
private void test(object sender, System.Windows.Forms.MouseEventArgs e)
{
MessageBox.Show("Scrolled");
}
private void check(object sender, System.EventArgs e)
{
//if (Initializing == false) { return; }
if(this.trackBar1.Value < this.trackBar1.Maximum )
this.trackBar1.Value += 1;
else
timer1.Stop();
}
private void Valuechange(object sender, System.EventArgs e)
{
imageupdate(this.trackBar1.Value);
if(this.trackBar1.Value < this.trackBar1.Maximum)
timer1.Start();
}
private void imageupdate(int k)
{
this.pictureBox1.Refresh();
this.pictureBox1.Image = new Bitmap(pics[k]);
Pen blackPen = new Pen(Color.Blue, 5);
this.pictureBox1.Refresh();
using (Graphics g = this.pictureBox1.CreateGraphics())
{
g.DrawRectangle(blackPen, 10, 10, 100, 50);
}
}
}
}

You can add this code to your form to scroll your form (of course with MouseWheel):
private void Wheel(int ticks, bool down){
//WM_MOUSEWHEEL = 0x20a
Message msg = Message.Create(Handle, 0x20a, new IntPtr((down ? -1 : 1)<<16), new IntPtr(MousePosition.X + MousePosition.Y << 16));
for(int i = 0; i < ticks; i++)
WndProc(ref msg);
}
//Use it
Wheel(120,true);//Wheel down
Wheel(120,false);//Wheel up
NOTE: I can see you define a MouseWheel event in your own form. This will hide the base MouseWheel event, I don't think you have any reason to do this, your own MouseWheel can't work as the base one, you have to catch the win32 message and raise it yourself, we should use the base MouseWheel event instead. (Maybe you thought there isn't any MouseWheel event in your form class?)

Related

Why is my screen flickering even though I have double buffering on?

Ok, Im pretty new to c# graphics and I'm trying to make a top down adventure game type thing. The problem is anything displayed above the background flickers. Everything is a bitmap from a png file. The background doesnt flicker so I dont know where I'm going wrong.
Here's my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AITS
{
public partial class Form1 : Form
{
Background background;
Foreground foreground;
Character player;
Graphics g;
public Form1()
{
InitializeComponent();
Console.WriteLine(Environment.CurrentDirectory);
background = new Background(Properties.Resources.background, Width, Height);
foreground = new Foreground(100, Width);
player = new Character();
DoubleBuffered = true;
Paint += DrawScreen;
KeyDown += KeyPressed;
Shown += Form1_Shown;
g = CreateGraphics();
}
private void Form1_Shown(Object sender, EventArgs e)
{
gameLoop();
}
private void DrawScreen(object sender, PaintEventArgs args)
{
background.Draw(g);
player.Draw(g);
foreground.Update(Height, Width);
foreground.Draw(g);
}
private void KeyPressed(object sender, KeyEventArgs e)
{
Console.WriteLine(e.KeyData.ToString());
}
public void gameLoop()
{
while (this.Created)
{
Invalidate();
Refresh();
Application.DoEvents();
}
}
}
}
EDIT:
Ok i found the answer, for anyone who couldnt find this like me:
g should = args.Graphics. DO NOT use CreateGraphics()!
The screen flickers, because the form first redraws its background before letting you paint on it.
You can suspend this behavior by overriding WndProc:
private const int WM_ERASEBKGND = 20;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_ERASEBKGND)
{
m.Result = IntPtr.Zero;
}
else
{
base.WndProc(ref m);
}
}
Ok i found the answer, for anyone who couldnt find this like me: g should = args.Graphics. DO NOT use CreateGraphics()!

Draw graphics on click and make them stay

This little program opens a windows form and draws 70 red rectangles, where the user clicks on the form.
Every time the user clicks, the rectangles disappear, and new ones are drawn on the new click-Point.
I want to make the rectangles to stay when the user clicks and draws a new set of rectangles.
How do i do that?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace tegnRektangel
{
public partial class Form1 : Form
{
int x;
int y;
bool mouseClicked = false;
Graphics g = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
}
private void Form1_Resize(object sender, EventArgs e)
{
Invalidate();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (mouseClicked)
{
g = panel1.CreateGraphics();
paintRectangel();
}
}
private void paintRectangel()
{
for (int i = 1; i <= 70; i++)
{
g.DrawRectangle(Pens.Red, x - 50-i*5, y - 40-i*5, 100, 80);
}
g.Dispose();
}//end paint
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
mouseClicked = true;
Point clickPoint = new Point(e.X,e.Y);
x = clickPoint.X;
y = clickPoint.Y;
panel1.Invalidate();
}
}
}
From MSDN:
The Graphics object that you retrieve through the CreateGraphics
method should not normally be retained after the current Windows
message has been processed, because anything painted with that object
will be erased with the next WM_PAINT message.
You can work around it like this:
In the click event, add the (x, y) coordinate to a list of coordinates.
In the paint event, iterate all these (x, y) coordinates and paint each rectangle.
Here is some code to demonstrate creating rectangles for each click, storing them, and painting all stored rectangles.
public partial class Form1 : Form
{
private List<Rectangle> Rectangles { get; set; }
public Form1()
{
InitializeComponent();
Rectangles = new List<Rectangle>();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (Rectangles.Count > 0)
e.Graphics.DrawRectangles(Pens.Red, Rectangles.ToArray());
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
for (int i = 1; i <= 70; i++)
{
Rectangles.Add(new Rectangle(e.X - 50 - i * 5, e.Y - 40 - i * 5, 100, 80));
}
Invalidate();
}
}

How do you make an object be limited to the boundaries of a Form

I am currently making a Space Invaders type game using C# Windows Forms. When creating the laser cannon which the user controls, I want them to move left and right, shooting lasers. This is my current code for the movement so far:
enter code here
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Move
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_KeyDown(object sender, KeyEventArgs e)
{
}
private void pictureBox1_Click(object sender, EventArgs e)
{
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
int i;
for (i = 0; i < 500; i++)
{
if (e.KeyCode == Keys.Up)
{
pictureBox1.Location = new Point(pictureBox1.Left - 1);
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
if (e.KeyCode == Keys.Down)
{
pictureBox1.Location = new Point(pictureBox1.Left + 1);
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
However, I'm having an issue with this; if the image goes too far, it goes out of the boundaries of the form but I want it to do is bounce off and go the other way.
I tried doing this but to no avail, it only moves by a pixel but I think it's a good step(right?...):
if(pictureBox1.Location == new Point(300,300))
{
pictureBox1.Location = new Point(pictureBox1.Left - 1);
}
Like how do I get the correct X,Y coordinates of the whole form so I could tell it to go the other way as well as actually getting it to move?
The smallest X and Y position for a picture box to stay inside the form is 0.
The largest X a picture box can go to is Form.ClientSize.Width - pictureBox.Size.Width
The largest Y a picture box can go is Form.ClientSize.Height - pictureBox.Size.Height.
Check all of these things in an if statement. If either the X or Y of the picture box is outside of the ranges, don't move the picture box, otherwise, do move it.

Colloring panels with mousemove

I have create a field of small panels on a form and I want the user to be able to color these panels. To color them you have to simpely click the panel, this works. Now I want to be able to let the use click a panel and drag over other panels to color more panels at once.
I have added the mousedown and mouseup event to all panels to set a boolean. The I use the mousemove event to color the panels. Yet only the first panel gets collored.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
namespace Application
{
public partial class Form1 : Form
{
private const int dim = 25;
private int cols;
private int rows;
private bool mouse_down = false;
private sbyte fill = -1;
private Panel pnlTmp;
public Form1()
{
InitializeComponent();
this.buildGrid();
}
/// <summary>
/// Rebuild the grid to fit the screen.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
this.buildGrid();
}
/// <summary>
/// Build the grid to fit the screen.
/// </summary>
private void buildGrid()
{
panel1.Controls.Clear();
cols = int.Parse(Math.Floor((double)panel1.Width / dim).ToString());
rows = int.Parse(Math.Floor((double)panel1.Height / dim).ToString());
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
Panel pnl = new Panel();
pnl.BorderStyle = BorderStyle.FixedSingle;
pnl.Width = dim;
pnl.Height = dim;
pnl.Location = new Point(j * 25 + 1, i * 25 + 1);
pnl.Name = string.Format("pnl-{0}-{1}", j, i);
pnl.MouseDown += new MouseEventHandler(pnl_MouseDown);
pnl.MouseUp += new MouseEventHandler(pnl_MouseUp);
pnl.MouseMove += new MouseEventHandler(pnl_MouseHover);
panel1.Controls.Add(pnl);
}
}
}
void pnl_MouseHover(object sender, EventArgs e)
{
if (mouse_down)
{
Panel p = (Panel)sender;
if (p != pnlTmp)
{
if (fill == -1)
fill = (p.BackColor == SystemColors.Control) ? (sbyte)1 : (sbyte)0;
if (fill == 1)
p.BackColor = Color.Blue;
else
p.BackColor = SystemColors.Control;
Debug.WriteLine(p.Name);
}
pnlTmp = p;
}
}
void pnl_MouseDown(object sender, MouseEventArgs e)
{
Debug.WriteLine("true");
mouse_down = true;
}
void pnl_MouseUp(object sender, MouseEventArgs e)
{
Debug.WriteLine("false");
mouse_down = false;
fill = -1;
}
private void panel1_MouseLeave(object sender, EventArgs e)
{
//mouse_down = false;
//fill = -1;
}
}
}
I have tried debugging the application and the result was that only the first panel keeps firing the event, even if I am moving over other panels.
Could someone tell me why this is?
Your problem is caused by a feature called "mouse capture". It is controlled by the Control.Capture property. The default behavior is that it is turned on automatically in the OnMouseDown() method, before it fires the MouseDown event.
Mouse capture forces all mouse events to be directed to the window that you clicked, even if you move the mouse outside of the window. Which is why you only ever get the MouseMove and MouseUp events for the panel that you clicked on. It is important in a number of scenarios, particularly to reliably generate the Click and MouseUp events.
The workaround is to simply turn the capture back off in your MouseDown event handler:
void pnl_MouseDown(object sender, MouseEventArgs e) {
((Control)sender).Capture = false;
}
Do note that you now have a new problem, your "mouse_down" variable is no longer reliable. If you move the mouse outside of any panel, or outside of the form, and release the mouse then the MouseUp event is sent to the wrong window and your mouse_down variable remains set to true even though the mouse is no longer down. You lost the guarantee provided by the capture feature. You solve that problem by checking the button state in your MouseMove event handler, like this:
private void pnl_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
// etc...
}
}
Beware that I fixed your incorrect pnl_MouseHover event handler and renamed it to pnl_MouseMove. I can see how you ended up making this mistake, but it possibly did prevent you from discovering this solution yourself. Careful with that axe Eugene ;)

DoDragDrop from standard Label not working

I can't figure out why attempting to drag text from a standard Label to Notepad (or any other control accepting text) doesn't work. I've looked at documentation and examples and I'm not seeing the problem. The cursor remains a circle with a line through it and if I register a FeedBack callback the event is always NONE. Creating a standard Windows Forms Application, dropping a Label control and registering MouseDown & MouseMove events I have this code where I call label1.DoDragDrop (label1, DragDropEffects.All | DragDropEffects.Link). Any help would be appreciated.
Here is my form code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace DragDropLabel
{
public partial class Form1 : Form
{
Point m_ClickLocation;
bool _bDragging = false;
public Form1()
{
InitializeComponent();
}
private void OnLabelMouseDown(object sender, MouseEventArgs e)
{
m_ClickLocation = e.Location;
_bDragging = true;
}
private void OnLabelMouseMove(object sender, MouseEventArgs e)
{
if (_bDragging)
{
Point pt = e.Location;
Size dragSize = SystemInformation.DragSize;
if (Math.Abs(pt.X - m_ClickLocation.X) > dragSize.Width / 2 ||
Math.Abs(pt.Y - m_ClickLocation.Y) > dragSize.Height / 2)
{
DragDropEffects rc = label1.DoDragDrop(label1, DragDropEffects.All | DragDropEffects.Link);
_bDragging = false;
}
}
}
}
}
First, change
DragDropEffects rc = label1.DoDragDrop(label1, DragDropEffects.All | DragDropEffects.Link);
to
label1.DoDragDrop(label1.Text, DragDropEffects.Copy);
Second, you must prepare your drop target. Lets assume, it is textbox. Here is exmple extension method which will allow to cofigure any textbox by calling MyTextBox.EnableTextDrop():
static class TextBoxExtensions
{
public static void EnableTextDrop(this TextBox textBox)
{
if(textBox == null) throw new ArgumentNullException("textBox");
// first, allow drop events to occur
textBox.AllowDrop = true;
// handle DragOver to provide visual feedback
textBox.DragOver += (sender, e) =>
{
if(((e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) &&
e.Data.GetDataPresent(typeof(string)))
{
e.Effect = DragDropEffects.Copy;
}
};
// handle DragDrop to set text
textBox.DragDrop += (sender, e) =>
{
if(((e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) &&
e.Data.GetDataPresent(typeof(string)))
{
((TextBox)sender).Text = (string)e.Data.GetData(typeof(string));
}
};
}
}
Standard edit controls (textboxes) do not support drag&drop and will not accept any dropped text.

Categories

Resources