Simulating hand position with Xtion pro live - c#

I am studying C# Programming and Kinect sensors programming (I am quite a
newbie in both C# language and Kinect). I am trying to use Microsoft Visual C# 2010 Express to write applications using sensors of Xtion Pro Live to control robots. In my main form, there are 2 picturebox objects, 2 button object, 3 label and 3 textbox objects. One of the two picturebox objects (pictureBox1) is to display the RGB camera. The other one pictureBox2) is to simulate the hand positions in 2D (x and y coordinates) graphics. One of the two buttons (button1) is to initialize Xtion Pro Live and to show RGB camera on picturebox1, and to simulate hand positions on picturebox2. The other one (button2) is to exit the program. The three labels, label1, label2, label3, and the three textboxes, textbox1, textbox2, textbox3 are used to show 3 coordinates of the hand.
This is my code in Form1.cs:
using OpenNI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace HandTracking
{
public partial class Form1 : Form
{
public const string path = #"C:/Vu/Kinect/Data/SamplesConfig.xml";
public bool run;
public Thread thread;
public Bitmap bitmap;
public Context context;
public ScriptNode node;
public ImageGenerator image;
public DepthGenerator depth;
public GestureGenerator gesture;
public HandsGenerator hand;
public Queue<Point3D> handpoint = new Queue<Point3D>();
public const int maxpoint = 30;
enum GestureStatus
{
Unrecognized, Progress, Recognized
}
private GestureStatus gesstatus = GestureStatus.Unrecognized;
enum HandsStatus
{
Untracked, Create, Update
}
private HandsStatus handstatus = HandsStatus.Untracked;
public Pen pen = new Pen(Color.Red, 5);
public Brush brush = new SolidBrush(Color.Magenta);
public Font font = new Font("Times New Roman", 20);
public PointF point = new PointF(0, 0);
public Form1()
{
InitializeComponent();
this.pictureBox1.BackColor = Color.Black;
this.pictureBox2.BackColor = Color.White;
this.button1.Enabled = true;
}
public void button1_Click(object sender, EventArgs e)
{
this.button1.Enabled = false;
try
{
context = Context.CreateFromXmlFile(path, out node);
image = context.FindExistingNode(NodeType.Image) as ImageGenerator;
if (image == null)
throw new Exception(context.GlobalErrorState);
depth = context.FindExistingNode(NodeType.Depth) as DepthGenerator;
if (depth == null)
throw new Exception(context.GlobalErrorState);
depth.AlternativeViewpointCapability.SetViewpoint(image);
gesture = context.FindExistingNode(NodeType.Gesture) as GestureGenerator;
if (gesture == null)
throw new Exception(context.GlobalErrorState);
gesture.AddGesture("RaiseHand");
gesture.GestureRecognized += new EventHandler<GestureRecognizedEventArgs>(GestureRecognized);
gesture.GestureProgress += new EventHandler<GestureProgressEventArgs> (GestureProgress);
hand = context.FindExistingNode(NodeType.Hands) as HandsGenerator;
if (hand == null)
throw new Exception(context.GlobalErrorState);
hand.HandCreate += new EventHandler<HandCreateEventArgs>(HandCreate);
hand.HandUpdate += new EventHandler<HandUpdateEventArgs>(HandUpdate);
context.StartGeneratingAll();
MapOutputMode map = image.MapOutputMode;
bitmap = new Bitmap((int)map.XRes, (int)map.YRes, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
run = true;
thread = new Thread(CallThread);
thread.Start();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
public void GestureRecognized(object sender, GestureRecognizedEventArgs e)
{
gesstatus = GestureStatus.Recognized;
hand.StartTracking(e.EndPosition);
}
public void GestureProgress(object sender, GestureProgressEventArgs e)
{
gesstatus = GestureStatus.Progress;
}
public void HandCreate(object sender, HandCreateEventArgs e)
{
handstatus = HandsStatus.Create;
}
public void HandUpdate(object sender, HandUpdateEventArgs e)
{
handstatus = HandsStatus.Update;
handpoint.Enqueue(e.Position);
}
public void button2_Click(object sender, EventArgs e)
{
DialogResult result = MessageBox.Show("Do you want to quit?", "Confirm", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
if (result == DialogResult.OK)
{
try
{
run = false;
if (thread != null)
thread.Join();
this.Close();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
public void CallThread()
{
try
{
while (run)
{
Data();
pictureBox1.Invalidate();
pictureBox2.Invalidate();
}
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
public unsafe void Data()
{
context.WaitAndUpdateAll();
ImageMetaData imd = image.GetMetaData();
lock (this)
{
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData data = bitmap.LockBits(rect, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
byte* dstp = (byte*)data.Scan0.ToPointer();
byte* imstp = (byte*)image.ImageMapPtr.ToPointer();
for (int i = 0; i < imd.DataSize; i += 3, dstp += 3, imstp += 3)
{
dstp[0] = imstp[2];
dstp[1] = imstp[1];
dstp[2] = imstp[0];
}
bitmap.UnlockBits(data);
if (handpoint.Count != 0)
{
Point3D start = depth.ConvertRealWorldToProjective(handpoint.Peek());
foreach (Point3D hpoint in handpoint)
{
Point3D pt = depth.ConvertRealWorldToProjective(hpoint);
HandPosition(start);
start = pt;
}
}
string mess = "Gesture: RaiseHand" + " ,Status:" + gesstatus.ToString() + "\n" + "Hand: " + handstatus.ToString();
PicDraw(bitmap, mess);
}
}
public void HandPosition(Point3D pt)
{
try
{
float a,b,c;
string handx, handy, handz;
a=pt.X;
b=pt.Y;
c=pt.Z;
handx = a.ToString();
handy = b.ToString();
handz = c.ToString();
Graphics g = pictureBox2.CreateGraphics();
g.FillEllipse(brush, a - 5, b - 5, 20, 20);
textBox1.Text = handx;
textBox2.Text = handy;
textBox3.Text = handz;
g.Dispose();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
public void PicDraw(Bitmap bmap, string me)
{
try
{
Graphics g;
pictureBox1.Image = bmap;
g = Graphics.FromImage(pictureBox1.Image);
g.DrawString(me, font, brush, point);
g.Dispose();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
}
And this is my code in Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace HandTracking
{
static class Program
{
........
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 f1 = new Form1();
f1.Text = "Hand Tracking";
f1.StartPosition = FormStartPosition.CenterScreen;
Application.Run(f1);
}
}
}
When I compile the program many times, each time different errors are thrown: InvalidOperationException not handled; Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on; Object is currently in use elsewhere.
I don't know whether the way I pass parameters at: HandPosition(start) and PicDraw(bitmap, mess) were correct. Any problem will come out if I use HandPosition(start) to control a robot? Can anybody show me my mistakes and help me correct the progam?

The problem is that you are trying to access a WinForms control on a thread other than the UI thread. It is being done from the thread you are creating with Thread.Start.
A much better technique for Windows Forms is to use the BackgroundWorker approach (if you are using .NET 4, Task Parallel Library is very nice). With BackgroundWorker, you send the thread off to do some work, and it gives the UI thread updates, sending back any objects of your choice. Since you are newer to C#, BackgroundWorker is the right choice because it is simple to use, and there is tons of documentation on it if you get stuck.
On the UI thread, you just take those updates, and then update your WinForms controls from the UI thread. Problem fixed.
To learn more about BackgroundWorker, Google it, or you can start here:
http://www.codeproject.com/Articles/99143/BackgroundWorker-Class-Sample-for-Beginners

Related

User controls can't be added "Failed to load toolbox item" C# winforms

When working on an application i decide to add my first user control for that project. I make it just fine, however when i drag it in to my main form from the toolbox it pops up with an error message:
No matter what i do it doesn't seem to fix it. I have tried adding it through code however it simply wouldn't show up at all.
Looking in to the problem online I was not able to find a working solution, or at least no solution that I could follow and understand.
Help would really be appreciated, and if any more information is needed I would be glad to add it. However currently I don't know what I could add that could be of any use.
The code is for a simple prank virus (Have to inspire myself to keep learning to code :) ) Here is the code (Please don't launch the file, it is a prank virus after all, the only way to exit is alt+f4):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Simple_virus_V2
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
internal static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public Form1()
{
InitializeComponent();
timer1.Start();
timer2.Start();
Thread newthread = new Thread(progress);
newthread.Start();
}
Random rnd = new Random();
int noticewidth = 0;
bool changecursor = false;
private void progress() {
Thread.Sleep(1000);
changecursor = true;
Thread.Sleep(1000);
timer3.Start();
Thread.Sleep(5000);
noticewidth = Width;
}
int mouseflash = 0;
private void timer1_Tick(object sender, EventArgs e)
{
if (changecursor) {
if (mouseflash < 1000)
{
Bitmap cursor = new Bitmap(new Bitmap(pictureBox1.Image), 24, 24);
Cursor = new Cursor(cursor.GetHicon());
} else if (mouseflash < 1700) {
Bitmap cursor = new Bitmap(new Bitmap(pictureBox2.Image), 30, 30);
Cursor = new Cursor(cursor.GetHicon());
}
else {
mouseflash = 0;
}
mouseflash = mouseflash + rnd.Next(3,10);
}
header.Left = MousePosition.X - (header.Width / 2);
label2.Left = MousePosition.X - (label2.Width / 2);
label3.Left = label2.Left + 25;
panel1.Width = noticewidth;
this.Location = new Point(0,0);
panel1.Location = new Point(0, MousePosition.Y - 40);
this.WindowState = FormWindowState.Maximized;
TopMost = true;
Process currentProcess = Process.GetCurrentProcess();
IntPtr hWnd = currentProcess.MainWindowHandle;
if (hWnd != IntPtr.Zero)
{
SetForegroundWindow(hWnd);
ShowWindow(hWnd, int.Parse("9"));
}
Focus();
this.Width = Screen.PrimaryScreen.Bounds.Width * 3;
this.Height = Screen.PrimaryScreen.Bounds.Height * 2;
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
/*
using (Form1 frm = new Form1()) {
if (frm.ShowDialog() == DialogResult.OK) {
}
}
*/
}
private void timer2_Tick(object sender, EventArgs e)
{
PictureBox pic = new PictureBox();
pic.Width = 1;
pic.Height = 1;
pic.BackColor = Color.Black;
pic.Location = new Point(rnd.Next(0, this.Width), rnd.Next(0, this.Height));
this.Controls.Add(pic);
}
private void timer3_Tick(object sender, EventArgs e)
{
/*
bartry bars = new bartry();
bars.Location = new Point(0, rnd.Next(0, 500));
Controls.Add(bars);
timer3.Interval = rnd.Next(100, 5000);
*/
}
}
}
Thanks
After ages of trying out the answers on the other post none of them ended up working. I did find the solution after opening a new project and experimenting around with my code.
The solution: Make sure that the user control and the main forms have the same "using" references!
Sorry if this was self explanatory, but i didn't know that you had to do that.
Just debug the project then try to add the User control form

Microsoft VSrollBar behavior or bug with touch screen - windows forms

I found a strange behavior with VScrollBar (vertical scrollbar available in Visual Studio tool box). The problem is "if I swipe down on the scrollbar, it moves up. If I swipe up, it moves down".
Steps to replicate Bug or behavior - 1
1) Add VScrollBar as a child to any user control.
2) Swipe up or down on the user control (not on scrollbar). Vertical scrollbar moves in opposite direction even if there isn't any programmatical connection between content and VScrollBar
Steps to replicate Bug or behavior - 2
1) Add VScrollBar as a child to any user control.
2) Swipe on scrollbar, it will move up during swipe up and down during swipe down (correct behavior)
3) Swipe up or down on the user control. Vertical scrollbar moves in opposite direction
4) Now swipe up or down on the vertical scrollbar. Vertical scrollbar starts moving in opposite direction (Buggy behavior, happens only after bug no: 1)
Simple control with vertical scrollbar to replicate this behavior
public class QuickViewer : Control
{
public QuickViewer()
{
// Designer generated code
// Copy pasted for illustration alone
this.vScrollBar1 = new System.Windows.Forms.VScrollBar();
this.SuspendLayout();
//
// vScrollBar1
//
this.vScrollBar1.Location = new System.Drawing.Point(420, 4);
this.vScrollBar1.Name = "vScrollBar1";
this.vScrollBar1.Size = new Size(this.vScrollBar1.Width, 292);
//
// QuickViewer
//
this.Controls.Add(this.vScrollBar1);
this.Name = "QuickViewer";
this.Size = new System.Drawing.Size(441, 296);
this.vScrollBar1.Value = 5;
this.ResumeLayout(false);
}
protected override void OnPaint(PaintEventArgs e)
{
//My actual control is different. I prepared a simple control to replicate the buggy behavior of VScrollBar
//Control border
Pen borderPen = new Pen(Color.LawnGreen, 5);
e.Graphics.DrawRectangle(borderPen, ClientRectangle);
borderPen.Dispose();
//View area
Rectangle rect = new Rectangle(ClientRectangle.Location, ClientRectangle.Size);
rect.Inflate(-25, -10);
e.Graphics.FillRectangle(Brushes.White, rect);
e.Graphics.DrawRectangle(Pens.Black, rect);
this.Font = new System.Drawing.Font("Segoe UI", 12, FontStyle.Bold);
StringFormat format = new StringFormat() { Alignment = StringAlignment.Center };
e.Graphics.DrawString("Quick viewer", this.Font, Brushes.Black, rect, format);
string content = "This is a control created to illustrate the bug in VScrollBar." +
"\n Control area refers to the area with white background" +
"\n Control and Vertical Scrollbar are not programatically connected with each other."
+ "But still VScrollBar moves if you swipe on control area";
Font font = new System.Drawing.Font("Segoe UI", 12, FontStyle.Italic);
rect.Y += 20;
e.Graphics.DrawString(content, font, Brushes.Black, rect, format);
font.Dispose();
format.Dispose();
base.OnPaint(e);
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private System.Windows.Forms.VScrollBar vScrollBar1;
}
Question:
Is there any way to overcome this behavior or bug ? I want the scrollbar to move down while swiping down and move up while swiping up. There should not be any scrolling when swiping over the content
I want the scrollbar to move down while swiping down and move up while swiping up.
As per Hans Passants comment its just a system setting (in the form of a registry key):
The answer is actually over at SuperUser:
https://superuser.com/questions/310681/inverting-direction-of-mouse-scroll-wheel
In C# as you wanted:
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 Microsoft.Win32;
using System.Diagnostics;
using System.Security.Principal;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private Flippable[] flippable;
private void Form1_Load(object sender, EventArgs e) {
WindowsPrincipal pricipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
bool hasAdministrativeRight = pricipal.IsInRole(WindowsBuiltInRole.Administrator);
if (!hasAdministrativeRight) {
RunElevated(Application.ExecutablePath);
this.Close();
Application.Exit();
}
//probably only want to flip mice.
flippable = getFlippable("hid.mousedevice");
dgv_flippable.DataSource = flippable;
foreach (var col in dgv_flippable.Columns.OfType<DataGridViewCheckBoxColumn>()) {
col.TrueValue = true;
col.FalseValue = false;
col.IndeterminateValue = null;
}
}
private static bool RunElevated(string fileName)
{
//MessageBox.Show("Run: " + fileName);
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.UseShellExecute = true;
processInfo.Verb = "runas";
processInfo.FileName = fileName;
try
{
Process.Start(processInfo);
return true;
}
catch (Win32Exception)
{
//Do nothing. Probably the user canceled the UAC window
}
return false;
}
private Flippable[] getFlippable(string filter) {
List<Flippable> flips = new List<Flippable>();
using (RegistryKey hid = Registry.LocalMachine.OpenSubKey(#"SYSTEM\CurrentControlSet\Enum\HID\",false)) {
foreach (string devicekn in hid.GetSubKeyNames()) {
using (RegistryKey device = hid.OpenSubKey(devicekn,false)) {
foreach (string devicekn2 in device.GetSubKeyNames()) {
using (RegistryKey device2 = device.OpenSubKey(devicekn2,false)) {
using (RegistryKey devparam = device2.OpenSubKey("Device Parameters",true)) {
if (devparam != null) {
flips.Add(new Flippable(new string[] { devicekn, devicekn2 }, device2, devparam, tmr_popup));
}
}
}
}
}
}
}
if (filter != null) {
return flips.Where(f=>f.name.Contains(filter)).ToArray();
}
return flips.ToArray();
}
private void dgv_flippable_MouseUp(object sender, MouseEventArgs e) {
dgv_flippable.EndEdit();
}
private void button1_Click(object sender, EventArgs e) {
flippable = getFlippable(null);
dgv_flippable.DataSource = flippable;
}
private void btn_flip_Click(object sender, EventArgs e) {
foreach (var f in flippable) {
f.vertical = true;
f.horizontal = true;
}
dgv_flippable.DataSource = null;
dgv_flippable.DataSource = flippable;
}
private void btn_normal_Click(object sender, EventArgs e) {
foreach (var f in flippable) {
f.vertical = false;
f.horizontal = false;
}
dgv_flippable.DataSource = null;
dgv_flippable.DataSource = flippable;
}
private void tmr_popup_Tick(object sender, EventArgs e) {
tmr_popup.Enabled = false;
notifyIcon1.ShowBalloonTip(99999999);
}
}
public class Flippable {
public Flippable(string[] keyPath, RegistryKey deviceKey, RegistryKey devparam, Timer timer) {
this._keyPath = keyPath;
IEnumerable<bool?> flipValues = Flippable.valueNames
.Select(v => onlyIntBool(devparam.GetValue(v, null)));
this.name = (string)deviceKey.GetValue("DeviceDesc");
this._vertical = flipValues.ElementAt(0);
this._horizontal = flipValues.ElementAt(1);
this._timer = timer;
}
private bool? onlyIntBool(object value) {
try {
return value == null ? null : (bool?)(((int)value) != 0);
} catch {
return null;
}
}
public static string[] valueNames = new string[] { "FlipFlopWheel", "FlipFlopHScroll" };
public string name { get; private set; }
private string[] _keyPath;
private bool? _vertical;
private bool? _horizontal;
Timer _timer;
public bool? vertical { set { flip(Flippable.valueNames[0], value); _vertical = value; } get { return _vertical; } }
public bool? horizontal { set { flip(Flippable.valueNames[1], value); _horizontal = value; } get { return _horizontal; } }
public void flip(string valueName, bool? value) {
using (RegistryKey hid = Registry.LocalMachine.OpenSubKey(#"SYSTEM\CurrentControlSet\Enum\HID\", false)) {
using (RegistryKey device = hid.OpenSubKey(_keyPath[0], false)) {
using (RegistryKey device2 = device.OpenSubKey(_keyPath[1], false)) {
using (RegistryKey devparam = device2.OpenSubKey("Device Parameters", true)) {
if (value == null) {
devparam.DeleteValue(valueName);
} else {
devparam.SetValue(valueName, value == true ? 1 : 0);
_timer.Enabled = true;
}
}
}
}
}
}
}
}
REF: https://github.com/jamie-pate/flipflop-windows-wheel/blob/master/Form1.cs
Disclaimer: normally this question would get closed as a duplicate but because there is a bounty on it and the duplicate is over at SuperUser I've chosen to share that answer here. Full credit to the original author: https://superuser.com/users/108033/richard and https://superuser.com/users/132069/jamie-pate
I think what you want is a ViewPort.
Essentially you put a Control inside a PictureBox. The Control has a larger height than the PictureBox making it a ViewPort.
Before
You'll need to change the form designer code to get the control inside the PictureBox:
'
'PictureBox1
'
Me.PictureBox1.Location = New System.Drawing.Point(96, 87)
Me.PictureBox1.Name = "PictureBox1"
Me.PictureBox1.Size = New System.Drawing.Size(231, 195)
Me.PictureBox1.TabIndex = 0
Me.PictureBox1.TabStop = False
'
'VScrollBar1
'
Me.VScrollBar1.Location = New System.Drawing.Point(330, 88)
Me.VScrollBar1.Name = "VScrollBar1"
Me.VScrollBar1.Size = New System.Drawing.Size(34, 194)
Me.VScrollBar1.TabIndex = 2
'
'TextBox1
'
Me.TextBox1.Location = New System.Drawing.Point(0, 0)
Me.TextBox1.Multiline = True
Me.TextBox1.Name = "TextBox1"
Me.TextBox1.Size = New System.Drawing.Size(211, 251)
Me.TextBox1.TabIndex = 3
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(522, 392)
Me.Controls.Add(Me.VScrollBar1)
Me.Controls.Add(Me.PictureBox1)
'======= THIS IS THE CRITICAL CHANGE =======
PictureBox1.Controls.Add(Me.TextBox1)
After
Then manually place a ScrollBar to the right of the PictureBox and facilitate the behaviour yourself, eg:
//set the VScroll the difference
VScroll.Max = Textbox.Height - PictureBox.Height;
In the VScroll event:
TextBox.Top = -VScroll.Value;
This will save you from mucking around with system settings in order to produce a QuickViewer custom control.
You can add smarts to it like programming PictureBox drag events to set the ScrollBar (and subsequently the inside controls Top). For most inside controls you'll just need to work out the Height which is easy using a for loop, eg:
foreach(var ctrl in PictureBox.Controls) {
// tally up the controls height
...
For inside Textbox controls you can work out the Height based on Fontsize and number of lines. There are plenty of examples online showing how to do that. Since you're doing Textbox's with graphics, eg e.Graphics.DrawString it should be easy enough having the inside control as a innerPictureBox.
To swap the scroll/swipe direction set the VScroll default starting Value to its Max value and set the inside controls Top = VScroll.Value (no minus sign needed)

How to exit a process by catching a mouse click? [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I'm new to C#, just beginning to write some codes.
I have something in mind but before proceeding to it, need some help on this matter.
How to exit a running process by detecting a mouse click?
I wrote some lines but when compiled and running, the mouse click has no effect at all.
Can someone please take a look and help me?
Here's my lines...
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 Graphic_test_1
{
public partial class Form1 : Form
{
public static Single lim_x, lim_y; // limits in X & Y
public static int dly = 45;
System.Drawing.Pen myPen = new System.Drawing.Pen(System.Drawing.Color.Blue); // color of the pen
System.Drawing.Graphics Canvas;
public Boolean clik = false; // initialize
public string mystring;
public Form1()
{
InitializeComponent();
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
clik = true;
lim_x = e.X;
lim_y = e.Y;
}
private void btgo_Click(object sender, EventArgs e) // Start drawing [GO]
{
Canvas = this.CreateGraphics();
btgo.Enabled = false;
MessageBox.Show("Checking the limits of the canvas.\r\n" +
"Click anywhere to stop and find out X position",
"Watching Coordinates",
MessageBoxButtons.OK, MessageBoxIcon.Information);
btgo.Visible = false;
btend.Enabled = false;
myPen.Color=System.Drawing.Color.Red; // color of the pen
myPen.Width = 2; // pen width
System.Drawing.Font drawfont = new System.Drawing.Font("Arial", 10); // Graphics font
System.Drawing.SolidBrush mybrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black); // color for the font
System.Drawing.Color background;
background = this.BackColor;
lim_x = 0; // initialize
do
{
Canvas.DrawLine(myPen, 0, 200, lim_x, 200);
mystring = "Current X = " + lim_x.ToString();
mybrush.Color = System.Drawing.Color.Black;
Canvas.DrawString(mystring, drawfont, mybrush, 351, 334);
System.Threading.Thread.Sleep(dly);
mybrush.Color = background; // use the background color
Canvas.FillRectangle(mybrush, new Rectangle(350, 333, 500, 353));
if (clik)
{
mybrush.Color = background; // use the background color
Canvas.FillRectangle(mybrush, new Rectangle(350, 333, 500, 353));
mystring = "Current X = " + lim_x.ToString();
mybrush.Color = System.Drawing.Color.Black;
Canvas.DrawString(mystring, drawfont, mybrush, 351, 334);
MessageBox.Show("Final position in X = " + lim_x.ToString(),
"Mouse click detected",
MessageBoxButtons.OK, MessageBoxIcon.Stop);
break;
}
else
lim_x++;
} while (lim_x < 611);
myPen.Dispose(); // release the pen
mybrush.Dispose(); // release the brush
Canvas.Dispose(); // release the canvas
btend.Enabled = true;
btend.Focus();
}
private void btend_Click(object sender, EventArgs e) // quit program [END]
{
Dispose(); // program ends.
}
}
}
If you want to close your form, use this.Close(). if you want to exit your application, you can use Application.Exit().
If I understand well, you are trying to stop the process it are running. (e.g. The btgo click event).
To do this, you should use an individual Thread to execute the process.
Why Thread ?
Your application will run two different process :
The main Thread
The second Thread
So, it will be possible to recognize the "Mouse Click" while you are running the second Thread.
E.g. I have one Button and one Label. I want, on the Button1 click,create and start a Thread. This Thread will loop 10000 time and modify the Label1 text. But when I click on the label, the loop will stop :
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
public partial class Test : Form
{
Thread thread;
public Test()
{
InitializeComponent();
}
void Button1_Click(object sender, EventArgs e)
{
thread = new Thread(new ThreadStart(StartThread));
thread.Start();
}
private void StartThread()
{
for(int i =0;i<1000000;i++)
{
Thread.Sleep(1000);
Label1.Invoke((MethodInvoker)(() => Label1.Text = i.ToString()));
//See the more information section, I will post a link about this.
}
}
void Label1_Click(object sender, EventArgs e)
{
thread.Abort();
}
}
More information :
You should read about how to properly close a thread here.
Invoke method here.

How can i use a flag to draw or not to draw in the pictureBox paint event?

I have a flag in the Form1 top level: addFrame wich is set to false in the constructor.
Then in the picnt event i check if its false let me draw if its true also let me draw. The problem here is that i want to be able to draw when im running the program first time !
But when im moving the trackBar to the right i dont want it to draw anything .
private void pictureBox1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Graphics g = e.Graphics;
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
moveCounter++;
label6.Text = moveCounter.ToString();
if (addFrame == false)
{
WireObjectGraphics.Draw(wireObject1, g);
}
else
{
addFrame = false;
WireObjectGraphics.Draw(wireObject1, g);
}
}
This is the button click event where im clicking to set the addFrame to true:
private void button16_Click(object sender, EventArgs e)
{
wireObjectAnimation1.AddFrame();
addFrame = true;
trackBar1.Select();
}
And the scroll bar event in this case i want to make that if i move the trackBar to the right and there are no any draws already then just show the image in the pictureBox dont draw anything ! But if i move it to the right and there are already draws then do show them.
If i move it to the left allways show the previous draws.
private void trackBar1_Scroll(object sender, EventArgs e)
{
if (addFrame == false)
{
}
else
{
currentFrameIndex = trackBar1.Value - 1;
textBox1.Text = "Frame Number : " + trackBar1.Value;
wireObject1.woc.Set(wireObjectAnimation1.GetFrame(currentFrameIndex));
trackBar1.Minimum = 0;
trackBar1.Maximum = fi.Length - 1;
if (checkBox1.Checked)
{
setpicture(trackBar1.Value);
Graphics g = Graphics.FromImage(pictureBox1.Image);
g.Clear(SystemColors.Control);
pictureBox1.Invalidate();
}
else
{
setpicture(trackBar1.Value);
}
pictureBox1.Refresh();
button1.Enabled = false;
button2.Enabled = false;
button3.Enabled = false;
button4.Enabled = false;
button8.Enabled = false;
SaveFormPicutreBoxToBitMapIncludingDrawings(currentFrameIndex);
return;
}
}
This is the draw function in the WireObjectGraphics class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace AnimationEditor
{
class WireObjectGraphics
{
static Point connectionPointStart;
static Point connectionPointEnd;
static SolidBrush brush;
static Pen p = null;
public WireObjectGraphics()
{
}
public static void Draw(WireObject wo, Graphics graphics)
{
brush = new SolidBrush(Color.Red);
p = new Pen(brush);
Graphics g = graphics;
WireObject wireObject1 = wo;
if (wireObject1 != null)
{
for (int idx = 0; idx < wireObject1.woc.Point_X.Count; ++idx)
{
Point dPoint = new Point((int)wireObject1.woc.Point_X[idx], (int)wireObject1.woc.Point_Y[idx]);
dPoint.X = dPoint.X - 5; // was - 2
dPoint.Y = dPoint.Y - 5; // was - 2
Rectangle rect = new Rectangle(dPoint, new Size(10, 10));
g.FillEllipse(brush, rect);
// bitmapGraphics.FillEllipse(brush, rect);
// g.FillEllipse(brush, rect);
}
for (int i = 0; i < wireObject1._connectionstart.Count; i++)
{
int startIndex = wireObject1._connectionstart[i];
int endIndex = wireObject1._connectionend[i];
connectionPointStart = new Point((int)wireObject1.woc.Point_X[startIndex], (int)wireObject1.woc.Point_Y[startIndex]);
connectionPointEnd = new Point((int)wireObject1.woc.Point_X[endIndex], (int)wireObject1.woc.Point_Y[endIndex]);
p.Width = 2;
g.DrawLine(p, connectionPointStart, connectionPointEnd);
// bitmapGraphics.DrawLine(p, connectionPointStart, connectionPointEnd);
}
}
}
}
}
What i need is that first time running the program to be able to draw !
Then when moving the trackBar to the righ to check if draws already exists show them if not exist show only the image and only when i click the button it will add the draws on the frame im on.
If i move to the left allways show the draws i did in the other frames.
WireObject class:
Constructor:
class WireObject
{
private string an;
private bool fnExt;
public string lockObject;
private int idx;
public WireObjectCoordinates woc;
private List<int> connectionStart = new List<int>();
private List<int> connectionEnd = new List<int>();
private const string version = "01.00";
string wo_name;
public WireObject( string name )
{
wo_name = name;
woc = new WireObjectCoordinates();
fnExt = false;
}
In the wireobject class i have some function like connecting points(pixels) like delete pixels like save and load...
WireObjectCoordinates class is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AnimationEditor
{
class WireObjectCoordinates
{
public List<float> Point_X = new List<float>();
public List<float> Point_Y = new List<float>();
public WireObjectCoordinates()
{
}
public WireObjectCoordinates(WireObjectCoordinates w)
{
Point_X.AddRange(w.Point_X);
Point_Y.AddRange(w.Point_Y);
}
public void Set(WireObjectCoordinates w)
{
if (w == null)
{
}
else
{
for (int i = 0; i < Point_X.Count; i++)
{
Point_X[i] = w.Point_X[i];
Point_Y[i] = w.Point_Y[i];
}
}
}
}
}
The problem is still in Form1 with the flag when to show the pixels i mean when and how to call the paint event like pictureBox1.Refresh(); but oncei t will use the Draw function inside and once it will not. When i run the program let me use the draw function once i moved the trackBar to the right dont use the draw function.
For a windows form control OnPaint is only called when a.) a window overlapping the current control is moved out of the way OR b.) you manually invalidate the control : http://msdn.microsoft.com/en-us/library/1e430ef4.aspx
So OnPaint should be getting called too often.

Stack Overflow Exception (C#)

I'm currently working on a Snake game that can solve itself, but when I activate it, usually after 30~ successful hits, my application crashes with the aforementioned exception either in System.drawing.dll or in System.Windows.Forms.dll.
The problem usually occurs in the command "Application.DoEvents()", but it has occured in several other places too.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Threading;
using System.IO;
namespace Snake
{
enum Directions
{
Right = 1,
Left = -1,
Up = 2,
Down = -2,
NoDirection = 0
}
public partial class GameForm : Form
{
#region Data Members
SnakeGame gmGame;
Point pCurrFood;
Directions dirFirstDirection;
Directions dirSecondDirection;
Directions dirHelpDirection;
Color DEFAULT_COLOUR = Color.White;
const int SEGMENT_HEIGHT = 10;
const int SEGMENT_WIDTH = 10;
#endregion
#region Ctor
public GameForm()
{
InitializeComponent();
this.gmGame = new SnakeGame();
this.dirFirstDirection = Directions.NoDirection;
this.dirSecondDirection = Directions.NoDirection;
}
#endregion
#region Other Methods
private void PaintSegment(Graphics gGraphics, Point pnPoint, Color cColour)
{
Pen Pen = new Pen(cColour);
Rectangle Rectangle = new Rectangle(pnPoint.X,
pnPoint.Y,
SEGMENT_HEIGHT,
SEGMENT_WIDTH);
gGraphics.DrawRectangle(Pen, Rectangle);
Brush Brush = new SolidBrush(cColour);
gGraphics.FillRectangle(Brush, Rectangle);
}
private void PlaceNewFood()
{
Random rRand = new Random();
int nHeight = rRand.Next(this.panel1.Size.Height);
int nWidth = rRand.Next(this.panel1.Size.Width);
while ((nHeight % 10 != 0) || (nWidth % 10 != 0))
{
nHeight = rRand.Next(this.panel1.Size.Height - 10);
nWidth = rRand.Next(this.panel1.Size.Width - 10);
while (this.gmGame.SnakeQueue.Contains(new Point(nWidth, nHeight)))
{
nHeight = rRand.Next(this.panel1.Size.Height);
nWidth = rRand.Next(this.panel1.Size.Width);
}
}
this.pCurrFood = new Point(nWidth, nHeight);
this.PaintSegment(this.panel1.CreateGraphics(), this.pCurrFood, Color.Red);
}
private void SelfSolve()
{
this.dirFirstDirection = (Directions)(Math.Sign(this.gmGame.SnakeHead.Y -
this.pCurrFood.Y) * 2);
this.dirSecondDirection = (Directions)Math.Sign(this.pCurrFood.X -
this.gmGame.SnakeHead.X);
this.ManageSnake(this.dirFirstDirection, this.dirSecondDirection);
}
private bool WillCollide(Point pnPointToCheck)
{
return ((pnPointToCheck.X > this.panel1.Size.Width) ||
(pnPointToCheck.Y > this.panel1.Size.Height) ||
(pnPointToCheck.X * pnPointToCheck.Y < 0) ||
(this.gmGame.SnakeQueue.Contains(pnPointToCheck)));
}
private void ManageSnake(Directions dirFirstSnakeDirection,
Directions dirSecondSnakeDirection)
{
Point pnNewHead = this.gmGame.SnakeHead;
switch (dirFirstSnakeDirection)
{
case (Directions.Down):
{
if (this.WillCollide(new Point(pnNewHead.X, pnNewHead.Y + SEGMENT_HEIGHT)))
{
this.ManageSnake(Directions.NoDirection, dirSecondSnakeDirection);
}
else
{
pnNewHead.Y += SEGMENT_HEIGHT;
dirHelpDirection = Directions.Down;
}
break;
}
case (Directions.Up):
{
if (this.WillCollide(new Point(pnNewHead.X, pnNewHead.Y - SEGMENT_HEIGHT)))
{
this.ManageSnake(Directions.NoDirection, dirSecondSnakeDirection);
}
else
{
pnNewHead.Y -= SEGMENT_HEIGHT;
dirHelpDirection = Directions.Up;
}
break;
}
case (Directions.NoDirection):
{
switch (dirSecondSnakeDirection)
{
case (Directions.Right):
{
if (this.WillCollide(new Point(pnNewHead.X + SEGMENT_WIDTH, pnNewHead.Y)))
{
this.ManageSnake(this.dirHelpDirection, dirSecondSnakeDirection);
}
else
{
pnNewHead.X += SEGMENT_WIDTH;
}
break;
}
case (Directions.Left):
{
if (this.WillCollide(new Point(pnNewHead.X - SEGMENT_WIDTH, pnNewHead.Y)))
{
this.ManageSnake(this.dirHelpDirection, dirSecondSnakeDirection);
}
else
{
pnNewHead.X -= SEGMENT_WIDTH;
}
break;
}
}
break;
}
}
this.gmGame.AddSegment(pnNewHead);
if (this.gmGame.SnakeHead.Equals(this.pCurrFood))
{
this.lblScoreNum.Text = (int.Parse(this.lblScoreNum.Text) + 1).ToString();
this.PlaceNewFood();
}
else
{
this.PaintSegment(this.panel1.CreateGraphics(),
(Point)this.gmGame.SnakeQueue.Peek(),
DEFAULT_COLOUR);
this.gmGame.RemoveSegment();
}
this.PaintSegment(this.panel1.CreateGraphics(),
this.gmGame.SnakeHead,
Color.Green);
Thread.Sleep(5);
Application.DoEvents();
this.SelfSolve();
}
#endregion
#region Events
private void GameForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
this.PlaceNewFood();
this.SelfSolve();
}
else if (e.KeyCode == Keys.Escape)
{
this.Close();
}
else if (e.KeyCode == Keys.Space)
{
MessageBox.Show("Frozen, press OK to continue");
}
}
private void GameForm_ClientSizeChanged(object sender, EventArgs e)
{
this.PaintSegment(this.panel1.CreateGraphics(), new Point(210, 250), Color.Green);
this.PaintSegment(this.panel1.CreateGraphics(), new Point(220, 250), Color.Green);
this.PaintSegment(this.panel1.CreateGraphics(), new Point(230, 250), Color.Green);
this.PaintSegment(this.panel1.CreateGraphics(), new Point(240, 250), Color.Green);
this.PaintSegment(this.panel1.CreateGraphics(), new Point(250, 250), Color.Green);
}
#endregion
}
}
I know it's a lot of code, but since I'm not sure where's the root of the problem, I had to copy all of it.
I'd greatly appreciate it if you could point me in the right direction.
Thanks in advance :)
P.S. I know that the algorithm has flaws, I'll get to that later. Right now my main concern is solving the crash.
This is because you keep on going recursive in your method. e.g.:
Thread.Sleep(5);
Application.DoEvents();
this.SelfSolve();
Your method will basically never end.
You should use a timer and within that timer, call SelfSolve() This should solve your problem.
When using a timer you dont have to call DoEvents yourself since a winforms timer anyways posts a call to your method as a message and the message loop will handle the invocation and other messages.
SelfSolve should not call ManageSnake directly, but rather schedule its run for some later moment. Otherwise you get infinite recursion SelfSolve -> ManageSnake -> SelfSolve etc.

Categories

Resources