【问题标题】:How to change style of an unselected element?如何更改未选中元素的样式?
【发布时间】:2020-02-24 08:33:58
【问题描述】:

我正在尝试使用 PyQt5 构建文件夹查看器,但遇到了问题。 为了标记选定的文件或目录,我创建了一个 eventFilter,它设置了 QLabel 元素的“选定”属性并对其应用了一些样式。 问题是,当我将 'selected' 设置为 True - 文件/文件夹被选中(应用到它的样式),但是当我尝试将 'selected' 设置为 None of previous selected element 时,它正在工作(属性更改),但是样式不会应用于它(它不是取消选择,不会返回到未选择状态)。 这是我的代码片段:

import sys
import os

from PyQt5.QtWidgets import (QApplication, QShortcut, QLabel, QPushButton,
                         QGridLayout, QWidget, QMainWindow, QLineEdit,
                         QVBoxLayout, QShortcut, QAction, QMessageBox,
                         QHBoxLayout, QComboBox, QCheckBox, QScrollArea)
from PyQt5.QtGui import QIntValidator, QIcon
from PyQt5.QtCore import Qt, QObject, QEvent, QSize


class MyWindow(QMainWindow):

    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.setGeometry(600, 300, 700, 500)
        self.setWindowTitle('Folder imitator')
        self.homeDirectory = os.path.splitdrive(os.getcwd())[0]+os.path.sep
        self.currentDirectory = self.homeDirectory
        self.setStyleSheet(open('style.css').read())
        self.selected = None
        self.initUI()

    def initUI(self):
        cenWidget = QWidget(self)
        mainVertLayout = QVBoxLayout(cenWidget)

        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        viewWidg = QWidget()
        viewVertLayout = QVBoxLayout(viewWidg)
        viewVertLayout.installEventFilter(self)
        viewVertLayout.setAlignment(Qt.AlignTop)
        viewVertLayout.setSpacing(0)
        viewVertLayout.setContentsMargins(3, 3, 3, 3)

        self.files = [QLabel(filename) for filename in self.getDirList()]
        for f in self.files:
            f.installEventFilter(self)
            viewVertLayout.addWidget(f)

        scroll.setWidget(viewWidg)

        mainVertLayout.addWidget(scroll)
        mainVertLayout.setContentsMargins(0, 0, 0, 0)
        mainVertLayout.setSpacing(0)
        mainVertLayout.setAlignment(Qt.AlignLeft)

        self.setCentralWidget(cenWidget)

    def getDirList(self):
        return sorted(os.listdir(self.currentDirectory), 
            key=lambda x : 1 if os.path.isdir(os.path.join(
            self.currentDirectory, x)) and not x.endswith('.BIN') else 2)

    def eventFilter(self, obj, event):
        if event.type() == QEvent.MouseButtonPress:
            # I am interested in this part
            if event.button() == Qt.LeftButton:
                if self.selected and self.files[self.selected] != obj:
                    self.files[self.selected].setProperty('selected', None)
                if obj.property('selected') == None:
                    obj.setProperty('selected', True)
                    self.selected = self.files.index(obj)
                else:
                    obj.setProperty('selected', None)
                    self.selected = None
                obj.setStyleSheet('')

        return QObject.event(obj, event)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    app.exec_()

这里是 style.css 文件:

QLabel {
    color: black;
    font-size: 12px;
    background-color: none;
}

QLabel[selected=true] {
    color: #fff;
    background-color: blue;
}

未再次单击它所选择的同一文件,似乎正在运行正常,但其他文件不是未选择的自动性,何时选择另一个文件,为什么这是如何解决这个问题? 提前谢谢你。

【问题讨论】:

    标签: python pyqt pyqt5 qtstylesheets


    【解决方案1】:

    你必须调用小部件QStyle的unpolish()polish()方法:

        def eventFilter(self, obj, event):
            if event.type() == QEvent.MouseButtonPress and obj in self.files:
                if event.button() == Qt.LeftButton:
                    if self.selected is None:
                        obj.setProperty("selected", True)
                        self.update_style(obj)
                        self.selected = obj
                    elif self.selected is obj:
                        last_state = obj.property("selected")
                        obj.setProperty("selected", None if last_state else True)
                        self.update_style(obj)
                        self.selected = None
                    else:
                        self.selected.setProperty("selected", None)
                        obj.setProperty("selected", True)
                        self.update_style(obj)
                        self.update_style(self.selected)
                        self.selected = obj
            return super(MyWindow, self).eventFilter(obj, event)
    
        @staticmethod
        def update_style(obj):
            obj.style().unpolish(obj)
            obj.style().polish(obj)
    

    【讨论】:

    • 我现在试了一下,它似乎不起作用,之前选择的文件/目录仍然处于选中状态,并且通过第二次单击取消选择就像以前一样工作。
    • @Zarkos 嗯我不明白你。当单击没有蓝色的 QLabel 时,它会变为蓝色,如果按下蓝色 QLabel,则会移除蓝色。这不是你想要的吗?
    • 是的,在我上面的代码中,那部分工作正常,问题是当我尝试选择另一个元素时,应该自动取消选择先前选择的元素,并且确实如此(属性'selected'是设置为无)但风格没有改变,这是我的问题
    • @Zarkos 你想一次只选择一个 QLabel 吗?
    • 是的,这正是我想要的,如果我无法正确传达这一点,请见谅
    猜你喜欢
    • 1970-01-01
    • 2016-02-09
    • 2015-07-05
    • 2016-03-11
    • 1970-01-01
    • 1970-01-01
    • 2017-04-06
    • 2021-03-15
    相关资源
    最近更新 更多