1、原版和例子都在这里

在浏览器的地址栏,或者在百度、google 输入文字的时候,输入框的下面会把有关的项目都提示出来。

wxPython 没有提供类似的控件,google 了一下,发现了一个,很好用。

AutocompleteTextCtrl

下面是核心文件 autocomplete.py

# -*- coding: utf-8 -*-
__license__ = """Copyright (c) 2008-2010, Toni Ruža, All rights reserved. Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.""" __author__ = u"Toni Ruža <gmr.gaf@gmail.com>"
__url__ = "http://bitbucket.org/raz/wxautocompletectrl" import wx class SuggestionsPopup(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(
self, parent,
style=wx.FRAME_NO_TASKBAR|wx.FRAME_FLOAT_ON_PARENT|wx.STAY_ON_TOP
)
self._suggestions = self._listbox(self)
self._suggestions.SetItemCount(0)
self._unformated_suggestions = None class _listbox(wx.HtmlListBox):
items = None def OnGetItem(self, n):
return self.items[n] def SetSuggestions(self, suggestions, unformated_suggestions):
self._suggestions.items = suggestions
self._suggestions.SetItemCount(len(suggestions))
self._suggestions.SetSelection(0)
self._suggestions.Refresh()
self._unformated_suggestions = unformated_suggestions def CursorUp(self):
selection = self._suggestions.GetSelection()
if selection > 0:
self._suggestions.SetSelection(selection - 1) def CursorDown(self):
selection = self._suggestions.GetSelection()
last = self._suggestions.GetItemCount() - 1
if selection < last:
self._suggestions.SetSelection(selection + 1) def CursorHome(self):
if self.IsShown():
self._suggestions.SetSelection(0) def CursorEnd(self):
if self.IsShown():
self._suggestions.SetSelection(self._suggestions.GetItemCount() - 1) def GetSelectedSuggestion(self):
return self._unformated_suggestions[self._suggestions.GetSelection()] def GetSuggestion(self, n):
return self._unformated_suggestions[n] class AutocompleteTextCtrl(wx.TextCtrl):
def __init__(
self, parent,
height=300, completer=None,
multiline=False, frequency=250
):
style = wx.TE_PROCESS_ENTER
if multiline:
style = style | wx.TE_MULTILINE
wx.TextCtrl.__init__(self, parent, style=style)
self.height = height
self.frequency = frequency
if completer:
self.SetCompleter(completer)
self.queued_popup = False
self.skip_event = False def SetCompleter(self, completer):
"""
Initializes the autocompletion. The 'completer' has to be a function
with one argument (the current value of the control, ie. the query)
and it has to return two lists: formated (html) and unformated
suggestions.
"""
self.completer = completer frame = self.Parent
while not isinstance(frame, wx.Frame):
frame = frame.Parent self.popup = SuggestionsPopup(frame) frame.Bind(wx.EVT_MOVE, self.OnMove)
self.Bind(wx.EVT_TEXT, self.OnTextUpdate)
self.Bind(wx.EVT_SIZE, self.OnSizeChange)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
self.popup._suggestions.Bind(wx.EVT_LEFT_DOWN, self.OnSuggestionClicked)
self.popup._suggestions.Bind(wx.EVT_KEY_DOWN, self.OnSuggestionKeyDown) def AdjustPopupPosition(self):
self.popup.Position = self.ClientToScreen((0, self.Size.height)).Get() def OnMove(self, event):
self.AdjustPopupPosition()
event.Skip() def OnTextUpdate(self, event):
if self.skip_event:
self.skip_event = False
elif not self.queued_popup:
wx.CallLater(self.frequency, self.AutoComplete)
self.queued_popup = True
event.Skip() def AutoComplete(self):
self.queued_popup = False
if self.Value != "":
formated, unformated = self.completer(self.Value)
if len(formated) > 0:
self.popup.SetSuggestions(formated, unformated)
self.AdjustPopupPosition()
self.Unbind(wx.EVT_KILL_FOCUS)
self.popup.ShowWithoutActivating()
self.SetFocus()
self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
else:
self.popup.Hide()
else:
self.popup.Hide() def OnSizeChange(self, event):
self.popup.Size = (self.Size[0], self.height)
event.Skip() def OnKeyDown(self, event):
key = event.GetKeyCode() if key == wx.WXK_UP:
self.popup.CursorUp()
return elif key == wx.WXK_DOWN:
self.popup.CursorDown()
return elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER) and self.popup.Shown:
self.skip_event = True
self.SetValue(self.popup.GetSelectedSuggestion())
self.SetInsertionPointEnd()
self.popup.Hide()
return elif key == wx.WXK_HOME:
self.popup.CursorHome() elif key == wx.WXK_END:
self.popup.CursorEnd() elif event.ControlDown() and unichr(key).lower() == "a":
self.SelectAll() elif key == wx.WXK_ESCAPE:
self.popup.Hide()
return event.Skip() def OnSuggestionClicked(self, event):
self.skip_event = True
n = self.popup._suggestions.HitTest(event.Position)
self.Value = self.popup.GetSuggestion(n)
self.SetInsertionPointEnd()
wx.CallAfter(self.SetFocus)
event.Skip() def OnSuggestionKeyDown(self, event):
key = event.GetKeyCode()
if key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
self.skip_event = True
self.SetValue(self.popup.GetSelectedSuggestion())
self.SetInsertionPointEnd()
self.popup.Hide()
event.Skip() def OnKillFocus(self, event):
if not self.popup.IsActive():
self.popup.Hide()
event.Skip()

