一個非常好看的標籤(Tag)搜索框

工具需要一個根據用戶輸入的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,實際上只是看起來是。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章