Virtual Keyboard (Swype like Keyboard) Windows Forms Application C# - c#

I am trying to create a swype like keyboard in Windows Forms using c#
I have two problems:
a. I am not able to reproduce the finger swipe action.
b. I am not able to recognize the letters under different keys.
For the first problem:
I used the Graphics Class and the Pen class and used it like this :
bool draw;
Graphics g;
Pen p;
int prevX;
int prevY;
private void Form1_Load(object sender, EventArgs e)
{
draw = false;
g = CreateGraphics();
p = new Pen(Color.Black, 2);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
draw = true;
prevX = e.X;
prevY = e.Y;
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (draw)
{
g.DrawLine(p, prevX, prevY, e.X, e.Y);
prevX = e.X;
prevY = e.Y;
}
}
But the problem here is that it starts drawing from the Left-top corner of the screen and not from the position of the button. It also does't draw over the buttons. Any control that is in the path overlaps the line.
For the second Issue:
a. I used the mouse down event to set a boolean value "Allow" as true and then when the mouse moves I tried getting the text of the button. Just as in the above picture. I tried to start from letter "S" and as I move over other letters only the letter "S" keeps recording. The Mouse Enter or Mouse Hover event of the other methods do not even occur.
b. I also tried using dragdrop event but it doesn't work too. I am not sure but I am assuming that as buttons are not draggable objects the dragdrop event doesn't work.
I don't understand or am confused how to achieve my goal.

You can create a custom control and handle its drawing yourself.
But if you are going to use Button controls and want to draw over those buttons, you can put a transparent panel as overlay on those buttons and draw the swipe path over the transparent panel:
Transparent Panel
using System.Windows.Forms;
public class TransparentPanel : Panel
{
const int WS_EX_TRANSPARENT = 0x20;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
return cp;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
}
}
Sample Form
This is just an example to demonstrate the usage of transparent control. To do so, it's enough to create a form and replace it's contents with following code:
TransparentPanel overlay;
TableLayoutPanel table;
List<Point> points = new List<Point>();
List<String> keys = new List<string>();
public Form1()
{
overlay = new TransparentPanel() { Dock = DockStyle.Fill };
this.Controls.Add(overlay);
table = new TableLayoutPanel()
{ ColumnCount = 6, RowCount = 4, Dock = DockStyle.Fill };
this.Controls.Add(table);
var list = Enumerable.Range('A', 'Z' - 'A' + 1)
.Select(x => ((char)x).ToString()).ToList();
list.ForEach(x => table.Controls.Add(new Button()
{ Text = x, Width = 32, Height = 32 }));
overlay.MouseDown += OverlayMouseDown;
overlay.MouseMove += OverlayMouseMove;
overlay.MouseUp += OverlayMouseUp;
overlay.Paint += OverlayPaint;
}
void OverlayMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
ProccessPoint(e.Location);
}
void OverlayMouseDown(object sender, MouseEventArgs e)
{
Clear();
ProccessPoint(e.Location);
}
void OverlayMouseUp(object sender, MouseEventArgs e)
{
if (points.Count > 0)
MessageBox.Show(string.Join(",", keys));
Clear();
}
void OverlayPaint(object sender, PaintEventArgs e)
{
if (points.Count >= 3)
e.Graphics.DrawCurve(Pens.Red, points.ToArray());
}
void ProccessPoint(Point p)
{
points.Add(p);
var c = table.Controls.Cast<Control>()
.Where(x => table.RectangleToScreen(x.Bounds)
.Contains(overlay.PointToScreen(p))).FirstOrDefault();
if ((c != null) && (keys.Count == 0 || keys[keys.Count - 1] != c.Text))
keys.Add(c.Text);
overlay.Invalidate();
}
void Clear()
{
keys.Clear();
points.Clear();
this.Refresh();
}

Related

C# Winform Panel clear / fully update --- used for mouse multiple selection