下面是用法举例 test_autocomplete.py

# -*- coding: utf-8 -*-
__license__ = """Copyright (c) 2008-2010, Toni Ruža, All rights reserved. Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.""" __author__ = u"Toni Ruža <gmr.gaf@gmail.com>"
__url__ = "http://bitbucket.org/raz/wxautocompletectrl" import sys
import os
import random
import string
import wx
from autocomplete import AutocompleteTextCtrl template = "%s<b><u>%s</b></u>%s" def random_list_generator(query):
formatted, unformatted = list(), list()
if query:
for i in xrange(random.randint(0, 30)):
prefix = "".join(random.sample(string.letters, random.randint(0, 10)))
postfix = "".join(random.sample(string.letters, random.randint(0, 10)))
value = (prefix, query, postfix)
formatted.append(template % value)
unformatted.append("".join(value)) return formatted, unformatted def list_completer(a_list):
def completer(query):
formatted, unformatted = list(), list()
if query:
unformatted = [item for item in a_list if query in item]
for item in unformatted:
s = item.find(query)
formatted.append(
template % (item[:s], query, item[s + len(query):])
) return formatted, unformatted
return completer def test():
some_files = [
name
for path in sys.path if os.path.isdir(path)
for name in os.listdir(path)
]
quotes = open("taglines.txt").read().split("%%") app = wx.App(False)
app.TopWindow = frame = wx.Frame(None)
frame.Sizer = wx.FlexGridSizer(3, 2, 5, 5)
frame.Sizer.AddGrowableCol(1)
frame.Sizer.AddGrowableRow(2) # A completer must return two lists of the same length based
# on the "query" (current value in the TextCtrl).
#
# The first list contains items to be shown in the popup window
# to the user. These items can use HTML formatting. The second list
# contains items that will be put in to the TextCtrl, usually the
# items from the first list striped of formating. field1 = AutocompleteTextCtrl(frame, completer=random_list_generator)
field2 = AutocompleteTextCtrl(frame, completer=list_completer(some_files))
field3 = AutocompleteTextCtrl(
frame, completer=list_completer(quotes), multiline=True
) frame.Sizer.Add(wx.StaticText(frame, label="Random strings"))
frame.Sizer.Add(field1, 0, wx.EXPAND)
frame.Sizer.Add(wx.StaticText(frame, label="Files in sys.path"))
frame.Sizer.Add(field2, 0, wx.EXPAND)
frame.Sizer.Add(wx.StaticText(frame, label="Famous quotes"))
frame.Sizer.Add(field3, 0, wx.EXPAND)
frame.Show()
app.MainLoop() if __name__ == '__main__':
test()

2、为了配合 wxFormBuilder 做了一些修改

如果是配合 wxFormBuilder 使用,就要先在设计器里画一个 TextCtrl,然后再修改生成的代码,把原来的 TextCtrl 替换成 AutocompleteTextCtrl。这样做有些麻烦,每次小改界面都要记得重新替换代码。

如果 AutocompleteTextCtrl 不是从无到有的生成一个新的 TextCtrl 实例,而是能够绑定到已经存在的 TextCtrl 上 就可以避免反复替换代码了。比如,在 wxFormBuilder 生成的代码中,我们有了一个现成的控件 m_textCtrl1,如果接下来能够像 AutocompleteTextCtrl(m_textCtrl1) 这样包装一下使用就好了。原版并没有提供这样的功能,不过修改一下也很简单。下面是修改后的 AutocompleteTextCtrl 类。

