Informação preliminar: Não quero usar folhas de estilo.
Eu costumo QPalette
alterar a cor do texto (primeiro plano) da QLabel
seguinte maneira:
QLabel * label = new QLabel("foobar", parent);
QPalette pal = label->palette();
pal.setColor(label->foregroundRole(), Qt::blue);
label->setPalette(pal);
E funciona como esperado.
Agora eu insiro esse rótulo em um QListWidget
:
QListWidget * list_widget = new QListWidget(parent);
QListWidgetItem * item = new QListWidgetItem(list_widget);
list_widget->addItem(item);
list_widget->setItemWidget(item, label);
item->setSizeHint(label->sizeHint());
Problema: a cor do texto é ignorada e o padrão (preto) é usado.
Pergunta: Existe uma maneira de forçar a QListWidget
exibição dos widgets fornecidos com seus respectivos widgets dedicados QPalette
? Se sim, como?
Tentei substituir a chamada para o rótulo backgroundRole()
por QPalette::WindowText
diretamente, mas não mudou nada.
Claro, no meu caso de uso real, tenho um widget personalizado que contém QLabel
s. Não faria sentido usar QListWidget::setItemWidget()
um único widget, QLabel
já que QListWidgetItem
ele já suporta texto colorido (normalmente).
tl;dr
Você precisa definir explicitamente a função de primeiro plano:
Explicação
Apenas alguns widgets definiram explicitamente funções de segundo e primeiro plano (por exemplo, QPushButton define
QPalette::Button
eQPalette::ButtonText
respectivamente), caso contrário, seus valores internosQPalette::NoRole
são .Quando as funções relacionadas
backgroundRole()
eforegroundRole()
são chamadas, elas retornarão o conjunto de funções interno (eventualmente definido explicitamente por meio das funções setter), a menos que sejaNoRole
; se for, elas retornarão uma função adequada (mas nãoNoRole
).Dos
backgroundRole()
documentos:O acima significa que, se o widget tiver uma
NoRole
função em segundo plano, ele percorrerá a árvore pai até que qualquer pai retorne uma função que não sejaNoRole
, ou até que alcance a janela de nível superior e, eventualmente, retorneQPalette::Window
. Aqui está o código-fonte dessa função:Dos
foregroundRole()
documentos:Isso significa que, se um
NoRole
foreground for definido, ele chamarábackgroundRole()
(fazendo tudo o que foi explicado acima) e retornará uma função adequada que contrasta com ele. Veja como funciona:Como o QLabel está entre os widgets que não têm funções padrão definidas, o seguinte acontece quando usado de forma independente:
NoRole
primeiro plano interno, ele chamabackgroundRole()
;NoRole
plano de fundo, ele procura na árvore de widgets até encontrar um pai com uma função válida adequada;QPalette::Window
;QPalette::WindowText
, e como oswitch()
acima não encontra nenhuma outra correspondência, ele retorna isso;Essa função assumida não é apenas a mesma que você obtém ao fazer
pal->setColor(label->foregroundRole(), Qt::blue);
, mas também, e mais importante, a usada pelo QPainter quando desenha o rótulo.Quando você adiciona o rótulo à visualização, as coisas mudam:
QPalette::Base
, e a janela de visualização é o pai de todos os widgets definidos para itens (incluindo editores delegados);backgroundRole()
do rótulo retornará, portanto, obackgroundRole()
da viewport, que foi definido comoQPalette::Base
;foregroundRole()
retornará então a função correspondente para esse plano de fundo, que éQPalette::Text
;Para substituir isso, a solução parece pouco intuitiva, além de inútil, mas faz sentido considerando o que foi explicado acima: você precisa definir explicitamente a função da paleta para o primeiro plano, com base na função "assumida":
Você pode fazer o acima antes ou depois de definir o rótulo para a visualização, mas é obrigatório que você faça isso depois
pal.setColor()
elabel->setPalette(pal)
depois de fazersetForegroundRole()
, porquebackgroundRole()
(e, portanto,foregroundRole()
) terá um resultado diferente dependendo do pai.