1、原版和例子都在这里

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

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

AutocompleteTextCtrl

下面是核心文件 autocomplete.py

  1. # -*- coding: utf-8 -*-
  2. __license__ = """Copyright (c) 2008-2010, Toni Ruža, All rights reserved.
  3. Redistribution and use in source and binary forms, with or without modification,
  4. are permitted provided that the following conditions are met:
  5. * Redistributions of source code must retain the above copyright notice,
  6. this list of conditions and the following disclaimer.
  7. * Redistributions in binary form must reproduce the above copyright notice,
  8. this list of conditions and the following disclaimer in the documentation
  9. and/or other materials provided with the distribution.
  10. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
  11. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  12. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  13. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  14. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  15. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  16. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  17. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  18. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  19. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  20. POSSIBILITY OF SUCH DAMAGE."""
  21. __author__ = u"Toni Ruža <gmr.gaf@gmail.com>"
  22. __url__ = "http://bitbucket.org/raz/wxautocompletectrl"
  23. import wx
  24. class SuggestionsPopup(wx.Frame):
  25. def __init__(self, parent):
  26. wx.Frame.__init__(
  27. self, parent,
  28. style=wx.FRAME_NO_TASKBAR|wx.FRAME_FLOAT_ON_PARENT|wx.STAY_ON_TOP
  29. )
  30. self._suggestions = self._listbox(self)
  31. self._suggestions.SetItemCount(0)
  32. self._unformated_suggestions = None
  33. class _listbox(wx.HtmlListBox):
  34. items = None
  35. def OnGetItem(self, n):
  36. return self.items[n]
  37. def SetSuggestions(self, suggestions, unformated_suggestions):
  38. self._suggestions.items = suggestions
  39. self._suggestions.SetItemCount(len(suggestions))
  40. self._suggestions.SetSelection(0)
  41. self._suggestions.Refresh()
  42. self._unformated_suggestions = unformated_suggestions
  43. def CursorUp(self):
  44. selection = self._suggestions.GetSelection()
  45. if selection > 0:
  46. self._suggestions.SetSelection(selection - 1)
  47. def CursorDown(self):
  48. selection = self._suggestions.GetSelection()
  49. last = self._suggestions.GetItemCount() - 1
  50. if selection < last:
  51. self._suggestions.SetSelection(selection + 1)
  52. def CursorHome(self):
  53. if self.IsShown():
  54. self._suggestions.SetSelection(0)
  55. def CursorEnd(self):
  56. if self.IsShown():
  57. self._suggestions.SetSelection(self._suggestions.GetItemCount() - 1)
  58. def GetSelectedSuggestion(self):
  59. return self._unformated_suggestions[self._suggestions.GetSelection()]
  60. def GetSuggestion(self, n):
  61. return self._unformated_suggestions[n]
  62. class AutocompleteTextCtrl(wx.TextCtrl):
  63. def __init__(
  64. self, parent,
  65. height=300, completer=None,
  66. multiline=False, frequency=250
  67. ):
  68. style = wx.TE_PROCESS_ENTER
  69. if multiline:
  70. style = style | wx.TE_MULTILINE
  71. wx.TextCtrl.__init__(self, parent, style=style)
  72. self.height = height
  73. self.frequency = frequency
  74. if completer:
  75. self.SetCompleter(completer)
  76. self.queued_popup = False
  77. self.skip_event = False
  78. def SetCompleter(self, completer):
  79. """
  80. Initializes the autocompletion. The 'completer' has to be a function
  81. with one argument (the current value of the control, ie. the query)
  82. and it has to return two lists: formated (html) and unformated
  83. suggestions.
  84. """
  85. self.completer = completer
  86. frame = self.Parent
  87. while not isinstance(frame, wx.Frame):
  88. frame = frame.Parent
  89. self.popup = SuggestionsPopup(frame)
  90. frame.Bind(wx.EVT_MOVE, self.OnMove)
  91. self.Bind(wx.EVT_TEXT, self.OnTextUpdate)
  92. self.Bind(wx.EVT_SIZE, self.OnSizeChange)
  93. self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
  94. self.popup._suggestions.Bind(wx.EVT_LEFT_DOWN, self.OnSuggestionClicked)
  95. self.popup._suggestions.Bind(wx.EVT_KEY_DOWN, self.OnSuggestionKeyDown)
  96. def AdjustPopupPosition(self):
  97. self.popup.Position = self.ClientToScreen((0, self.Size.height)).Get()
  98. def OnMove(self, event):
  99. self.AdjustPopupPosition()
  100. event.Skip()
  101. def OnTextUpdate(self, event):
  102. if self.skip_event:
  103. self.skip_event = False
  104. elif not self.queued_popup:
  105. wx.CallLater(self.frequency, self.AutoComplete)
  106. self.queued_popup = True
  107. event.Skip()
  108. def AutoComplete(self):
  109. self.queued_popup = False
  110. if self.Value != "":
  111. formated, unformated = self.completer(self.Value)
  112. if len(formated) > 0:
  113. self.popup.SetSuggestions(formated, unformated)
  114. self.AdjustPopupPosition()
  115. self.Unbind(wx.EVT_KILL_FOCUS)
  116. self.popup.ShowWithoutActivating()
  117. self.SetFocus()
  118. self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
  119. else:
  120. self.popup.Hide()
  121. else:
  122. self.popup.Hide()
  123. def OnSizeChange(self, event):
  124. self.popup.Size = (self.Size[0], self.height)
  125. event.Skip()
  126. def OnKeyDown(self, event):
  127. key = event.GetKeyCode()
  128. if key == wx.WXK_UP:
  129. self.popup.CursorUp()
  130. return
  131. elif key == wx.WXK_DOWN:
  132. self.popup.CursorDown()
  133. return
  134. elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER) and self.popup.Shown:
  135. self.skip_event = True
  136. self.SetValue(self.popup.GetSelectedSuggestion())
  137. self.SetInsertionPointEnd()
  138. self.popup.Hide()
  139. return
  140. elif key == wx.WXK_HOME:
  141. self.popup.CursorHome()
  142. elif key == wx.WXK_END:
  143. self.popup.CursorEnd()
  144. elif event.ControlDown() and unichr(key).lower() == "a":
  145. self.SelectAll()
  146. elif key == wx.WXK_ESCAPE:
  147. self.popup.Hide()
  148. return
  149. event.Skip()
  150. def OnSuggestionClicked(self, event):
  151. self.skip_event = True
  152. n = self.popup._suggestions.HitTest(event.Position)
  153. self.Value = self.popup.GetSuggestion(n)
  154. self.SetInsertionPointEnd()
  155. wx.CallAfter(self.SetFocus)
  156. event.Skip()
  157. def OnSuggestionKeyDown(self, event):
  158. key = event.GetKeyCode()
  159. if key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
  160. self.skip_event = True
  161. self.SetValue(self.popup.GetSelectedSuggestion())
  162. self.SetInsertionPointEnd()
  163. self.popup.Hide()
  164. event.Skip()
  165. def OnKillFocus(self, event):
  166. if not self.popup.IsActive():
  167. self.popup.Hide()
  168. event.Skip()