class AutocompleteTextCtrl(object):
def __init__( self, textCtrl, completer=None, height=300, frequency=250 ):
"""
textCtrl用于指出已经存在的wx.TextCtrl实例,其他参数意义和原版一样。
"""
self.textCtrl = textCtrl
self.height = height
self.frequency = frequency
if completer:
self.SetCompleter(completer)
self.queued_popup = False
self.skip_event = False def SetCompleter(self, completer):
"""
Initializes the autocompletion. The 'completer' has to be a function
with one argument (the current value of the control, ie. the query)
and it has to return two lists: formated (html) and unformated
suggestions.
"""
self.completer = completer frame = self.textCtrl.Parent
while not isinstance(frame, wx.Frame):
frame = frame.Parent self.popup = SuggestionsPopup(frame) frame.Bind(wx.EVT_MOVE, self.OnMove)
self.textCtrl.Bind(wx.EVT_TEXT, self.OnTextUpdate)
self.textCtrl.Bind(wx.EVT_SIZE, self.OnSizeChange)
self.textCtrl.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
self.popup._suggestions.Bind(wx.EVT_LEFT_DOWN, self.OnSuggestionClicked)
self.popup._suggestions.Bind(wx.EVT_KEY_DOWN, self.OnSuggestionKeyDown) def AdjustPopupPosition(self):
self.popup.Position = self.textCtrl.ClientToScreen((0, self.textCtrl.Size.height)).Get() def OnMove(self, event):
self.AdjustPopupPosition()
event.Skip() def OnTextUpdate(self, event):
if self.skip_event:
self.skip_event = False
elif not self.queued_popup:
wx.CallLater(self.frequency, self.AutoComplete)
self.queued_popup = True
event.Skip() def AutoComplete(self):
self.queued_popup = False
if self.textCtrl.Value != "":
formated, unformated = self.completer(self.textCtrl.Value)
if len(formated) > 0:
self.popup.SetSuggestions(formated, unformated)
self.AdjustPopupPosition()
self.textCtrl.Unbind(wx.EVT_KILL_FOCUS)
self.popup.ShowWithoutActivating()
self.textCtrl.SetFocus()
self.textCtrl.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
else:
self.popup.Hide()
else:
self.popup.Hide() def OnSizeChange(self, event):
self.popup.Size = (self.textCtrl.Size[0], self.height)
event.Skip() def OnKeyDown(self, event):
key = event.GetKeyCode() if key == wx.WXK_UP:
self.popup.CursorUp()
return elif key == wx.WXK_DOWN:
self.popup.CursorDown()
return elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER) and self.popup.Shown:
self.skip_event = True
self.textCtrl.SetValue(self.popup.GetSelectedSuggestion())
self.textCtrl.SetInsertionPointEnd()
self.popup.Hide()
return elif key == wx.WXK_HOME:
self.popup.CursorHome() elif key == wx.WXK_END:
self.popup.CursorEnd() elif event.ControlDown() and unichr(key).lower() == "a":
self.SelectAll() elif key == wx.WXK_ESCAPE:
self.popup.Hide()
return event.Skip() def OnSuggestionClicked(self, event):
self.skip_event = True
n = self.popup._suggestions.HitTest(event.Position)
self.textCtrl.Value = self.popup.GetSuggestion(n)
self.textCtrl.SetInsertionPointEnd()
wx.CallAfter(self.textCtrl.SetFocus)
event.Skip() def OnSuggestionKeyDown(self, event):
key = event.GetKeyCode()
if key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
self.skip_event = True
self.textCtrl.SetValue(self.popup.GetSelectedSuggestion())
self.textCtrl.SetInsertionPointEnd()
self.popup.Hide()
event.Skip() def OnKillFocus(self, event):
if not self.popup.IsActive():
self.popup.Hide()
event.Skip()

