使用 Python 的过滤方法的预测文本 MDDropdown
Predictive Text MDDropdown with Python's filter Method
我正在尝试在 KivyMD 应用程序上构建预测文本 MDDropdown。我有一个 MDTextField,用户将在其中输入文本。当用户写下 his/her 搜索时,MDDropdown 应该显示包含所写文本的项目。选择任何给定项目时,应将所选内容的全文添加到 TextField。
我试过Python的过滤方法来完成这样的任务,但是我没有成功。输入文本时永远不会打开 MDDropdown。另外,我注意到过滤器函数会查找完全匹配项。有没有办法过滤字符串的部分部分?
Python代码如下:
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.app import MDApp
from kivymd.uix.button import MDIconButton, MDTooltip
from kivymd.uix.menu import MDDropdownMenu
from kivy.clock import Clock
class TooltipMDIconButton(MDIconButton, MDTooltip):
pass
# HOJA DE ACTIVIDADES ################################
class IngActivWindow(Screen):
menu_cliente = None
def cliente_dropdown(self):
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
if len(self.ids.name_client.text) != 0:
def filtar_clientes(cliente):
filtrar_valor = self.ids.name_client.text
if cliente in filtrar_valor:
return True
else:
return False
filtered = filter(lambda l: str(self.ids.name_client.text) in l, clientes)
for valores in filtered:
print(valores)
# Create the drop down menu
for cliente in filtered:
menu_items = [{"text": f"{valores}"} for valores in filtered]
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
self.menu_cliente.bind(on_release=self.set_item_cliente)
def open_clientes_list(self):
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
# Create the drop down menu
menu_items = [{"text": f"{cliente}"} for cliente in clientes]
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
self.menu_cliente.bind(on_release=self.set_item_cliente)
def set_item_cliente(self, instance_menu, instance_menu_item):
def set_item_cliente(interval):
self.ids.name_client.text = instance_menu_item.text
instance_menu.dismiss()
Clock.schedule_once(set_item_cliente, 0.5)
# WINDOW MANAGER ################################
class WindowManager(ScreenManager):
pass
# MAIN CLASS ################################
class PredictiveDropdown(MDApp):
def build(self):
return WindowManager()
if __name__ == "__main__":
PredictiveDropdown().run()
基维密码:
<WindowManager>:
id: screen_manager
IngActivWindow:
id: ingActiv
name: 'ingActiv'
<IngActivWindow>:
MDBoxLayout:
orientation: 'horizontal'
size_hint: 1, 1
pos_hint: {'center_x':0.5 , 'center_y':0.5}
padding: '20dp'
MDTextField:
id: name_client
pos_hint: {"x":0, 'center_y': 0.5}
write_tab: False
size_hint: 0.45, None
halign: 'left'
valign: 'center'
hint_text:'Seleccionar Cliente o Prospecto'
on_text: root.cliente_dropdown()
TooltipMDIconButton:
id: client_list
pos_hint: {"x":0, 'center_y': 0.5}
valign: 'center'
icon: 'arrow-down-drop-circle-outline'
tooltip_text: 'Haga clic para visualizar la lista completa de clientes'
on_release: root.open_clientes_list()
有什么关于如何完成预期任务的建议吗?我做错了什么?
非常感谢。
编辑
有没有一种方法可以按角色的位置进行过滤?我更改了 filtered 变量代码。现在,当我打字时,我确实得到了一份打印清单。但是,如果我写 'a',我会得到所有带有 a 的元素,例如 'Calvin Klein'。我希望程序只打印 'Amazon' 和 'Adidas'。我已经相应地修改了我的代码。
DropDown
永远不会打开,因为您正在使用 filter
在您 print
filter
的结果时产生的 iterator
。 iterator
一旦使用,就不能重复使用。要解决这个问题,只需删除以下行:
for valores in filtered:
print(valores)
考虑使用 regular expressions。而不是 filter
来获取您的 filtered
列表。
另外两个问题。您正在循环 for valores in filtered:
中打开 DropDown
,但我不明白您为什么要在循环中这样做。由于您在 kv
中使用 on_text
触发 cliente_dropdown()
方法,因此当您的 set_item_cliente()
方法更改文本时,它将再次触发。解决方法是在下拉菜单更改文本时禁用 cliente_dropdown()
方法。
这是您的 IngActivWindow
class 的修改版本,解决了这些问题:
class IngActivWindow(Screen):
menu_cliente = None
do_dropdown = True
def cliente_dropdown(self):
# do not open a dropdown if the text was changed by the dropdown
if not self.do_dropdown:
return
if self.menu_cliente:
# if dropdown is already open, close it
self.menu_cliente.dismiss()
self.menu_cliente = None
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
filtered_list = []
if len(self.ids.name_client.text) != 0:
prefix = self.ids.name_client.text.title()
filtered = filter(lambda l: l.startswith(prefix), clientes)
menu_items = [{"text": f"{valores}"} for valores in filtered]
if len(menu_items) < 1:
return
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
callback=self.set_item_cliente, # use callback instead of bind
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
def open_clientes_list(self):
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
# Create the drop down menu
menu_items = [{"text": f"{cliente}"} for cliente in clientes]
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
self.menu_cliente.bind(on_release=self.set_item_cliente)
def set_item_cliente(self, instance_menu_item):
def set_item_cliente(interval):
self.do_dropdown = False
self.ids.name_client.text = instance_menu_item.text
self.menu_cliente.dismiss()
self.menu_cliente = None
self.do_dropdown = True
Clock.schedule_once(set_item_cliente, 0.5)
我将 cliente_dropdown 函数更改为:
def cliente_dropdown(self):
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
filtered_list = []
if len(self.ids.name_client.text) != 0:
prefix = self.ids.name_client.text.title()
filtered = filter(lambda l: l.startswith(prefix), clientes)
# Create the drop down menu
for valores in filtered:
filtered_list.append(valores)
menu_items = [{"text": f"{valores}"} for valores in filtered_list]
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
self.menu_cliente.bind(on_release=self.set_item_cliente)
这很管用,正是我需要的。但是,下拉菜单会不断打开一个在另一个之上。我希望前一个 MDDropdown 在后一个打开之前关闭。
有什么建议吗?非常感谢!
我正在尝试在 KivyMD 应用程序上构建预测文本 MDDropdown。我有一个 MDTextField,用户将在其中输入文本。当用户写下 his/her 搜索时,MDDropdown 应该显示包含所写文本的项目。选择任何给定项目时,应将所选内容的全文添加到 TextField。
我试过Python的过滤方法来完成这样的任务,但是我没有成功。输入文本时永远不会打开 MDDropdown。另外,我注意到过滤器函数会查找完全匹配项。有没有办法过滤字符串的部分部分?
Python代码如下:
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.app import MDApp
from kivymd.uix.button import MDIconButton, MDTooltip
from kivymd.uix.menu import MDDropdownMenu
from kivy.clock import Clock
class TooltipMDIconButton(MDIconButton, MDTooltip):
pass
# HOJA DE ACTIVIDADES ################################
class IngActivWindow(Screen):
menu_cliente = None
def cliente_dropdown(self):
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
if len(self.ids.name_client.text) != 0:
def filtar_clientes(cliente):
filtrar_valor = self.ids.name_client.text
if cliente in filtrar_valor:
return True
else:
return False
filtered = filter(lambda l: str(self.ids.name_client.text) in l, clientes)
for valores in filtered:
print(valores)
# Create the drop down menu
for cliente in filtered:
menu_items = [{"text": f"{valores}"} for valores in filtered]
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
self.menu_cliente.bind(on_release=self.set_item_cliente)
def open_clientes_list(self):
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
# Create the drop down menu
menu_items = [{"text": f"{cliente}"} for cliente in clientes]
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
self.menu_cliente.bind(on_release=self.set_item_cliente)
def set_item_cliente(self, instance_menu, instance_menu_item):
def set_item_cliente(interval):
self.ids.name_client.text = instance_menu_item.text
instance_menu.dismiss()
Clock.schedule_once(set_item_cliente, 0.5)
# WINDOW MANAGER ################################
class WindowManager(ScreenManager):
pass
# MAIN CLASS ################################
class PredictiveDropdown(MDApp):
def build(self):
return WindowManager()
if __name__ == "__main__":
PredictiveDropdown().run()
基维密码:
<WindowManager>:
id: screen_manager
IngActivWindow:
id: ingActiv
name: 'ingActiv'
<IngActivWindow>:
MDBoxLayout:
orientation: 'horizontal'
size_hint: 1, 1
pos_hint: {'center_x':0.5 , 'center_y':0.5}
padding: '20dp'
MDTextField:
id: name_client
pos_hint: {"x":0, 'center_y': 0.5}
write_tab: False
size_hint: 0.45, None
halign: 'left'
valign: 'center'
hint_text:'Seleccionar Cliente o Prospecto'
on_text: root.cliente_dropdown()
TooltipMDIconButton:
id: client_list
pos_hint: {"x":0, 'center_y': 0.5}
valign: 'center'
icon: 'arrow-down-drop-circle-outline'
tooltip_text: 'Haga clic para visualizar la lista completa de clientes'
on_release: root.open_clientes_list()
有什么关于如何完成预期任务的建议吗?我做错了什么?
非常感谢。
编辑 有没有一种方法可以按角色的位置进行过滤?我更改了 filtered 变量代码。现在,当我打字时,我确实得到了一份打印清单。但是,如果我写 'a',我会得到所有带有 a 的元素,例如 'Calvin Klein'。我希望程序只打印 'Amazon' 和 'Adidas'。我已经相应地修改了我的代码。
DropDown
永远不会打开,因为您正在使用 filter
在您 print
filter
的结果时产生的 iterator
。 iterator
一旦使用,就不能重复使用。要解决这个问题,只需删除以下行:
for valores in filtered:
print(valores)
考虑使用 regular expressions。而不是 filter
来获取您的 filtered
列表。
另外两个问题。您正在循环 for valores in filtered:
中打开 DropDown
,但我不明白您为什么要在循环中这样做。由于您在 kv
中使用 on_text
触发 cliente_dropdown()
方法,因此当您的 set_item_cliente()
方法更改文本时,它将再次触发。解决方法是在下拉菜单更改文本时禁用 cliente_dropdown()
方法。
这是您的 IngActivWindow
class 的修改版本,解决了这些问题:
class IngActivWindow(Screen):
menu_cliente = None
do_dropdown = True
def cliente_dropdown(self):
# do not open a dropdown if the text was changed by the dropdown
if not self.do_dropdown:
return
if self.menu_cliente:
# if dropdown is already open, close it
self.menu_cliente.dismiss()
self.menu_cliente = None
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
filtered_list = []
if len(self.ids.name_client.text) != 0:
prefix = self.ids.name_client.text.title()
filtered = filter(lambda l: l.startswith(prefix), clientes)
menu_items = [{"text": f"{valores}"} for valores in filtered]
if len(menu_items) < 1:
return
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
callback=self.set_item_cliente, # use callback instead of bind
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
def open_clientes_list(self):
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
# Create the drop down menu
menu_items = [{"text": f"{cliente}"} for cliente in clientes]
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
self.menu_cliente.bind(on_release=self.set_item_cliente)
def set_item_cliente(self, instance_menu_item):
def set_item_cliente(interval):
self.do_dropdown = False
self.ids.name_client.text = instance_menu_item.text
self.menu_cliente.dismiss()
self.menu_cliente = None
self.do_dropdown = True
Clock.schedule_once(set_item_cliente, 0.5)
我将 cliente_dropdown 函数更改为:
def cliente_dropdown(self):
clientes = ['Amazon', 'Adidas','Banana Republic', 'Calvin Klein','Coach', 'DKNY', 'Microsoft','Nike', 'Sony']
filtered_list = []
if len(self.ids.name_client.text) != 0:
prefix = self.ids.name_client.text.title()
filtered = filter(lambda l: l.startswith(prefix), clientes)
# Create the drop down menu
for valores in filtered:
filtered_list.append(valores)
menu_items = [{"text": f"{valores}"} for valores in filtered_list]
self.menu_cliente = MDDropdownMenu(
caller=self.ids.name_client,
items=menu_items,
width_mult=5,
)
self.menu_cliente.open()
self.menu_cliente.bind(on_release=self.set_item_cliente)
这很管用,正是我需要的。但是,下拉菜单会不断打开一个在另一个之上。我希望前一个 MDDropdown 在后一个打开之前关闭。
有什么建议吗?非常感谢!