工具需要一個根據用戶輸入的tag來搜索的功能,借鑑了下別的軟件的模式,於是誕生下面我的這個,獻上動圖了。
具體的實現方式如下:
# -*- coding: utf-8 -*-
from PySide import QtGui, QtCore
import sys
from functools import partial
class TagBar(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
# self.setWindowTitle('Tag Bar')
self.tags = []
self.h_layout = QtGui.QHBoxLayout()
self.h_layout.setSpacing(4)
self.setLayout(self.h_layout)
self.line_edit = QtGui.QLineEdit(self)
self.line_edit.installEventFilter(self)
self.line_edit.setMinimumHeight(30)
self.line_edit.setStyleSheet('border:0px solid rgb(192, 192, 192); border-radius: 12px;')
# self.line_edit.setStyleSheet('border:0px')
self.line_edit.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Maximum)
self.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)
self.setContentsMargins(2, 2, 2, 2)
self.h_layout.setContentsMargins(2, 2, 2, 2)
self.refresh()
self.setup_ui()
# self.show()
def setup_ui(self):
self.line_edit.returnPressed.connect(self.create_tags)
def create_tags(self):
new_tags = self.line_edit.text().split(', ')
self.line_edit.setText('')
for _tag in new_tags:
if _tag and _tag not in self.tags:
self.tags.append(_tag)
# self.tags.sort(key=lambda x: x.lower())
self.refresh()
def check_element(self, item):
if item in self.tags:
return False
else:
return True
def refresh(self):
for i in reversed(range(self.h_layout.count())):
self.h_layout.itemAt(i).widget().setParent(None)
for tag in self.tags:
self.add_tag_to_bar(tag)
self.h_layout.addWidget(self.line_edit)
self.line_edit.setFocus()
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
painter.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255), 30, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap))
painter.drawLine(15, self.height() / 2, self.width() - 15, self.height() / 2)
painter.end()
def add_tag_to_bar(self, text):
tag = QtGui.QFrame()
tag.setStyleSheet('border:1px solid rgb(192, 192, 192); border-radius: 12px;')
tag.setContentsMargins(2, 2, 2, 2)
tag.setFixedHeight(24)
hbox = QtGui.QHBoxLayout()
hbox.setContentsMargins(4, 4, 4, 2)
hbox.setSpacing(0)
tag.setLayout(hbox)
label = QtGui.QLabel(text)
label.setAlignment(QtCore.Qt.AlignRight)
label.setStyleSheet('border:0px')
label.setFixedHeight(16)
hbox.addWidget(label)
x_button = QtGui.QPushButton()
x_button.setIcon(QtGui.QIcon('C:/Users/Administrator/Downloads/delete.png'))
# x_button.setFixedSize(15, 15)
x_button.setStyleSheet('border:0px; font-weight:bold')
x_button.setSizePolicy(QtGui.QSizePolicy.Maximum, QtGui.QSizePolicy.Maximum)
x_button.clicked.connect(partial(self.delete_tag, text))
hbox.addWidget(x_button)
tag.setSizePolicy(QtGui.QSizePolicy.Maximum, QtGui.QSizePolicy.Preferred)
self.h_layout.addWidget(tag)
def delete_tag(self, tag_name):
self.tags.remove(tag_name)
self.refresh()
def eventFilter(self, widget, event):
if type(event) == QtGui.QWidgetItem:
return False
if event.type() == QtCore.QEvent.KeyPress and widget is self.line_edit:
key = event.key()
text = ''
if key == QtCore.Qt.Key_Backspace:
if len(self.line_edit.text()) >= 1:
count = len(self.line_edit.text())
text = self.line_edit.text()[:count - 1]
self.line_edit.setText(text)
else:
if len(self.tags) > 0:
self.tags.remove(self.tags[-1])
self.refresh()
return True
return QtGui.QWidget.eventFilter(self, widget, event)
class TagBarWin(QtGui.QDialog):
def __init__(self):
super(TagBarWin, self).__init__(parent=None)
hbox = QtGui.QHBoxLayout()
tag_bar = TagBar()
hbox.addWidget(tag_bar)
self.setLayout(hbox)
self.setWindowTitle('Tag Bar')
self.setMinimumWidth(420)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
tag_win = TagBarWin()
tag_win.show()
sys.exit(app.exec_())
這裏面最核心的是用到eventFilter這個函數來捕捉backspace這個鍵,而普通的keyPressEvent是辦不到的,但是要用這個event,就必須給對應的widget使用self.line_edit.installEventFilter(self) 這個方法,方能正確地將這個event設置給指定的widget,然後剩下里面刪除的細節操作了,給用戶感覺像是用backspace刪除了tag,實際上只是看起來是。