C# 實現(xiàn)輸入提示選擇框?qū)崿F(xiàn)

C# 簡單實現(xiàn)輸入提示選擇框

鼠標(biāo)鉤子類:

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,則結(jié)束消息,這個消息到此為止,不再傳遞。
            //如果返回0或調(diào)用CallNextHookEx函數(shù)則消息出了這個鉤子繼續(xù)往下傳遞,也就是傳給消息真正的接受者
            //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);
            }
        }
 
        //委托+事件(把鉤到的消息封裝為事件,由調(diào)用者處理)
        public delegate void MouseMoveHandler(object sender, MouseEventArgs e);
        public event MouseMoveHandler MouseMoveEvent;
 
        public delegate void MouseDownHandler(object sender, MouseEventArgs e);
        public event MouseDownHandler MouseDownEvent;
    }
}

使用的時候只需要綁定在需要使用的界面上面:
需要注意的是 當(dāng)前程序關(guān)閉的時候 一定需要將鉤子 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();
    }
}

鼠標(biāo)鉤子獲取到的鼠標(biāo)移動事件:

// 當(dāng)鼠標(biāo)移動的時候 判斷需要提示東西的對話框是否還存在 有沒有被注銷  
void mh_MouseMoveEvent(object sender, MouseEventArgs e)
{
    if (frmSymoblHint != null && !frmSymoblHint.IsDisposed)
    {
        // 獲取當(dāng)前windows 正在活動的控件  判斷是否是對話匡 不是的話 
        // 就代表切換了 鼠標(biāo)移動了就需要關(guān)閉 輸入提示對話匡
        IntPtr intPtr = Win32Api.GetActiveWindow();
        if (intPtr != frmSymoblHint.Handle)
        {
            frmSymoblHint.Close();
        }
    }
}

鼠標(biāo)鉤子 獲取到的鼠標(biāo)點擊事件:

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);
        // 判斷鼠標(biāo)鉤子獲取到的 鼠標(biāo)點擊事件,如果!點擊到的不是當(dāng)前的 輸入提示對話匡 則關(guān)閉它!
        if (!frmSymoblHint.IsDisposed && frmSymoblHint.IsHandleCreated && !frmSymoblHint.Disposing && !rect.Contains(point))
        {
            frmSymoblHint.Close();
        }
    }
}

----------------------------我是分割線-----------------------------
frmSymbolHint 輸入提示對話框
由 textbox 和 ListView 組成

綁定當(dāng)前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 事件 當(dāng)按下鍵盤 下或者上 或者鼠標(biāo)點擊 那個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 設(shè)置使?jié)L動條滾動起來 -- 這個地兒 滾動條滾動可能不會特別精確。

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

當(dāng)前選擇的 listView item 被雙擊選擇 循環(huán)判斷哪個 item的backColor 是處于高亮狀態(tài) 獲取其數(shù)據(jù) 并發(fā)出事件:

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

輸入框輸入的值發(fā)生改變事件 :
可以根據(jù)兩種格式的數(shù)據(jù)進(jìn)行 匹配和設(shè)置 例如 : 000000(中國紅套票) , ZGHTP(中國紅套票)
正則 表達(dá)式獲取 正則:

private Regex regex = new Regex(@"\([^\)]*?\)");
void textBox1_TextChanged(object sender, EventArgs e)
{
    lvwSymbols.Items.Clear();
    if (productNameAndSymbols == null || productNameAbbreviations == null)
    {
        // 重新去回去新的數(shù)據(jù)  數(shù)組 例如: 000000(中國紅套票) 
        productNameAndSymbols = commonService.ProductSymbols;
        // 獲取 首字母縮寫 數(shù)組 例如:ZGHTP(中國紅套票)
        productNameAbbreviations = commonService.ProductNameAbbreviations;
        // 重新觸發(fā) 該事件 
        textBox1_TextChanged(sender, e);
    }
    if (CheckedTextIsNumber(txtSymbol.Text)) //判斷當(dāng)前輸入的是 字母還是 數(shù)字 根據(jù)這個判斷是用 哪個數(shù)組來進(jìn)行匹配
    {
        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();
}

當(dāng)鼠標(biāo)點擊 item 改變當(dāng)前選擇的 item 綁定事件 :

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

第一次發(fā) 寫的特別粗糙 也是個剛寫出來的東西。沒有經(jīng)過測試...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容