设置样式表后 Qt Customwidget 外观没有改变

Posted

技术标签:

【中文标题】设置样式表后 Qt Customwidget 外观没有改变【英文标题】:Qt Customwidget appearance not changing after setting stylesheet 【发布时间】:2020-01-05 09:43:32 【问题描述】:

我想提供一个系统来为我的应用程序编写自己的样式表。我像这样加载样式表: 我使用 QFileInfo 来检查文件是否存在(如本文How to check whether file exists in Qt in c++)

bool Settings::fileExists(const QString &path)

    QFileInfo check_file(path);
    if (check_file.exists() && check_file.isFile()) 
        return true;
     else 
        return false;
    

然后我打开文件

QString filePath = stylesPath + "/"  + text;
    if(fileExists(filePath)) 
        QFile stylesheetFile(filePath);
        stylesheetFile.open(QFile::ReadOnly | QFile::Text);
        QString newStylesheet = QLatin1String(stylesheetFile.readAll());
        stylesheetFile.close();
        if(m_previewFrame) 
            m_previewFrame->setStyleSheet(newStylesheet);
            m_previewFrame->style()->unpolish(m_previewFrame);
            m_previewFrame->style()->polish(m_previewFrame);
            m_previewFrame->update();
        
    
    qDebug()  << m_previewFrame->styleSheet();

Edit3:m_previewframe 是一个 Qframe 对象,我想更改作为 m_previewFrame 子级的 customWidget 的样式。我是否必须为每个孩子抛光/取消抛光,而不是只为 QFrame?

样式表用于自定义小部件,因此已覆盖本文中的paintEvent Qt Stylesheet for custom widget 编辑:使用 QFile::Text (Unable to set stylesheet properties using qss file) 很重要

如果我运行它,它会像这样打印出文件的内容

"CustomWidget\n\tbackground-color:black;\n"

但它只重新加载样式一次。 如果我尝试像这样直接传递 QString:

auto newStyleSheet = QString("CustomWidgetbackground-color:black;");
m_previewFrame->setStyleSheet(newStylesheet);
m_previewFrame->style()->unpolish(m_previewFrame);
m_previewFrame->style()->polish(m_previewFrame);
m_previewFrame->update();

它有效。 编辑:第一个例子也有效。但它只工作一次。如果我设置了一个样式表,它就不会更新另一个样式表。 Edit2:这绝对是一个更新问题,polish/unpolish + update() 和 ensurePolished() + update() 都不起作用。 我不确定如何强制我的 QFrame 及其子项重新渲染。 Qt 未抛光:

请注意,unpolish() 只有在小部件被销毁时才会被调用。这在某些情况下可能会导致问题,例如,如果您从 UI 中删除一个小部件,缓存它,然后在样式更改后重新插入它; Qt 的一些类缓存它们的小部件。

这意味着我必须销毁对象?

我正在使用 C++17、Qt Creator 4.9.2 和 Desktop Qt 5.13.0 MinGW 64 Bit

【问题讨论】:

“qDebug() styleSheet();”的输出是什么当您像在第二个工作示例中那样设置样式时?您加载文件的方式似乎是正确的,我做的基本相同,它对我有用。这在我看来 \r\n\ 可能是问题所在。 输出类似于字符串。如果我使用 QString::simplified 我得到完全相同的字符串并摆脱 \r\n 但不知何故它不起作用。我还注意到,如果我在更改 CustomWidget 的 MainWindow 中没有加载样式表,则第二个示例才有效。 【参考方案1】:

我不确定这是否有帮助,但不需要为自定义小部件覆盖 QEvent::Paint 以便能够将样式表应用于它们。它甚至可能会给您带来问题,因为仅请求绘制 QStyle::PE_Widget 元素,而 Qt 可以为您绘制更多其他元素。此外, QWidget::setStyleSheet() 应该为您自动取消抛光和抛光所有内容,因此不需要重新抛光。换句话说,您只需要以下几行:

auto newStyleSheet = QString("CustomWidgetbackground-color:black;");
m_previewFrame->setStyleSheet(newStylesheet);

我不确定它是否会起作用,但是正如我所尝试的(通过 QTextEdit 设置它),它可以正常工作,就像您设置样式表一样多次。无论如何,问题应该出在其他地方。顺便说一句,我使用的是 C++11、Qt Creator 4.8.2 和 Qt5.9.8。也许较新的 Qt 版本有这种类型的错误?我非常怀疑 C++17 或 Qt Creator 4.9.2 会导致任何问题。

【讨论】:

我解决了我的问题,方法是为 previewFrame 的每个子项(递归)调用波兰/取消抛光 + 更新,并为每个 CustomWidget 覆盖paintEvent(如果它不是小部件,则调用父母的paintEvent)。但这会导致 setStylesheet 出现问题。有时它有效,有时它给出警告无法解析对象 QFrame(0x18e6130, name="previewframe") 的样式表并且样式表没有改变。我试图不覆盖paintEvent和/或不使用波兰/取消抛光,但它不起作用。

以上是关于设置样式表后 Qt Customwidget 外观没有改变的主要内容,如果未能解决你的问题,请参考以下文章

对 Javascript 的 div 调用在样式表后停止工作

通过Qt样式表定制程序外观(比较通俗易懂)

QT之设计部件背景色

QT样式表

自定义QT窗口部件外观之QStyle

[Qt Creator 快速入门] 第8章 界面外观