美文网首页
C# 实现输入提示选择框实现

C# 实现输入提示选择框实现

作者: choglala | 来源:发表于2016-08-10 16:39 被阅读0次

    C# 简单实现输入提示选择框

    鼠标钩子类:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows.Forms;
    using System.Drawing;
    using System.Runtime.InteropServices;
     
    namespace Common.Utils
    {
        public class MouseHook
        {
            private Point point;
            private Point Point
            {
                get { return point; }
                set
                {
                    if (point != value)
                    {
                        point = value;
                        if (MouseMoveEvent != null)
                        {
                            var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0);
                            MouseMoveEvent(this, e);
                        }
                    }
                }
            }
            private int hHook;
            public const int WH_MOUSE_LL = 14;
     
            private const int WM_NCLBUTTONDOWN = 513;
            private const int WM_NCLBUTTONUP = 514;
            private const int WM_NCRBUTTONDOWN = 516;
            private const int WM_NCRBUTTONUP = 517;
            private const int WM_NCMBUTTONDOWN = 519;
            private const int WM_NCMBUTTONUP = 520;
     
            public Win32Api.HookProc hProc;
            public MouseHook()
            {
                Point = new Point();
            }
            public int SetHook()
            {
                hProc = new Win32Api.HookProc(MouseHookProc);
                hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0);
                return hHook;
            }
            public void UnHook()
            {
                Win32Api.UnhookWindowsHookEx(hHook);
            }
            private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
            {
                Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct));
                if (MouseDownEvent != null && (wParam == WM_NCLBUTTONDOWN || wParam == WM_NCLBUTTONUP
                    || wParam == WM_NCRBUTTONDOWN || wParam == WM_NCRBUTTONUP
                    || wParam == WM_NCMBUTTONDOWN || wParam == WM_NCMBUTTONUP))
                {
                    var mouseButton = MouseButtons.None;
                    switch (wParam)
                    {
                        case WM_NCLBUTTONDOWN:
                        case WM_NCLBUTTONUP:
                            mouseButton = MouseButtons.Left;
                            break;
                        case WM_NCRBUTTONDOWN:
                        case WM_NCRBUTTONUP:
                            mouseButton = MouseButtons.Right;
                            break;
                        case WM_NCMBUTTONDOWN:
                        case WM_NCMBUTTONUP:
                            mouseButton = MouseButtons.Middle;
                            break;
                        default:
                            break;
                    }
                    var point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y);
                    var e = new MouseEventArgs(mouseButton, 0, point.X, point.Y, 0);
                    MouseDownEvent(this, e);
                }
                //如果返回1,则结束消息,这个消息到此为止,不再传递。
                //如果返回0或调用CallNextHookEx函数则消息出了这个钩子继续往下传递,也就是传给消息真正的接受者
                //return CallNextHookEx(hHook, nCode, wParam, lParam);
                if (nCode < 0)
                {
                    return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
                }
                else
                {
                    this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y);
                    return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
                }
            }
     
            //委托+事件(把钩到的消息封装为事件,由调用者处理)
            public delegate void MouseMoveHandler(object sender, MouseEventArgs e);
            public event MouseMoveHandler MouseMoveEvent;
     
            public delegate void MouseDownHandler(object sender, MouseEventArgs e);
            public event MouseDownHandler MouseDownEvent;
        }
    }
    

    使用的时候只需要绑定在需要使用的界面上面:
    需要注意的是 当前程序关闭的时候 一定需要将钩子 UnHook;

    MouseHook mh = new MouseHook();
    mh.SetHook();
    mh.MouseDownEvent += new MouseHook.MouseDownHandler(mh_MouseDownEvent);
    mh.MouseMoveEvent += new MouseHook.MouseMoveHandler(mh_MouseMoveEvent);
     
    void YBKTradeMarketEx_Disposed(object sender, EventArgs e)
    {
        if (mh != null)
        {
            mh.UnHook();
        }
    }
    

    鼠标钩子获取到的鼠标移动事件:

    // 当鼠标移动的时候 判断需要提示东西的对话框是否还存在 有没有被注销  
    void mh_MouseMoveEvent(object sender, MouseEventArgs e)
    {
        if (frmSymoblHint != null && !frmSymoblHint.IsDisposed)
        {
            // 获取当前windows 正在活动的控件  判断是否是对话匡 不是的话 
            // 就代表切换了 鼠标移动了就需要关闭 输入提示对话匡
            IntPtr intPtr = Win32Api.GetActiveWindow();
            if (intPtr != frmSymoblHint.Handle)
            {
                frmSymoblHint.Close();
            }
        }
    }
    

    鼠标钩子 获取到的鼠标点击事件:

    void mh_MouseDownEvent(object sender, MouseEventArgs e)
    {
        if (frmSymoblHint != null)
        {
            int x = e.Location.X;
            int y = e.Location.Y;
            Point point = new Point(x, y);
            Rectangle rect = new Rectangle(frmSymoblHint.Location.X, frmSymoblHint.Location.Y, frmSymoblHint.Width, frmSymoblHint.Height);
            // 判断鼠标钩子获取到的 鼠标点击事件,如果!点击到的不是当前的 输入提示对话匡 则关闭它!
            if (!frmSymoblHint.IsDisposed && frmSymoblHint.IsHandleCreated && !frmSymoblHint.Disposing && !rect.Contains(point))
            {
                frmSymoblHint.Close();
            }
        }
    }
    

    ----------------------------我是分割线-----------------------------
    frmSymbolHint 输入提示对话框
    由 textbox 和 ListView 组成

    绑定当前form 的键盘输入事件 :

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        if (keyData == Keys.Down)
        {
            if (lvwFlag >= lvwSymbols.Items.Count)
            {
                return true;
            }
            lvwFlag++;
            selectChange();
            Calc(true);
        }
        if (keyData == Keys.Up)
        {
            if (lvwFlag <= 0)
            {
                lvwFlag = 1;
                return true;
            }
            lvwFlag--;
            selectChange();
            Calc(false);
            if (txtSymbol.Focused)
            {
                return true;
            }
        }
        if (keyData == Keys.Escape)
        {
            this.Close();
        }
        if (keyData == Keys.Enter)
        {
            CheckedItemChangeProduct();
        }
        return base.ProcessCmdKey(ref msg, keyData);
    }
    

    selectChange 事件 当按下键盘 下或者上 或者鼠标点击 那个item的时候 绘制ListView里面 item的前景色和背景色:

    private void selectChange()
    {
        try
        {
            for (int j = 0; j < lvwSymbols.Items.Count; j++)
            {
                lvwSymbols.Items[j].BackColor = SystemColors.Window;
                lvwSymbols.Items[j].ForeColor = Color.Black;
            }
            lvwSymbols.Items[lvwFlag - 1].BackColor = SystemColors.Highlight;
            lvwSymbols.Items[lvwFlag - 1].ForeColor = Color.White;
            lvwSymbols.Items[lvwFlag - 1].Selected = false;
        }
        catch (ArgumentOutOfRangeException)
        {
            if (lvwSymbols.Items.Count > 0)
            {
                if (lvwFlag <= 0)
                {
                    lvwSymbols.Items[0].BackColor = SystemColors.Highlight;
                    lvwSymbols.Items[0].ForeColor = Color.White;
                    lvwSymbols.Items[0].Selected = false;
                }
                else
                {
                    lvwSymbols.Items[lvwSymbols.Items.Count - 1].BackColor = SystemColors.Highlight;
                    lvwSymbols.Items[lvwSymbols.Items.Count - 1].ForeColor = Color.White;
                    lvwSymbols.Items[lvwSymbols.Items.Count - 1].Selected = false;
                }
            }
        }
    }
    

    计算长度 和 win32Api 设置使滚动条滚动起来 -- 这个地儿 滚动条滚动可能不会特别精确。

    private void Calc(bool isDown)
    {
        int fontHeight = 0;
        var point = new Point();
        using (Graphics g = this.CreateGraphics())
        {
            SizeF string_size = g.MeasureString("字符串", this.Font);
            fontHeight = (int)string_size.Height;
        }
        for (int i = 0; i < lvwSymbols.Items.Count; i++)
        {
            point = lvwSymbols.Items[i].Position;
            if (lvwSymbols.Items[i].BackColor == SystemColors.Highlight)
            {
                point.Y += fontHeight;
     
                if (!lvwSymbols.ClientRectangle.Contains(point) && isDown)
                {
                    Win32Api.SendMessage(lvwSymbols.Handle, 0x0115, 1, 0); // 0x0115 WM_VSCROLL wParam= 1往下滚动 wParam = 0往上滚动
                }
                else if (lvwSymbols.ClientRectangle.Contains(point) && !isDown)
                {
                    Win32Api.SendMessage(lvwSymbols.Handle, 0x0115, 0, 0);
                }
            }
        }
    }
    

    当前选择的 listView item 被双击选择 循环判断哪个 item的backColor 是处于高亮状态 获取其数据 并发出事件:

    private void CheckedItemChangeProduct()
    {
        ListViewItem listViewItem = new ListViewItem();
        if (lvwSymbols.SelectedItems.Count <= 0)
        {
            for (int i = 0; i < lvwSymbols.Items.Count; i++)
            {
                if (lvwSymbols.Items[i].BackColor == SystemColors.Highlight)
                {
                    listViewItem = lvwSymbols.Items[i];
                }
            }
        }
        else
        {
            listViewItem = lvwSymbols.SelectedItems[0];
        }
        if (listViewItem == null) return;
     
        if (userProductNameAndSymbols)
        {
            var symbol = regex.Replace(listViewItem.Text, ""); // 
            if (ItemDoubleClick != null)
            {
                ItemDoubleClick(this, new SymbolHintEventArgs(symbol));
            }
        }
        else
        {
            var str1 = regex.Replace(listViewItem.Text, "");// 缩写
            var product = commonService.GetProductByProductNameAbbreviationsFromCache(str1);
            if (ItemDoubleClick != null)
            {
                ItemDoubleClick(this, new SymbolHintEventArgs(product.Symbol));
            }
        }
    }
    

    输入框输入的值发生改变事件 :
    可以根据两种格式的数据进行 匹配和设置 例如 : 000000(中国红套票) , ZGHTP(中国红套票)
    正则 表达式获取 正则:

    private Regex regex = new Regex(@"\([^\)]*?\)");
    
    void textBox1_TextChanged(object sender, EventArgs e)
    {
        lvwSymbols.Items.Clear();
        if (productNameAndSymbols == null || productNameAbbreviations == null)
        {
            // 重新去回去新的数据  数组 例如: 000000(中国红套票) 
            productNameAndSymbols = commonService.ProductSymbols;
            // 获取 首字母缩写 数组 例如:ZGHTP(中国红套票)
            productNameAbbreviations = commonService.ProductNameAbbreviations;
            // 重新触发 该事件 
            textBox1_TextChanged(sender, e);
        }
        if (CheckedTextIsNumber(txtSymbol.Text)) //判断当前输入的是 字母还是 数字 根据这个判断是用 哪个数组来进行匹配
        {
            for (int i = 0; i < productNameAndSymbols.Length; i++)
            {
                if (productNameAndSymbols[i].ToUpper().Contains(txtSymbol.Text))
                {
                    lvwSymbols.Items.Add(productNameAndSymbols[i]);
                }
            }
            userProductNameAndSymbols = true;
        }
        else
        {
            for (int i = 0; i < productNameAbbreviations.Length; i++)
            {
                if (productNameAbbreviations[i].ToUpper().Contains(txtSymbol.Text))
                {
                    lvwSymbols.Items.Add(productNameAbbreviations[i]);
                }
            }
            userProductNameAndSymbols = false;
        }
     
        if (string.IsNullOrEmpty(txtSymbol.Text))
        {
            this.Close();
        }
        selectChange();
    }
    

    当鼠标点击 item 改变当前选择的 item 绑定事件 :

    void lvwSymbols_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
    {
        lvwFlag = e.ItemIndex + 1;
        selectChange();
    }
    

    第一次发 写的特别粗糙 也是个刚写出来的东西。没有经过测试...

    相关文章

      网友评论

          本文标题:C# 实现输入提示选择框实现

          本文链接:https://www.haomeiwen.com/subject/lmdjsttx.html