利用C#制作一个仿IE地址栏的文本框.docx
- 文档编号:10561036
- 上传时间:2023-05-26
- 格式:DOCX
- 页数:17
- 大小:240.46KB
利用C#制作一个仿IE地址栏的文本框.docx
《利用C#制作一个仿IE地址栏的文本框.docx》由会员分享,可在线阅读,更多相关《利用C#制作一个仿IE地址栏的文本框.docx(17页珍藏版)》请在冰点文库上搜索。
利用C#制作一个仿IE地址栏的文本框
利用C#制作一个仿IE地址栏的文本框
丽水市汽车运输集团有限公司信息中心苟安廷
利用IE上网时,只要在地址栏中输入几个字母,与这几个字母模糊匹配的地址就会自动显示出来供用户选择(如下图),用户通过按键盘上的上、下箭头在已有选项中遍历,找到自己需要的选项后,按回车键进行选择,也可以直接用鼠标进行操作,非常方便,我们在程序中也可以利用这一功能,实现自动提示,方便用户输入,下面就以一个实际例子介绍我在工作中是如何实现的。
从上图中可以看出,最佳的办法似乎就是继承ComboBox写一个控件,在TextChanged事件中,根据内容变化决定是否应拉下提示框,以及该提示什么内容,在实际工作中我们发现,ComboBox非常难以控制,如修改了SelectedIndex属性后,会自动产生TextChanged事件,造成死循环等等,虽然可以添加其他一些变量来标记该文本改变是用户引起的还是由程序引起的以进行区别对待处理,但效果始终不理想,经过反复试验,最后选择了文本框+列表框的方式,并做成控件库供其他程序调用,效果很理想,其中,文本框接收用户输入,列表框提供选项让用户选择。
新建一个普通的windows应用程序用来测试,不妨取名为Test吧,然后单击菜单“文件”→“添加项目”→“新建项目(N)”,从弹出来的对话框选择“windows控件库”,将该项目和Test项目放在同一个文件夹中,不妨取名为“TextBoxExt”,该项目是本文的重点。
在“解决方案资源管理器”中,右键单击“TextBoxExt”项目,从弹出的菜单中选择“属性”,会弹出属性配置对话框,在左上角的“配置(C)”中选择“所有配置”,设置输出路径为“..\output”,注意,该输入有点特殊,两个小数点+反斜杠+output,意思是当前文件夹上一层的ouput文件夹(从VC过来的朋友可能比较熟悉这种方式),如下图:
编译一下,在“我的电脑”或“资源管理器”中我们可以就可以看到与TextBoxExt文件夹同一级自动创建了一个output文件夹,输出的TextboxExt.dll乖乖地躺在这里:
再来配置一下依赖性,点菜单“项目”→“设置依赖性(D)”,设置项目Test取决于“TextBoxExt”,至此,开发环境配置完毕。
在“解决方案资源管理器”中双击“UserControl1.cs”文件,再切换到代码窗口中。
为便于引用,我们将命名空间“namespaceTextBoxExt”改为“namespaceTools”,由于本控件继承于文本框,因此,将代码
publicclassUserControl1:
System.Windows.Forms.UserControl
{
publicUserControl1()
{
InitializeComponent();
}
修改为:
publicclassTextBoxExt:
System.Windows.Forms.TextBox
{
privateSystem.ComponentModel.Containercomponents=null;
publicTextBoxExt()
{
}
也就是说将命名空间改为Tools,将类名改为TextBoxExt,让该类继承于System.Windows.Forms.TextBox,并修改相应的构造函数。
编译成功后,在“解决方案资源管理器中”双击项目“Test”的“Form1.cs”来切换到窗体设计,在“工具箱”窗口中切换到“我的用户控件”选项中,在空白处单击右键,从弹出的菜单中选择“添加/移出项”,接下来会弹出一个对话框,点“浏览”按钮,找到刚才生成的控件库,如下图:
最后点“确定”按钮,在“工具箱”的“我的控件库”中就多了一个“TextBoxExt”控件,同操作普通文本框控件一样,在窗体上添加几个该自定义控件。
可以看出,该文本框和平时使用的文本框目前完全一样。
切换到UserControl1.cs代码设计窗口中,添加一个列表框变量,用于显示提示:
privateSystem.Windows.Forms.ListBoxm_lstShowChoice=null;
添加一段代码,用于响应列表框鼠标的MouseUp事件,也就是用户通过单击列表框进行选择:
privatevoidlstBox_MouseUp(objectsender,System.Windows.Forms.MouseEventArgse)
{
ListBoxbox=(ListBox)sender;
if((box.SelectedIndex>-1)&&!
this.ReadOnly)
{
this.Text=box.SelectedItem.ToString();
//选择后文本框失去了焦点,这里移回来
this.Focus();
}
}
添加鼠标在列表框中移动的事件,当用户在列表框中移动鼠标时,根据鼠标位置,自动设置列表框当前项。
privatevoidlstBox_MouseMove(objectsender,System.Windows.Forms.MouseEventArgse)
{
ListBoxbox=(ListBox)sender;
Pointpt=newPoint(e.X,e.Y);
intn=box.IndexFromPoint(pt);
if(n>=0)
box.SelectedIndex=n;
}
为了美观,可以设置列表框的前景、背景、边框风格等,按常规,我们可以设置一个public变量来供程序调用,但在程序设计时无法通过属性窗口直接修改,不方便,通过“性质”来引用可以解决,下面的代码是设置列表框的背景,比较好理解:
#region设置提示框的背景
privateColorm_lstForColor=System.Drawing.SystemColors.InfoText;
///
///设置/获取提示的背景色
///
publicColorPromptBackColor
{
get
{
returnm_lstBackColor;
}
set
{
m_lstBackColor=value;
//lstPrompt的创建见下面的代码
ListBoxbox=this.lstPrompt;
if(box!
=null)
box.BackColor=m_lstBackColor;
}
}
#endregion
设置前景、边框的方法完全一样,不再赘述,经过这样处理,我们在程序设计时就可以直接在“属性”窗口中指定了,如下图:
接下来,也是通过“性质”来返回当前列表框,如果没有则创建:
privateSystem.Windows.Forms.ListBoxlstPrompt
{
get
{
//如果没有列表用于显示提示的列表框,则创建一个
if((m_lstShowChoice==null)&&this.Parent!
=null)
{
m_lstShowChoice=newListBox();
m_lstShowChoice.Visible=false;
m_lstShowChoice.Left=this.Left;
m_lstShowChoice.Top=this.Bottom;
m_lstShowChoice.Width=this.Width;
m_lstShowChoice.TabStop=false;
m_lstShowChoice.Sorted=true;
m_lstShowChoice.ForeColor=this.m_lstForColor;//前景
m_lstShowChoice.BackColor=this.m_lstBackColor;//背景(参见m_lstForColor的创建
m_lstShowChoice.BorderStyle=this.m_lstBordrStyle;//边框,背景(参见m_lstForColor的创建
//如果提示框过低,则显示到上面
if(m_lstShowChoice.Bottom>this.Parent.Height)
m_lstShowChoice.Top=this.Top-m_lstShowChoice.Height+8;
m_lstShowChoice.MouseUp+=newSystem.Windows.Forms.MouseEventHandler(this.lstBox_MouseUp);
m_lstShowChoice.MouseMove+=newSystem.Windows.Forms.MouseEventHandler(this.lstBox_MouseMove);
this.Parent.Controls.Add(m_lstShowChoice);
this.Parent.ResumeLayout(false);
m_lstShowChoice.BringToFront();
}
returnm_lstShowChoice;
}
}
创建一个ArrayList用于存放全部可供选择的项目:
privateArrayListm_ForChoice=newArrayList();
publicArrayListChoiceArray
{
get
{
returnm_ForChoice;
}
set
{
m_ForChoice=(ArrayList)(value.Clone());
ListBoxbox=this.lstPrompt;
if(box!
=null)
{
box.Items.Clear();
box.Items.AddRange(m_ForChoice.ToArray());
}
}
}
用户在输入时,经常喜欢加空格,如两个字的姓名“张三”,用户喜欢输成“张三”,虽然可以和三个字的姓名对齐,比较美观,但对程序中姓名检索等非常不便,因为你还要判断中间是否有空格,有多少空格等,为此,我们设置一个“性质”来决定是否允许用户输入空格。
privateboolm_AllowSpace=false;
publicboolAllowSpace
{
get
{
returnm_AllowSpace;
}
set
{
m_AllowSpace=value;
}
}
在输入过程中,有些内容是只能选择不能输入的,就象我们将ComboBox的DropDownStyle设置为DropDownList一样,但为了方便用户,我们允许用户输入,光标离开本文本框时,进行检查,判断用户输入的内容是否在可选项内,如果不在,则清空用户输入,因此,添加下面变量:
privateboolm_bChoiceOnly=false;
publicboolChoicOnly
{
get
{
returnthis.m_bChoiceOnly;
}
set
{
this.m_bChoiceOnly=value;
}
}
按常理,我们应该在响应文本框的TextChange事件中根据文本变化来决定是否显示列表框,以及列表框中该出现哪些可选项,但同ComboBox一样,文本改变事件可能有多种事件连带引发(如程序使用了TextBox1.Text=”abc”之类),难以控制,我们这里响应KeyUp事件,在通过KeyUp和KeyDown的配合来完成,就避开了上述问题。
本文开始处我们说过,可以通过键盘上的“↑”和“↓”在可选项中遍历,而文本框默认上下箭头也用来移动当前键盘光标,因此,我们在KeyDown中记下当前光标位置,在KeyUp中恢复,故声明一个变量m_nOldPos来记录按键前键盘光标位置,在实际工作中我们发现,部分输入法存在BUG,用户键入一个键后,产生了一个KeyDown后产生两个KeyUp事件,为此,通过一个变量bKeyDown来记录键是否按下,供KeyUp正确判断,文本改变发生在KeyDown和KeyUp之间,因此,在KeyDown中必须记录当前文本,在KeyUp中判断文本是否改变,根据上述分析,我们添加文本框的KeyDown事件响应代码:
privateintm_nOldPos=0;
privateboolbKeyDown=false;
privatestringm_strOldText="";
privatevoidTextBoxExt_KeyDown(objectsender,System.Windows.Forms.KeyEventArgse)
{
m_nOldPos=this.SelectionStart;
bKeyDown=true;
m_strOldText=this.Text;
}
创建一个函数,用来根据文本框当前内容,从可供选择的m_ForChoice数组中筛选出模糊匹配的选项,添加到列表框中:
privatevoidFillPrompt(stringp_strText)
{
ListBoxbox=this.lstPrompt;
if(box!
=null)
{
box.Items.Clear();
if(p_strText.Length==0)//没有内容,显示全部
box.Items.AddRange(this.m_ForChoice.ToArray());
else
{
foreach(stringsinthis.m_ForChoice)
{
if(s.ToLower().IndexOf(p_strText.ToLower())>=0)
box.Items.Add(s);
}
}
}
}
添加文本框的KeyUp事件响应代码:
privatevoidTextBoxExt_KeyUp(objectsender,System.Windows.Forms.KeyEventArgse)
{
if(!
bKeyDown)//忽略掉多余的KeyUp事件
return;
bKeyDown=false;
ListBoxbox=this.lstPrompt;
switch(e.KeyCode)
{
//通过上下箭头在待选框中移动
caseSystem.Windows.Forms.Keys.Up:
caseSystem.Windows.Forms.Keys.Down:
if((box!
=null)&&!
this.Multiline)//多行文本通过上下箭头在两行之间移动
{
if((e.KeyCode==System.Windows.Forms.Keys.Up)&&(box.SelectedIndex>-1))//↑
box.SelectedIndex--;
elseif((e.KeyCode==System.Windows.Forms.Keys.Down)&&(box.SelectedIndex box.SelectedIndex++; //上下箭头不能移动当前光标,因此,还原原来位置 this.SelectionStart=m_nOldPos; //显示提示框 if(! box.Visible) { if(box.Width! =this.Width) box.Width=this.Width; box.Visible=true; } } break; caseSystem.Windows.Forms.Keys.Escape: //ESC隐藏提示 if((box! =null)&&box.Visible) box.Hide(); break; caseSystem.Windows.Forms.Keys.Return: //回车选择一个或跳到下一控件 if((box==null)||this.Multiline) break; //没有显示提示框时,移动到下一控件 if(! box.Visible) { SendKeys.Send("{TAB}"); } else//有提示,关闭提示 { if(box.SelectedIndex>-1)//有选择,使用当前选择的内容 this.Text=box.SelectedItem.ToString(); this.SelectionStart=this.Text.Length; this.SelectAll(); box.Hide(); } break; default: //判断文本是否改变 stringstrText=this.Text; //不允许产生空格,去掉文本中的空格 if(! m_AllowSpace) strText=this.Text.Replace("",""); intnStart=this.SelectionStart; if(strText! =m_strOldText)//文本有改变 { //设置当前文本和键盘光标位置 this.Text=strText; if(nStart>this.Text.Length) nStart=this.Text.Length; this.SelectionStart=nStart; //修改可供选择的内容,并显示供选择的列表框 if(box! =null) { this.FillPrompt(strText); if(! box.Visible) { if(box.Width! =this.Width) box.Width=this.Width; box.Visible=true; } } } break; } } 当文本框失去键盘光标后,必须隐藏提示,对于只选型文本框,还要判断用户输入是否在可选项中: privatevoidTextBoxExt_Leave(objectsender,System.EventArgse) { //对于只选字段,必须输入同待选相匹配的值 if(this.m_bChoiceOnly) { intnIndex=this.ChoiceArray.IndexOf(this.Text); if(nIndex<0) this.Text=""; } //失去焦点后,必须隐藏提示 ListBoxbox=this.lstPrompt; if(box! =null) box.Visible=false; } 在IE地址栏中,右边有一个“↓”,我们可以点该箭头来打开提示框,本例中没有增加该功能不能不说是一个缺陷,这里,我们用双击文本框的办法来代替(也可以通过在右边加一个按钮模拟下拉箭头,制作方法见笔者另一篇文章《在C#中制作组合控件》): privatevoidTextBoxExt_DoubleClick(objectsender,System.EventArgse) { if(this.ReadOnly) return; ListBoxbox=this.lstPrompt; if((box! =null)&&(! box.Visible)) { if(box.Width! =this.Width) box.Width=this.Width; box.Visible=true; } } 切换到Test项目Form1的代码窗口中,在前面添加一个引用: usingTools;并添加Form1的Load事件响应代码: privatevoidForm1_Load(objectsender,System.EventArgse) { //创建一个数组,用于填充本控件的可选项 ArrayListarr=newArrayList(); arr.Add("aaabbbcccddd"); arr.Add("bbbcccdddeee"); arr.Add("cccdddeeefff"); arr.Add("dddeeefffggg"); //遍历所有控件,筛选出增强型文本框控件进行可选项赋值 foreach(Controlctlinthis.Controls) { TextBoxExttxtbox=ctlasTextBoxExt; if(txtbox==null) continue; txtbox.ChoiceArray=arr; } } 运行一下,当在文本框中输入一些字母后,文本框会自动匹配,去掉不符合要求的文本,同时,通过按上下箭头、回车键、ESC键、双击等可以检验效果,运行结果如下图所示: 至此,类似IE地址栏的控件就开发完成了,在工作中可以扩充该控件,如在控件中增加一个“代表字段”的性质,程序设计时在属性窗口中指定其所代表的字段(如“姓名”),在上面Form1的Load事件的“foreach(Controlctlinthis.Contro
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 利用 C# 制作 一个 IE 地址栏 文本框
![提示](https://static.bingdoc.com/images/bang_tan.gif)