I want to select some structures (polygons and rectangles) in a panel. I have used the new ExtendedPanel Class, for the opacity of the mouse panel.
panel1 is for the structure, extendedPanel1 is for the selected area of the mouse. (SetSelectionRect() ist the set of the selections area)
In the figure below, the red is the graph I drew on panel1, and the green is the rectangle selected by the mouse. In fact, it should present a green rectangle, which is the rectangle when the mouse selection ends, but now there are many. This shows that the transparency setting in the extendetPanel1 works after extendedPanel1.Invalidate();, but the historical rectangle drawn does not disappear.
Can you please tell me, how should I write the code for the mouse selection in the Panel?
I actually want to realize some polygons and editing. I drew some polygons (rectangles) in panel1, and now I want to use the mouse to select some parts and make some changes (such as deleting some polygons).
My thoughts on this are: Draw the polygons on panel1, and panel2 displays the selection by the mouse, but the bottom of panel2 is transparent.
Then, according to the coordinate calculation, etc., it is judged whether the geometric figure in panel1 is in the area selected in panel2. If it is, then I will delete it. I don’t know if my thoughts are reasonable.
If you can provide a suitable solution, I am very grateful.
code of extendetpanel:
public class ExtendedPanel : Panel
{
private const int WS_EX_TRANSPARENT = 0x20;
public ExtendedPanel()
{
SetStyle(ControlStyles.Opaque, true);
}
private int opacity = 0;
[DefaultValue(0)]
public int Opacity
{
get
{
return this.opacity;
}
set
{
if (value < 0 || value > 100)
throw new ArgumentException("value must be between 0 and 100");
this.opacity = value;
}
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
return cp;
}
}
protected override void OnPaint(PaintEventArgs e)
{
using (var brush = new SolidBrush(Color.FromArgb(this.opacity * 255 / 100, this.BackColor)))
{
e.Graphics.FillRectangle(brush, this.ClientRectangle);
}
base.OnPaint(e);
}
}
Code of paint and events:
private void extendedPanel1_Paint(object sender, PaintEventArgs e)
{
base.OnPaint(e);
extendedPanel1.Opacity = 0;
if (mouseDown)
{
using (Pen pen = new Pen(Color.Green, 1F))
{
pen.DashStyle = DashStyle.Dash;
e.Graphics.DrawRectangle(pen, selection);
}
}
}
private void extendedPanel1_MouseDown(object sender, MouseEventArgs e)
{
selectionStart = extendedPanel1.PointToClient(MousePosition);
mouseDown = true;
}
private void extendedPanel1_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
SetSelectionRect();
extendedPanel1.Invalidate();
}
private void extendedPanel1_MouseMove(object sender, MouseEventArgs e)
{
if (!mouseDown)
return;
selectionEnd = extendedPanel1.PointToClient(MousePosition);
SetSelectionRect();
extendedPanel1.Invalidate();
}

How can I click on drawn points and make a external window opening?

