from PyQt5 import QtCore from PyQt5.QtWidgets import * class CustomEdit(QLineEdit): """ 带下拉框的文本输入框类(文本下拉输入框),输入文字可以搜索内容 """ def __init__(self, parent, size=(50, 50, 100, 20), name='edit', drag=False, text_list=True, search=True, qss_file=''): """ 初始化控件 :param parent: 控件显示的父对象 :param size: 输入框控件尺寸 :param name: 输入框控件名称 :param drag: 拖放标识位 :param text_list: 是否开启下拉框功能标识位 """ super(CustomEdit, self).__init__(None, parent) # 输入框的尺寸 self.w = size[2] self.h = size[3] self.setGeometry(*size) # 输入框名称 self.setObjectName(name) # 输入框是否支持拖放 self.drag_flag = False if drag: self.setAcceptDrops(True) self.setDragEnabled(True) # 开启可拖放事件 else: self.setAcceptDrops(False) self.setDragEnabled(False) # 关闭可拖放事件 self.click_flag = False # 点击状态,为False时显示下拉框 self.text_list = None # 下拉框对象 self.p_text = "" # placehold text,输入框背景上的灰色文字 self.qss_file = qss_file # 下拉框样式文件 self.org_data = [] # 用来进行搜索的数据list # 如果text_list为True,则初始化下拉框 if text_list: # 下拉列表模型为StringListModel self.list_model = QtCore.QStringListModel() # 初始化下拉列表对象为QListView类型 self.text_list = QListView(parent) # 下拉列表名称,以list_开头 self.text_list.setObjectName("list_%s" % name) # 设置下拉列表初始化尺寸 self.text_list.setGeometry(size[0], size[1]+size[3], size[2], size[3]) # 隐藏下拉列表 self.text_list.hide() # 初始化下拉列表数据 self.text_list.data = [] if search: self.textChanged.connect(self.on_search_data) def fill_data(self, text_data_list): """ 初始化文本下拉输入框控件数据 :param text_data_list: 下拉框数据,必须为纯文本list """ # 设置下拉列表数据 self.list_model.setStringList(text_data_list) self.text_list.setModel(self.list_model) self.text_list.data = text_data_list # 填充list数据 if text_data_list: self.text_list.data = text_data_list self.org_data = text_data_list[:] # 深拷贝一份数据,用来搜索 self.text_list.resize(self.w, self.h * 0.6 * len(self.text_list.data)) self.setText(text_data_list[0]) else: self.setText('') self.text_list.hide() edit_clicked = QtCore.pyqtSignal() # 定义clicked信号 def mouseReleaseEvent(self, event): """ 鼠标按键松开时的事件处理 :param event: 鼠标按键松开事件 """ # 左键松开 if event.button() == QtCore.Qt.LeftButton: # 下拉列表存在数据,并且未点击过,则显示下拉框 if self.text_list.data and not self.click_flag: self.text_list.show() # 下拉列表存在,并且点击过,则隐藏下拉框 elif self.click_flag: self.text_list.hide() self.click_flag = not self.click_flag self.edit_clicked.emit() # 发送clicked信号 def on_select_data(self, func): """ 选择下拉框数据时的消息响应函数 """ text = '' idx = self.text_list.currentIndex() if self.text_list.data: text = self.text_list.data[idx.row()] self.text_list.hide() self.setText(text) self.setFocus() self.setCursorPosition(len(text)) # 选择数据后就隐藏了下拉框,设置点击标识位为False,下次点击才会显示下拉框 self.click_flag = False if func: func() def on_search_data(self): """ 文本变化时的消息响应,搜索下拉框列表里的数据 """ # 输入框中文本和List选择文本不一样的时候,才显示下拉框 cur_text = self.text() list_text = '' idx = self.text_list.currentIndex() if self.text_list.data: list_text = self.text_list.data[idx.row()] if cur_text != list_text: # and len(cur_text) > 1: self.text_list.show() # 根据消息响应传入的data来搜索 self.text_list.data = self.org_data[:] for _text in self.org_data: if cur_text not in _text: self.text_list.data.remove(_text) # 刷新下拉框 self.list_model.setStringList(self.text_list.data) self.text_list.setModel(self.list_model) if not self.click_flag: self.text_list.hide() self.click_flag = True if self.text_list.data: # 有数据的时候就调整下拉框大小 self.resize_text_list() else: self.text_list.hide() # 没有数据就隐藏下拉框 class MainWindow(QMainWindow): """主窗口,继承了QMainWindow类""" def __init__(self, name, title): """初始化类的成员变量""" super(MainWindow, self).__init__() self.w = 0 self.h = 0 self.init_ui(name, title) # 初始化UI界面 def init_ui(self, name, title): """初始化UI界面""" self.w = 140 self.h = 100 self.setObjectName(name) # 设置主窗口对象的名称 self.setWindowTitle(title) # 设置主窗口显示的标题 self.resize(self.w, self.h) # 设置主窗口尺寸 self.custom_edit = CustomEdit(self, size=(10, 10, 120, 24), name='custom_edit', search=True) self.custom_edit.setPlaceholderText('我是自定义输入框') data_list = [i * ('%s' % i) for i in range(15)] self.custom_edit.fill_data(data_list) # self.custom_edit = CustomEdit(self, size=(10, 10, 120, 24), # name='custom_edit', search=True) if __name__ == '__main__': import sys app = QApplication(sys.argv) n = 'CustomUI' t = '自定义控件' ex = MainWindow(n, t) ex.show() sys.exit(app.exec_())