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ù)進行 匹配和設(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ù)組來進行匹配
    {
        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)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市不铆,隨后出現(xiàn)的幾起案子蝌焚,更是在濱河造成了極大的恐慌裹唆,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件只洒,死亡現(xiàn)場離奇詭異许帐,居然都是意外死亡,警方通過查閱死者的電腦和手機毕谴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門成畦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人涝开,你說我怎么就攤上這事循帐。” “怎么了舀武?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵拄养,是天一觀的道長。 經(jīng)常有香客問我奕剃,道長,這世上最難降的妖魔是什么捐腿? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任纵朋,我火速辦了婚禮,結(jié)果婚禮上茄袖,老公的妹妹穿的比我還像新娘操软。我一直安慰自己,他們只是感情好宪祥,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布聂薪。 她就那樣靜靜地躺著,像睡著了一般蝗羊。 火紅的嫁衣襯著肌膚如雪藏澳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天耀找,我揣著相機與錄音翔悠,去河邊找鬼。 笑死野芒,一個胖子當(dāng)著我的面吹牛蓄愁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狞悲,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼撮抓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了摇锋?” 一聲冷哼從身側(cè)響起丹拯,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤站超,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后咽笼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體顷编,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年剑刑,在試婚紗的時候發(fā)現(xiàn)自己被綠了媳纬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡施掏,死狀恐怖钮惠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情七芭,我是刑警寧澤素挽,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站狸驳,受9級特大地震影響预明,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜耙箍,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一撰糠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辩昆,春花似錦阅酪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至施无,卻和暖如春辉词,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背猾骡。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工较屿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卓练。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓隘蝎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親襟企。 傳聞我的和親對象是個殘疾皇子嘱么,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容