I want to click on points that I drew.
It would be also cool if a window would popup and I could do something with that. But the general thing i want to do is clicking on a drawn point. I want to make it work, that i can click on the map on points that I drew.
Example image:
public partial class Form1 : Form
{
Graphics g;
Pen p;
Point cursor;
int k = 0;
Point[] points = new Point[50];
public Form1()
{
InitializeComponent();
g = pbxkarte.CreateGraphics();
p = new Pen(Color.DeepSkyBlue, 3);
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Pbxkarte_Click(object sender, EventArgs e)
{
if (drawmodecbx.Checked == true)
{
g.DrawEllipse(p, cursor.X - 10, cursor.Y - 10, 20, 20);
points[k++] = new Point(cursor.X, cursor.Y);
lbxDrawnPoints.Items.Add("X:" + cursor.X + "Y:" + cursor.Y);
}
}
private void Pbxkarte_MouseMove(object sender, MouseEventArgs e)
{
cursor = this.PointToClient(Cursor.Position);
xydisplay.Text = "X:" + cursor.X + "Y:" + cursor.Y;
}
}
}
Example code:
Two class level variables and a helper function:
List<Point> dots = new List<Point>();
int dotSize = 12;
Rectangle fromPoint(Point pt, int size)
{
return new Rectangle(pt.X - size/ 2, pt.Y - size / 2, size, size);
}
The mouseclick (as opposed to the click event) contains the location:
private void Pbxkarte_MouseClick(object sender, MouseEventArgs e)
{
if (!dots.Contains(e.Location))
{
dots.Add(e.Location);
Pbxkarte.Invalidate(); // show the dots
}
}
You could add code to remove dots or change the properties, esp. if you create a dot class. - If you want to avoid overlapping dots you can to use code like the one in the mousemove to detect this. But. Don't repeat the code! Instead factor out a boolOrPoint IsDotAt(Point) function you can use both times!!
In the mousemove I only show the hit state. You do your thing..
private void Pbxkarte_MouseMove(object sender, MouseEventArgs e)
{
bool hit = false;
foreach (var dot in dots)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddEllipse(fromPoint(dot, dotSize));
if (gp.IsVisible(e.Location))
{
hit = true; break;
}
}
}
Cursor = hit ? Cursors.Hand : Cursors.Default;
}
All dot in the list must get shown every time anything changes, both in the list or in the system.:
private void Pbxkarte_Paint(object sender, PaintEventArgs e)
{
foreach (var dot in dots)
{
using (GraphicsPath gp = new GraphicsPath())
{
gp.AddEllipse(fromPoint(dot, dotSize));
e.Graphics.FillPath(Brushes.Red, gp);
}
}
}
If you want more properties, like texts or colors do create a class dot and use a List<dot> !

How to get picturebox pixel color on mousemove

I tried to make drag and drop application . I drawn rectangle in run time and I want to detect if user try to move this rectangle or not
this is my code
private bool Mouse_Down = false;
Rectangle re = new Rectangle(100, 100, 60, 60);
private void DrawRegion_Paint(object sender, PaintEventArgs e)
{
e.Graphics.FillRectangle(new SolidBrush(Color.RoyalBlue), re);
}
private void DrawRegion_MouseMove(object sender, MouseEventArgs e)
{
if (Mouse_Down == true)
{
re.Location = e.Location;
if (re.Right > DrawRegion.Width)
{
re.X = DrawRegion.Width - re.Width;
}
if (re.Top < 0)
{
re.Y = 0;
}
if (re.Left < 0)
{
re.X = 0;
}
if (re.Bottom > DrawRegion.Height)
{
re.Y = DrawRegion.Height - re.Height;
}
Refresh();
}
}
private void DrawRegion_MouseUp(object sender, MouseEventArgs e)
{
Mouse_Down = false;
}
private void DrawRegion_MouseDown(object sender, MouseEventArgs e)
{
Mouse_Down = true;
}
For more details now this rectangle move either user click on this rectangle or in any empty space so I want to detect if clicked location color pixel is rectangle color pixel or not before moving rectangle how to do that ?
Note:DrawRegion is a picturebox
Sorry for bad English
You can use Rect.Contains() to detect if your Rectaingle contain your current location
private void DrawRegion_MouseClick(object sender,MouseEventArgs e)
{
if (re.Contains(e.Location))
Mouse_Down = true;
else
Mouse_Down = false;
}
check this https://msdn.microsoft.com/en-us/library/ms557979(v=vs.110).aspx

Change ComboBox Border Color - Flash when SelectedIndex changed

