Невозможно изменить цвет выделенного текста пользовательских строк QListView

По какой-то странной причине не удается переопределить цвет выделенного текста в QListView. Он работал нормально (цвет выделенного текста автоматически меняется на белый), пока я не определил свой собственный виджет для представления строки.

Теперь я могу изменить цвет фона и некоторые другие визуальные аспекты выбранной строки, но цвет текста всегда остается черным по умолчанию.

Уже перепробовал все что можно с QSS, QPalette и data()/Qt.ForegroundRole - не помогает никакая хитрость.

Вот упрощенный код, который все еще страдает от проблемы на OS X. К сожалению, у меня не было возможности протестировать на Windows или GNU/Linux.

from PySide.QtCore import *
from PySide.QtGui import *
import sys

view = None
mapp = {}

style = '''
QListView {
    show-decoration-selected: 1;
    selection-color: white;
    selection-background-color: #0068d9;
}

QListView::item:selected:active:hover{
    background-color:red; color: white;
}
QListView::item:selected:active:!hover{
    background-color: #0068d9; color: white;
}
QListView::item:selected:!active{
    background-color:yellow; color: white;
}
QListView::item:!selected:hover{
    background-color:green; color: white;
}
'''

class SimpleListModel(QAbstractListModel):

    def __init__(self, mlist):
        QAbstractListModel.__init__(self)
        self._items = mlist

    def rowCount(self, parent = QModelIndex()):
        return len(self._items)

    def index(self, row, column, parent=QModelIndex()):
        node = self._items[row]

        if not(str(row) in mapp):
            index = self.createIndex(row, column)
            widget = QLabel(node)
            view.setIndexWidget(index, widget)
            mapp[str(row)] = index
            return index

        return mapp[str(row)]

    def data(self, index, role = Qt.DisplayRole):
        return None

    def flags(self, index):
        return Qt.ItemIsSelectable | Qt.ItemIsEnabled    

class MyMainWindow(QWidget):
    def __init__(self):
        global view
        QWidget.__init__(self, None)

        self._model = SimpleListModel(["test", "tes1t", "t3est", "t5est", "t3est"])

        vbox = QVBoxLayout()
        view = QListView()
        view.setModel(self._model)
        vbox.addWidget(view)
        self.setLayout(vbox)

        view.setStyleSheet(style)

        first = self._model.index(0, 0)
        view.setCurrentIndex(first)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyMainWindow()
    w.show()
    w.raise_()
    app.exec_()
    sys.exit()

person zfr    schedule 06.04.2015    source источник
comment
Просто дайте мне знать, если я правильно понял. Вы хотите изменить цвет текста выбранной строки, а остальные оставить прежними? Если это то, что вы хотите, пожалуйста, проверьте мой ответ ниже. Не лучшее решение, но сейчас я очень тороплюсь. Если нужно, я могу немного почистить его в ближайшие дни... Пасха все-таки :)   -  person Iuliu    schedule 10.04.2015
comment
Да, ваше решение именно то, что мне нужно. Что ж, я ожидал увидеть упущенный из виду убойный CSS-селектор документации, который решает проблему самым элегантным способом. Но очевидно, что чисто CSS-решения не существует, и ваш подход в этом случае весьма хорош. Спасибо! Награда твоя.   -  person zfr    schedule 13.04.2015


Ответы (2)


Не самое чистое или лучшее решение, но это то, с чем я пришел после некоторой настройки.

Результат:

введите здесь описание изображения

Синий элемент выбран. Зеленый элемент — это зависший.

Код:

from PySide.QtCore import *
from PySide.QtGui import *
import sys

view = None
mapp = {}

style = '''
QListView {
    show-decoration-selected: 1;
    selection-color: white;
    selection-background-color: #0068d9;
}

QListView::item:selected:active:hover{
    background-color:red; color: white;
}
QListView::item:selected:active:!hover{
    background-color: #0068d9; color: white;
}
QListView::item:selected:!active{
    background-color:yellow; color: white;
}
QListView::item:!selected:hover{
    background-color:green; color: white;
}
'''

