【问题标题】:Virtual Keyboard (Swype like Keyboard) Windows Forms Application C#虚拟键盘(像键盘一样的 Swype)Windows 窗体应用程序 C#
【发布时间】:2017-09-30 13:29:43
【问题描述】:

我正在尝试使用 c# 在 Windows 窗体中创建类似键盘的 swype

我有两个问题: 一种。我无法重现手指滑动动作。 湾。我无法识别不同键下的字母。

对于第一个问题:

我使用了 Graphics 类和 Pen 类,并像这样使用它:

    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;
        }
    }

但这里的问题是它从屏幕的左上角开始绘制,而不是从按钮的位置开始绘制。它也不会在按钮上绘制。路径中的任何控件都与该线重叠。

第二期:

一个。我使用鼠标按下事件将布尔值“允许”设置为 true,然后当鼠标移动时,我尝试获取按钮的文本。就像上图一样。我尝试从字母“S”开始,当我移过其他字母时,只有字母“S”继续记录。其他方法的 Mouse Enter 或 Mouse Hover 事件甚至都不会发生。

b.我也尝试过使用拖放事件,但它也不起作用。我不确定,但我假设按钮不是可拖动的对象,因此拖放事件不起作用。

我不明白或困惑如何实现我的目标。

【问题讨论】:

  • 我假设当您开始绘制时,您会从左上角到鼠标位置得到一条线?这可能是因为您的 prevx/prevy 变量是默认值 (0),在这种情况下,您希望将绘图推迟到第二个鼠标移动事件,这应该会给您正确的结果。不过,我无法对问题的其余部分发表评论
  • 这是非常基本的。您不能使用 Button 控件,它们会剪切您绘制的任何内容并拥有自己的鼠标处理。您必须通过 Paint 事件使它们看起来像按钮。
  • @HansPassant 有没有办法在做动作时检测字母?
  • 您首先需要一个可以从普通鼠标点击中选择正确字母的 hittest 方法。一旦你有了它,“动态”做就不会成为障碍。
  • @Akhil 看看this post中的解决方案2

标签: c# .net winforms windows-forms-designer


【解决方案1】:

您可以创建自定义控件并自行处理其绘制。

但是,如果您要使用 Button 控件并希望在这些按钮上进行绘制,您可以在这些按钮上放置一个透明面板作为叠加层,然后在透明面板上绘制滑动路径:

透明面板

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)
    {
    }
}

示例表格

这只是一个演示透明控件用法的示例。为此,只需创建一个表单并将其内容替换为以下代码即可:

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();
}

【讨论】:

    猜你喜欢
    • 2013-01-03
    • 2019-12-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 2013-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多