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)過測試...