下面是用法举例 test_autocomplete.py

  1. # -*- coding: utf-8 -*-
  2. __license__ = """Copyright (c) 2008-2010, Toni Ruža, All rights reserved.
  3. Redistribution and use in source and binary forms, with or without modification,
  4. are permitted provided that the following conditions are met:
  5. * Redistributions of source code must retain the above copyright notice,
  6. this list of conditions and the following disclaimer.
  7. * Redistributions in binary form must reproduce the above copyright notice,
  8. this list of conditions and the following disclaimer in the documentation
  9. and/or other materials provided with the distribution.
  10. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
  11. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  12. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  13. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  14. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  15. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  16. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  17. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  18. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  19. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  20. POSSIBILITY OF SUCH DAMAGE."""
  21. __author__ = u"Toni Ruža <gmr.gaf@gmail.com>"
  22. __url__ = "http://bitbucket.org/raz/wxautocompletectrl"
  23. import sys
  24. import os
  25. import random
  26. import string
  27. import wx
  28. from autocomplete import AutocompleteTextCtrl
  29. template = "%s<b><u>%s</b></u>%s"
  30. def random_list_generator(query):
  31. formatted, unformatted = list(), list()
  32. if query:
  33. for i in xrange(random.randint(0, 30)):
  34. prefix = "".join(random.sample(string.letters, random.randint(0, 10)))
  35. postfix = "".join(random.sample(string.letters, random.randint(0, 10)))
  36. value = (prefix, query, postfix)
  37. formatted.append(template % value)
  38. unformatted.append("".join(value))
  39. return formatted, unformatted
  40. def list_completer(a_list):
  41. def completer(query):
  42. formatted, unformatted = list(), list()
  43. if query:
  44. unformatted = [item for item in a_list if query in item]
  45. for item in unformatted:
  46. s = item.find(query)
  47. formatted.append(
  48. template % (item[:s], query, item[s + len(query):])
  49. )
  50. return formatted, unformatted
  51. return completer
  52. def test():
  53. some_files = [
  54. name
  55. for path in sys.path if os.path.isdir(path)
  56. for name in os.listdir(path)
  57. ]
  58. quotes = open("taglines.txt").read().split("%%")
  59. app = wx.App(False)
  60. app.TopWindow = frame = wx.Frame(None)
  61. frame.Sizer = wx.FlexGridSizer(3, 2, 5, 5)
  62. frame.Sizer.AddGrowableCol(1)
  63. frame.Sizer.AddGrowableRow(2)
  64. # A completer must return two lists of the same length based
  65. # on the "query" (current value in the TextCtrl).
  66. #
  67. # The first list contains items to be shown in the popup window
  68. # to the user. These items can use HTML formatting. The second list
  69. # contains items that will be put in to the TextCtrl, usually the
  70. # items from the first list striped of formating.
  71. field1 = AutocompleteTextCtrl(frame, completer=random_list_generator)
  72. field2 = AutocompleteTextCtrl(frame, completer=list_completer(some_files))
  73. field3 = AutocompleteTextCtrl(
  74. frame, completer=list_completer(quotes), multiline=True
  75. )
  76. frame.Sizer.Add(wx.StaticText(frame, label="Random strings"))
  77. frame.Sizer.Add(field1, 0, wx.EXPAND)
  78. frame.Sizer.Add(wx.StaticText(frame, label="Files in sys.path"))
  79. frame.Sizer.Add(field2, 0, wx.EXPAND)
  80. frame.Sizer.Add(wx.StaticText(frame, label="Famous quotes"))
  81. frame.Sizer.Add(field3, 0, wx.EXPAND)
  82. frame.Show()
  83. app.MainLoop()
  84. if __name__ == '__main__':
  85. test()

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

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

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

  1. class AutocompleteTextCtrl(object):
  2. def __init__( self, textCtrl, completer=None, height=300, frequency=250 ):
  3. """
  4. textCtrl用于指出已经存在的wx.TextCtrl实例,其他参数意义和原版一样。
  5. """
  6. self.textCtrl = textCtrl
  7. self.height = height
  8. self.frequency = frequency
  9. if completer:
  10. self.SetCompleter(completer)
  11. self.queued_popup = False
  12. self.skip_event = False
  13. def SetCompleter(self, completer):
  14. """
  15. Initializes the autocompletion. The 'completer' has to be a function
  16. with one argument (the current value of the control, ie. the query)
  17. and it has to return two lists: formated (html) and unformated
  18. suggestions.
  19. """
  20. self.completer = completer
  21. frame = self.textCtrl.Parent
  22. while not isinstance(frame, wx.Frame):
  23. frame = frame.Parent
  24. self.popup = SuggestionsPopup(frame)
  25. frame.Bind(wx.EVT_MOVE, self.OnMove)
  26. self.textCtrl.Bind(wx.EVT_TEXT, self.OnTextUpdate)
  27. self.textCtrl.Bind(wx.EVT_SIZE, self.OnSizeChange)
  28. self.textCtrl.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
  29. self.popup._suggestions.Bind(wx.EVT_LEFT_DOWN, self.OnSuggestionClicked)
  30. self.popup._suggestions.Bind(wx.EVT_KEY_DOWN, self.OnSuggestionKeyDown)
  31. def AdjustPopupPosition(self):
  32. self.popup.Position = self.textCtrl.ClientToScreen((0, self.textCtrl.Size.height)).Get()
  33. def OnMove(self, event):
  34. self.AdjustPopupPosition()
  35. event.Skip()
  36. def OnTextUpdate(self, event):
  37. if self.skip_event:
  38. self.skip_event = False
  39. elif not self.queued_popup:
  40. wx.CallLater(self.frequency, self.AutoComplete)
  41. self.queued_popup = True
  42. event.Skip()
  43. def AutoComplete(self):
  44. self.queued_popup = False
  45. if self.textCtrl.Value != "":
  46. formated, unformated = self.completer(self.textCtrl.Value)
  47. if len(formated) > 0:
  48. self.popup.SetSuggestions(formated, unformated)
  49. self.AdjustPopupPosition()
  50. self.textCtrl.Unbind(wx.EVT_KILL_FOCUS)
  51. self.popup.ShowWithoutActivating()
  52. self.textCtrl.SetFocus()
  53. self.textCtrl.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
  54. else:
  55. self.popup.Hide()
  56. else:
  57. self.popup.Hide()
  58. def OnSizeChange(self, event):
  59. self.popup.Size = (self.textCtrl.Size[0], self.height)
  60. event.Skip()
  61. def OnKeyDown(self, event):
  62. key = event.GetKeyCode()
  63. if key == wx.WXK_UP:
  64. self.popup.CursorUp()
  65. return
  66. elif key == wx.WXK_DOWN:
  67. self.popup.CursorDown()
  68. return
  69. elif key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER) and self.popup.Shown:
  70. self.skip_event = True
  71. self.textCtrl.SetValue(self.popup.GetSelectedSuggestion())
  72. self.textCtrl.SetInsertionPointEnd()
  73. self.popup.Hide()
  74. return
  75. elif key == wx.WXK_HOME:
  76. self.popup.CursorHome()
  77. elif key == wx.WXK_END:
  78. self.popup.CursorEnd()
  79. elif event.ControlDown() and unichr(key).lower() == "a":
  80. self.SelectAll()
  81. elif key == wx.WXK_ESCAPE:
  82. self.popup.Hide()
  83. return
  84. event.Skip()
  85. def OnSuggestionClicked(self, event):
  86. self.skip_event = True
  87. n = self.popup._suggestions.HitTest(event.Position)
  88. self.textCtrl.Value = self.popup.GetSuggestion(n)
  89. self.textCtrl.SetInsertionPointEnd()
  90. wx.CallAfter(self.textCtrl.SetFocus)
  91. event.Skip()
  92. def OnSuggestionKeyDown(self, event):
  93. key = event.GetKeyCode()
  94. if key in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
  95. self.skip_event = True
  96. self.textCtrl.SetValue(self.popup.GetSelectedSuggestion())
  97. self.textCtrl.SetInsertionPointEnd()
  98. self.popup.Hide()
  99. event.Skip()
  100. def OnKillFocus(self, event):
  101. if not self.popup.IsActive():
  102. self.popup.Hide()
  103. 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. python下如何安装biopython

    本来是自学python,后来又了解到有biopython这个包,将想安装下来,结果折腾了我一上午...终于安装成了,哈哈哈,功夫不负有心啊 过程如下: 1.首先去http://biopython.or ...

  2. 基于pcDuino-V2的无线视频智能小车

    这段时间抽空做了个智能视频小车.包含了pid电机控制.socket网络编程.多线程编程.epoll机制.gtk图形界面编程. 这是界面: 小车的底层是用的stm32f405系列的单片机+电机驱动做的一 ...

  3. poj 2352 Stars 数星星 详解

    题目: poj 2352 Stars 数星星 题意:已知n个星星的坐标.每个星星都有一个等级,数值等于坐标系内纵坐标和横坐标皆不大于它的星星的个数.星星的坐标按照纵坐标从小到大的顺序给出,纵坐标相同时 ...

  4. charing animation

    FHD : full high definition,1920 x 1080,全高清 vendor/mediatek/proprietary/bootable/bootloader/lk/dev/lo ...

  5. 搭建web框架手册(一)

    昨天听完永康对EASYUI的介绍后终于明白了优秀的UI框架就是第一生产力,过去自己一直沉浸在后端代码中,完全忽视了前端的生产力交互,总觉得界面漂亮就是生产力,其实大错特错,真正的具有高效生产力的界面其 ...

  6. JsonResult类设置返回json的长度(工作笔记 json转化出错)

    public JsonResult PoundageReportSearch()         {    JsonResult jr = new JsonResult();        // 实例 ...

  7. 如何在网页标题栏加入logo图标?

    标题栏: <link rel="icon" href="ico地址" type="image/x-icon">收藏夹:<l ...

  8. BZOJ3434 [Wc2014]时空穿梭

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  9. SpringBoot IntelliJ创建简单的Restful接口

    使用SpringBoot快速建服务,和NodeJS使用express几乎一模一样,主要分为以下: 1.添加和安装依赖  2.添加路由(即接口) 3.对路由事件进行处理 同样坑的地方就是,祖国的防火墙太 ...

  10. C#工具代码

    反射获取当前请求参数 var prop = System.Type.GetType("System.Web.HttpContext, System.Web, Version=4.0.0.0, ...