class LineEdit(QLineEdit): """ 包含清空按钮的单行输入框 """ def __init__(self, string=None, parent=None, isNeedClearBt: bool = True): super().__init__(string, parent) self.isNeedClearBt = isNeedClearBt # 设置提示条和鼠标点击次数 self.customToolTip = None self.clickedTime = 0 iconPath_dict = { 'normal': r'resource\images\lineEdit\clearInfo_cross_normal.png', 'hover': r'resource\images\lineEdit\clearInfo_cross_hover.png', 'pressed': r'resource\images\lineEdit\clearInfo_cross_pressed.png' } # 实例化一个用于清空内容的按钮 self.clearButton = ThreeStateButton(iconPath_dict, self) # 实例化右击菜单 self.menu = LineEditMenu(self) # 实例化布局 self.h_layout = QHBoxLayout() self.initWidget() def initWidget(self): """ 初始化小部件 """ self.resize(500, 40) self.clearButton.hide() self.textChanged.connect(self.textChangedEvent) self.clearButton.move(self.width() - self.clearButton.width(), 0) if self.isNeedClearBt: self.setTextMargins(0, 0, self.clearButton.width(), 0) # 安装事件过滤器 self.clearButton.installEventFilter(self) def mousePressEvent(self, e): if e.button() == Qt.LeftButton: # 如果已经全选了再次点击就取消全选 if self.clickedTime == 0: self.selectAll() else: # 需要调用父类的鼠标点击事件,不然无法部分选中 super().mousePressEvent(e) self.setFocus() # 如果输入框中有文本,就设置为只读并显示清空按钮 if self.text() and self.isNeedClearBt: self.clearButton.show() self.clickedTime += 1 def contextMenuEvent(self, e: QContextMenuEvent): """ 设置右击菜单 """ self.menu.exec_(e.globalPos()) def focusOutEvent(self, e): """ 当焦点移到别的输入框时隐藏按钮 """ # 调用父类的函数,消除焦点 super().focusOutEvent(e) self.clickedTime = 0 self.clearButton.hide() def enterEvent(self, e): """ 鼠标进入时显示提示条 """ if self.customToolTip: self.customToolTip.setText(self.customToolTipText) self.customToolTip.move( e.globalX() - int(self.customToolTip.width() / 2), e.globalY() - 140 - self.customToolTip.isWordWrap * 30) self.customToolTip.show() def leaveEvent(self, e): """ 判断鼠标是否离开标签 """ if self.parent() and self.customToolTip: notLeave = isNotLeave(self) if notLeave: return self.customToolTip.hide() def setCustomToolTip(self, toolTip, text: str): """ 设置提示条和提示条内容 """ self.customToolTip = toolTip self.customToolTipText = text def textChangedEvent(self): """ 如果输入框中文本改变且此时清空按钮不可见,就显示清空按钮 """ if self.text( ) and not self.clearButton.isVisible() and self.isNeedClearBt: self.clearButton.show() def resizeEvent(self, e): """ 改变大小时需要移动按钮的位置 """ self.clearButton.move(self.width() - self.clearButton.width(), 0) def eventFilter(self, obj, e): """ 清空按钮按下时清空内容并隐藏按钮 """ if obj == self.clearButton: if e.type() == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton: self.clear() self.clearButton.hide() return True return super().eventFilter(obj, e)
class SearchLineEdit(QLineEdit): """ 单行搜索框 """ def __init__(self, parent=None): super().__init__(parent) # 按钮图标位置 clear_iconPath_dict = { 'normal': r'resource\images\searchLineEdit\搜索框清空按钮_normal_45_45.png', 'hover': r'resource\images\searchLineEdit\搜索框清空按钮_hover_45_45.png', 'pressed': r'resource\images\searchLineEdit\搜索框清空按钮_pressed_45_45.png' } self.__search_iconPath_dict = { 'normal': r'resource\images\searchLineEdit\搜索框透明搜索按钮_normal_46_45.png', 'hover': r'resource\images\searchLineEdit\搜索框透明搜索按钮_hover_46_45.png', 'pressed': r'resource\images\searchLineEdit\搜索框搜索按钮_pressed_46_45.png' } # 实例化按钮 self.clearButton = ThreeStateButton(clear_iconPath_dict, self, (46, 45)) self.searchButton = ThreeStateButton(self.__search_iconPath_dict, self, (46, 45)) # 实例化右击菜单 self.menu = LineEditMenu(self) # 初始化界面 self.__initWidget() def __initWidget(self): """ 初始化小部件 """ self.resize(370, 45) self.clearButton.hide() self.setAttribute(Qt.WA_StyledBackground) # 设置提示文字 self.setPlaceholderText('搜索') self.textChanged.connect(self.textChangedEvent) self.setWindowFlags(Qt.FramelessWindowHint) # 设置外边距 self.setTextMargins(0, 0, self.clearButton.width() + self.searchButton.width(), 0) # 调整按钮位置 self.__adjustButtonPos() # 安装监听 self.clearButton.installEventFilter(self) self.searchButton.installEventFilter(self) def textChangedEvent(self): """ 编辑框的文本改变时选择是否显示清空按钮 """ if self.text(): self.clearButton.show() else: self.clearButton.hide() def __adjustButtonPos(self): """ 调整按钮的位置 """ # 需要补上margin的位置 self.searchButton.move(self.width() - self.searchButton.width() - 8, 0) self.clearButton.move(self.searchButton.x() - self.clearButton.width(), 0) def resizeEvent(self, e): """ 调整大小的同时改变按钮位置 """ self.__adjustButtonPos() def mousePressEvent(self, e): if e.button() != Qt.LeftButton: return # 需要调用父类的鼠标点击事件,不然无法部分选中 super().mousePressEvent(e) # 如果输入框中有文本,就设置为只读并显示清空按钮 if self.text(): self.clearButton.show() def focusOutEvent(self, e): """ 当焦点移到别的输入框时隐藏按钮 """ # 调用父类的函数,消除焦点 super().focusOutEvent(e) self.clearButton.hide() def eventFilter(self, obj, e): """ 过滤事件 """ if obj == self.clearButton: if e.type() == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton: self.clear() self.clearButton.hide() return True elif obj == self.searchButton: if e.type() == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton: self.searchButton.setIcon( QIcon(self.__search_iconPath_dict['hover'])) return True return super().eventFilter(obj, e) def contextMenuEvent(self, e): """ 设置右击菜单 """ self.menu.exec_(e.globalPos())
class LineEdit(QLineEdit): """ 编辑框 """ def __init__(self, text='', parent=None): super().__init__(text, parent) iconPath_dict = { 'normal': r'resource\images\createPlaylistPanel\清空按钮_normal_50_50.png', 'hover': r'resource\images\createPlaylistPanel\清空按钮_hover_50_50.png', 'pressed': r'resource\images\createPlaylistPanel\清空按钮_pressed_50_50.png' } # 创建小部件 self.clearButton = ThreeStateButton(iconPath_dict, self, (50, 50)) self.pencilPic = QLabel(self) self.menu = LineEditMenu(self) # 初始化 self.initWidget() self.setQss() def initWidget(self): """ 初始化小部件 """ self.setFixedSize(484, 70) self.adjustButtonPos() self.textChanged.connect(self.textChangedEvent) self.setObjectName('createPlaylistPanelLineEdit') # 初始化按钮 self.clearButton.hide() self.clearButton.installEventFilter(self) self.pencilPic.setPixmap( QPixmap(r'resource\images\createPlaylistPanel\pencil_50_50.png')) # 设置文字的外间距,防止文字和文本重叠 self.setTextMargins( 0, 0, self.clearButton.width() + self.pencilPic.pixmap().width() + 1, 0) def textChangedEvent(self): """ 编辑框的文本改变时选择是否显示清空按钮 """ if self.text(): self.clearButton.show() else: self.clearButton.hide() def enterEvent(self, e): """ 鼠标进入更新样式 """ if self.property('noText') == 'true': self.pencilPic.setPixmap( QPixmap( r'resource\images\createPlaylistPanel\pencil_noFocus_hover_50_50.png' )) def leaveEvent(self, e): """ 鼠标离开更新样式 """ if self.property('noText') == 'true': self.pencilPic.setPixmap( QPixmap( r'resource\images\createPlaylistPanel\pencil_noFocus_50_50.png' )) def focusOutEvent(self, e): """ 当焦点移到别的输入框时隐藏按钮 """ super().focusOutEvent(e) if not self.text(): self.setProperty('noText', 'true') self.setStyle(QApplication.style()) self.setText(' 命名此播放列表') self.clearButton.hide() self.pencilPic.setPixmap( QPixmap( r'resource\images\createPlaylistPanel\pencil_noFocus_50_50.png' )) def focusInEvent(self, e): """ 焦点进入时更换样式并取消提示文字 """ super().focusInEvent(e) # 必须有判断的一步,不然每次右击菜单执行完都会触发focusInEvent()导致菜单功能混乱 if self.property('noText') == 'true': self.clear() self.setProperty('noText', 'false') self.setStyle(QApplication.style()) self.pencilPic.setPixmap( QPixmap(r'resource\images\createPlaylistPanel\pencil_50_50.png')) def mousePressEvent(self, e): """ 鼠标点击事件 """ if e.button() == Qt.LeftButton: # 需要调用父类的鼠标点击事件,不然无法部分选中 super().mousePressEvent(e) # 如果输入框中有文本,就设置为只读并显示清空按钮 if self.text(): self.clearButton.show() def contextMenuEvent(self, e): """ 设置右击菜单 """ self.menu.exec_(e.globalPos()) def resizeEvent(self, e): """ 调整大小的同时改变按钮位置 """ self.adjustButtonPos() def eventFilter(self, obj, e): """ 过滤事件 """ if obj == self.clearButton: if e.type() == QEvent.MouseButtonRelease and e.button( ) == Qt.LeftButton: self.clear() self.clearButton.hide() return True return super().eventFilter(obj, e) def adjustButtonPos(self): """ 调整按钮的位置 """ self.clearButton.move(self.width() - 101, 10) self.pencilPic.move(self.width() - 51, 10) def setQss(self): """ 设置层叠样式 """ with open('resource\\css\\lineEdit.qss', encoding='utf-8') as f: self.setStyleSheet(f.read())