I just wanted to know if in windows forms I can create a red line around the border of a combobox when its changed? Like just a flash of red and then gone again just to show that it was changed. Catch the user's eye or something. I will provide screens to represent what i would like.
If it is possible, please tell me where I can look it up to gain some information on it.
No border
Border flash on change
Border gone again after a second or two
Anytime the combobox changes, I want to flash a border to indicate it has changed.
The main idea is using a timer and drawing a border for some times. You can draw the border using different solutions. For example you can (1) draw the border on ComboBox or (2) you can draw border on Parent of ComboBox.
In the answer which I posed, I created a MyComboBox and added a FlashHotBorder method which can be called to flash border. Also I added a HotBorderColor property which can be used to set border color.
Flashing Border of ComboBox
To draw a border for ComboBox you can handle WM_Paint message of ComboBox and draw a border for control. Then to flash the border, you need to use a timer and turn on and turn off border for some times:
MyComboBox Code
I've created a FlashHotBorder method which you can call in SelectedIndexChanged event. Also if always you want to flash border when selected index changes, you can call it in OnSelectedIndexChanged. I prefer to call it in event handler. Here is the implementation:
using System.Drawing;
using System.Windows.Forms;
public class MyComboBox : ComboBox
{
int flash = 0;
private const int WM_PAINT = 0xF;
private int buttonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
public Color HotBorderColor { get; set; }
private bool DrawBorder { get; set; }
Timer timer;
public MyComboBox()
{
this.HotBorderColor = Color.Red;
timer = new Timer() { Interval = 100 };
timer.Tick += new System.EventHandler(timer_Tick);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT && this.DrawBorder)
using (var g = Graphics.FromHwnd(this.Handle))
using (var p = new Pen(this.HotBorderColor))
g.DrawRectangle(p, 0, 0, this.Width - 1, this.Height - 1);
}
public void FlashHotBorder()
{
flash = 0;
timer.Start();
}
void timer_Tick(object sender, System.EventArgs e)
{
if (flash < 10)
{
flash++;
this.DrawBorder = !this.DrawBorder;
this.Invalidate();
}
else
{
timer.Stop();
flash = 0;
DrawBorder = false;
}
}
protected override void Dispose(bool disposing)
{
if (disposing) { timer.Dispose(); }
base.Dispose(disposing);
}
}
Then it's enough to use this event handler for SelectedIndexChanged event of eeach combo which you want to flash:
private void myComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var combo = sender as FlatCombo;
if (combo != null)
combo.FlashHotBorder();
}
You can create an outline/draw a border outside a comboBox or any other control using the DrawRectangle method.
The border will be drawn outside the comboBox if the SelectedIndex range condition satisfies else it'll revert to it's original state with no outline.
bool changed = false;
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (changed)
{
Pen p = new Pen(Color.Red);
Graphics g = e.Graphics;
int diff = 1;
g.DrawRectangle(p, new Rectangle(comboBox1.Location.X - diff, comboBox1.Location.Y - diff, comboBox1.Width + diff, comboBox1.Height + diff));
}
}
And, I am calling the Form1_Paint event on SelectedIndexChanged event of the comboBox.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex >= 1 && comboBox1.SelectedIndex <= 9)
{
changed = true;
this.Refresh();
}
else
{
changed = false;
this.Refresh();
}
}
                    Outline                                         Without Outline