wxPython 自动提示文本框的更多相关文章

  1. Android 自学之自动完成文本框 AutoCompleteTextView

    自动完成文本框(AutoCompleteTextView)从EditText派生而出,实际上他也是一个编辑框,但他比普通的编辑框多了一个功能:当用户输入一定字符后,自动完成文本框会显示一个下拉菜单,供 ...

  2. Android开发10.2:UI组件AutoCompleteTextView(自动完成文本框)

    概述 AutoCompleteTextVeiw(自动完成文本框)从 EditText派生而出  PS :EditText用法介绍           当用户输入一定字符后,自动完成自动完成文本框会显示 ...

  3. android脚步---自动完成文本框

    自动完成文本框AutoCompleteTextView,当用户输入一定字符时,自动完成文本框会显示一个下拉菜单,供用户选择,设置一个Adapter,该Adapter中封装了AutoCompleteTe ...

  4. Android零基础入门第47节:自动完成文本框AutoCompleteTextView

    原文:Android零基础入门第47节:自动完成文本框AutoCompleteTextView 上一期学习的Spinner的使用,掌握的怎么样?本期一起来学习AutoCompleteTextView的 ...

  5. AutoCompleteTextView自动完成文本框

    AutoCompleteTextView是从EditText派生出来的,比普通编辑框多了一个功能,当用户输入一定字符后,自动完成文本框会显示一个下拉单,供用户选择,当选中一个后,被选中的内容会显示在文 ...

  6. JS实现动态提示文本框可输入剩余字数(类似发表微博数字提示)

    一.实现效果: 为了更直观的体现用户在文本框输入文本时能看到自己输入了多少字,项目中需要通过判断提示文本框剩余可输入字数. html & JS: <div> <textare ...

  7. javascript 文字大小自动适应文本框 (文字大小自动调整)

    javascript 文字大小自动适应文本框 (文字大小自动调整) TOC 思考 思考一:面积法 思考二:微调法 代码 在进行类似微博墙之类的展示页面中,经常会遇到这样的需求:在固定大小的区域放入字数 ...

  8. Android自己主动提示文本框(AutoCompleteTextView)

    自己主动提示文本框(AutoCompleteTextView)能够加强用户体验,缩短用户的输入时间(百度的搜索框就是这个效果). 首先.在xml中定义AutoCompleteTextView控件: a ...

  9. Android 开发笔记___AutoComplateTextView__自动完成文本框

    原理:EdtText结合监听器TextWatcher与下拉框spinner,一旦监控到EditText的文本发生变化,就自动弹出适配好的文字下拉内容. 属性以及设置方法: XML中的属性 代码中 说明 ...

随机推荐

  1. 使用Servlet和JSP实现一个简单的Web聊天室系统

    1 问题描述                                                利用Java EE相关技术实现一个简单的Web聊天室系统,具体要求如下. (1)编写一个登录 ...

  2. 在Azure上部署Windows Server Core

    作为服务器操作系统,图形界面真心有些多余了,这也是很多人喜欢Linux服务器的原因之一.从Windows Server 2008开始,微软提供了Server Core版本,其实就是一个没有图形界面的服 ...

  3. (转)也谈BIO | NIO | AIO (Java版)

    原文地址: https://my.oschina.net/bluesky0leon/blog/132361 关于BIO | NIO | AIO的讨论一直存在,有时候也很容易让人混淆,就我的理解,给出一 ...

  4. 安装ArcGIS Engine 9.3

    本文仅用于学习交流,商业用途请支持正版!转载请注明:http://www.cnblogs.com/mxbs/p/6217003.html 准备: ArcGIS Engine 9.3.crack_for ...

  5. 值得注意的IsHitTestVisible

    这个属性我们平时可能并不怎么用.先来看下MSDN上的解释: 解释的非常专业,然而我并没有看懂. 说说我的理解吧:把这个属性设置为false,看起来没有变化,但操作上已经把他完全忽视了,不触发事件,可以 ...

  6. 百度广告 高亮 Chrome插件(附源码)

    一前言 百度最近是上了舆论头条了,相信中过百度毒的人对百度都反感.百度自己挖了这么多坑,终究还是要自己来填.国内网民使且最频繁的搜过 还是以百度为主,而百度依靠这种市场占有率靠他的广告竞价排名大发横财 ...

  7. Alpha阶段总结

    Alpha阶段的验收已经完成,8个小组都展现了他们经过连夜奋战后的成果.相比过往几届,这是第一次8个小组全部顺利演示操作完成,没有个别小组因为任务未完成而延宕演示的情况发生.Alpha演示,各组都实现 ...

  8. 0104探究MySQL优化器对索引和JOIN顺序的选择

    转自http://www.jb51.net/article/67007.htm,感谢博主 本文通过一个案例来看看MySQL优化器如何选择索引和JOIN顺序.表结构和数据准备参考本文最后部分" ...

  9. maven

    maven常见问题问答 1.前言 Maven,发音是[`meivin],"专家"的意思.它是一个很好的项目管理工具,很早就进入了我的必备工具行列,但是这次为了把project1项目 ...

  10. Android环境变量配置

    第一步: 把这些东西全部准备好!然后jdk怎么安装我相信大家都知道.安装好jdk之后,我们来配置环境变量. 我的电脑—右键—属性—高级系统设置—环境变量 JAVA_HOME环境变量.它指向jdk的安装 ...