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();
}
第一次发 写的特别粗糙 也是个刚写出来的东西。没有经过测试...
网友评论