So I came up with this. It's the shortest and easiest way to do it I think. If you have any recommendation, feel free to post them or comment it. thanx for all the help :).
public partial class Form1 : Form
{
private int tick = 0;
public Form1()
{
InitializeComponent();
}
bool changed = false;
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (changed == true)
{
changed = false;
this.Refresh();
}
else
{
if(tick<3)
{
timer1.Enabled = true;
timer1.Start();
}
changed = true;
this.Refresh();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
if (changed)
{
Graphics g1 = e.Graphics;
int diff = 1;
Rectangle rect2 = new Rectangle(comboBox1.Location.X - diff, comboBox1.Location.Y - diff, comboBox1.Width + diff, comboBox1.Height + diff);
using (LinearGradientBrush br = new LinearGradientBrush(rect2,Color.Red,Color.Blue,LinearGradientMode.Horizontal))
{
ColorBlend color_blend = new ColorBlend();
color_blend.Colors = new Color[] { Color.Red, Color.Orange, Color.Yellow, Color.Lime, Color.Blue, Color.Indigo, Color.DarkViolet};
color_blend.Positions = new float[] { 0 / 6f, 1 / 6f, 2 / 6f, 3 / 6f, 4 / 6f, 5 / 6f, 6 / 6f };
br.InterpolationColors = color_blend;
Pen p = new Pen(br, 10);
e.Graphics.DrawRectangle(p, rect2);
}
}
else
{
Pen p = new Pen(Color.Transparent);
Graphics g = e.Graphics;
int diff = 1;
g.DrawRectangle(p, new Rectangle(comboBox1.Location.X - diff, comboBox1.Location.Y - diff, comboBox1.Width + diff, comboBox1.Height + diff));
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if(tick<3)
{
comboBox1_SelectedIndexChanged(null, null);
tick++;
}
else
{
timer1.Stop();
tick = 0;
}
}
}

Use Fillpath with mouse input as flood fill between drawn paths?

(New to this and playing around with a basic paint application) Ive found detailed instructions to code a flood-fill but as i am new it is very hard to understand every bits of it, and instead of copying, i would like to try to make my own simple(small scale) flood-fill.
Would it be possible to use fillpath as a flood-fill? i would draw paths and use my mouse to determine my x,y, on screen and have the graphicspath find out if it has borders(points from the drawn paths) and if so, fill these paths with a color?
this is what ive come up with but obviously it doesnt work, so how would i go about to make this working?
namespace WindowsFormsApplication3
{
public partial class Form1 : Form
{
Graphics g;
readonly Pen pen = new Pen(Color.Navy, 2);
Point oldCoords;
GraphicsPath graphicsPaths = new GraphicsPath();
bool spaceFound = false;
public Form1()
{
InitializeComponent();
g = panel1.CreateGraphics();
}
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
Point mousePt = new Point(e.X, e.Y);
if (e.Button == MouseButtons.Right &&
graphicsPaths.IsVisible(mousePt))
{
spaceFound = true;
}
}
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (oldCoords.IsEmpty)
graphicsPaths.StartFigure();
else
{
graphicsPaths.AddLine(oldCoords, new Point(e.X, e.Y));
g.DrawPath(pen, graphicsPaths);
}
oldCoords = new Point(e.X, e.Y);
}
else
oldCoords = Point.Empty;
}
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
g.DrawPath(pen, graphicsPaths);
if(spaceFound == true)
{
g.FillPath(Brushes.AliceBlue, graphicsPaths);
}
}
}
}
Yes, this is quite possible; of course you would want to store the path in a List<GraphicsPath> in the MouseUp event to allow for more filled shapes..
You need to correct a few issues in your code:
Set the path.FillMode to Winding
Never cache a Graphics object
Never use control.CreateGraphics()
Don't cache Pens or Brushes
Only draw in the Paint event, unless you do not want the drawing to persist
The last point might actually apply here: Maybe you don't want the currently drawing outline to stay visible? In that, and only that case you can stick with drawing it in the MouseMove with a Graphics object created there on the fly.
Here is a corrected version:
Point oldCoords;
GraphicsPath graphicsPaths = new GraphicsPath() { FillMode = FillMode.Winding };
bool spaceFound = false;
private void drawPanel1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right && graphicsPaths.IsVisible(e.Location))
{
spaceFound = true;
drawPanel1.Invalidate();
}
}
private void drawPanel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (oldCoords.IsEmpty) graphicsPaths.StartFigure();
else
{
graphicsPaths.AddLine(oldCoords, new Point(e.X, e.Y));
drawPanel1.Invalidate();
}
oldCoords = new Point(e.X, e.Y);
}
else oldCoords = Point.Empty;
}
private void drawPanel1_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(Color.Black, 2f))
e.Graphics.DrawPath(pen, graphicsPaths);
if (spaceFound == true)
{
e.Graphics.FillPath(Brushes.AliceBlue, graphicsPaths);
}
}
Note that it will fill your path but not in the way of a true floodfill, i.e. it will always fill the whole path, not just the innermost segment you have clicked in. For a true floodfill much more involved code is needed that actually goes over all neighbouring pixels starting at the click location..
Examples of a true floodfill are here and here

Categories

Resources