class SimpleListModel(QAbstractListModel):

    def __init__(self, mlist):
        QAbstractListModel.__init__(self)
        self._items = mlist

    def rowCount(self, parent = QModelIndex()):
        return len(self._items)

    def index(self, row, column, parent=QModelIndex()):
        node = self._items[row]

        if not(str(row) in mapp):
            index = self.createIndex(row, column)
            widget = QLabel(node)
            view.setIndexWidget(index, widget)

            mapp[str(row)] = index
            return index


        return mapp[str(row)]

    def data(self, index, role = Qt.DisplayRole):
        # The following code shouldn't be put in this function but i'm in a hurry right now...
        selectedIndexes = view.selectedIndexes()

        # Set all items to black
        for i in range(0, self.rowCount()):
            currentRowIndex = self.index(i, 0, QModelIndex())
            myWidget = view.indexWidget(currentRowIndex)
            myWidget.setStyleSheet("color: black")

        # Set selected items to white
        for i in selectedIndexes:
            myWidget = view.indexWidget(i)
            myWidget.setStyleSheet("color: white")

        return None

    def flags(self, index):
        return Qt.ItemIsSelectable | Qt.ItemIsEnabled    

class MyMainWindow(QWidget):
    def __init__(self):
        global view
        QWidget.__init__(self, None)

        self._model = SimpleListModel(["test", "tes1t", "t3est", "t5est", "t3est"])

        vbox = QVBoxLayout()
        view = QListView()
        view.setModel(self._model)
        vbox.addWidget(view)
        self.setLayout(vbox)

        view.setStyleSheet(style)

        first = self._model.index(0, 0)
        view.setCurrentIndex(first)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MyMainWindow()
    w.show()
    w.raise_()
    app.exec_()
    sys.exit()

Пожалуйста, дайте мне знать, если я что-то не понял или код недостаточно ясен.

person Iuliu    schedule 10.04.2015

Во-первых: ваш код точно так же работает в GNU/Linux (Ubuntu 14.04 LTS, PyQt5).

Поскольку текст записывается в indexWidget, таблица стилей для text-color должна быть установлена ​​для QLabel.

Поскольку QLabel не поддерживает псевдосостояние наведения, это нельзя сделать так же, как для элементов.

Чтобы установить таблицу стилей для выбранных indexWidgets, я использовал механизм signal-slot, для наведенных indexWidgets я использовал фильтр событий,

введите здесь описание изображения

изменен только класс MyMainWindow:

class MyMainWindow(QWidget):
    def __init__(self):
        global view
        QWidget.__init__(self, None)

        self._model = SimpleListModel(["test", "tes1t", "t3est", "t5est", "t3est"])

        vbox = QVBoxLayout()
        view = QListView()
        view.setModel(self._model)
        view.setMouseTracking(True)         # to catch mouseEvents
        view.installEventFilter(self)           # for events in ListView 
        vbox.addWidget(view)
        self.setLayout(vbox)

        view.setStyleSheet(style)

        first = self._model.index(0, 0)
        view.setCurrentIndex(first)
        view.clicked.connect(self.setIndexStyle)    # or any other signal

    def setIndexStyle(self, index):
        for i in range(0,view.model().rowCount()):
            style = 'color: black;'
            view.indexWidget(view.model().index(i,0)).setStyleSheet(style)
        for i in view.selectedIndexes():    # works for multiseletion too
            style = 'color: white;'
            view.indexWidget(i).setStyleSheet(style)

    def eventFilter(self,obj,event):
        if event.type() == QEvent.HoverMove and isinstance(obj,QListView):
            i =  view.indexAt(event.pos())      # index at mouse.pos()
            self.setIndexStyle(i)       # selected indexWidgets still have white text
            style = 'color: white;'
            try:                # if no item on mouse.pos()
                view.indexWidget(i).setStyleSheet(style)
            except AttributeError:      
                pass
            return False
        return QWidget.eventFilter(self,obj,event)
person a_manthey_67    schedule 11.04.2015
comment
Спасибо за ваш вклад! luliu первым предложил приемлемое решение, поэтому награда досталась ему. Я очень ценю вашу помощь! - person zfr; 13.04.2015