首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用CSS (QSS)选择器获取QWidget*

使用CSS (QSS)选择器获取QWidget*
EN

Stack Overflow用户
提问于 2016-02-01 11:14:16
回答 1查看 1.7K关注 0票数 3

Qt允许您使用样式表对GUI进行样式化。它们使用与常规CSS类似的选择器语法。我希望在代码中使用这些选择器来访问特定的小部件,类似于jQuery的工作方式。例如:

代码语言:javascript
运行
复制
SomeQtCSSMagic::resolveSelector("QPushButton#okButton");

这个是可能的吗?如果没有,是否至少有代码可以从Qt库复制粘贴并进行编辑以满足我的需要?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-01 14:20:23

目前,Qt没有提供官方支持。但是使用普通的C++代码并不难。

您的选择器翻译为:

代码语言:javascript
运行
复制
for (auto top : qApp->topLevelWidgets()) {
  auto widgets = top->findChildren<QWidget*>("okButton");
  widgets << top;
  for (auto widget : widgets)
    if (widget->inherits("QPushButton"))
      qDebug() << "found" << widget;
}

如果您发现这样的代码很乏味,您可以利用私有的Qt代码。CSS解析器接口在p.h中。除了解析器之外,您还需要一些代码来使用解析的选择器来查找小部件。也就是说,必须为指向一个QCss::StyleSelector的节点实现一个QObject。这是由QStyleSheetStyleSelectorsrc/widget/styles/q样式表styles.src中完成的,但是这是一个没有导出的本地类,所以您确实有一些copypasta来处理这个问题。

一旦您实现了一个QCss::StyleSelector,在这里作为QObjectStyleSelector,获得选择器应用到的小部件是很容易的。您必须迭代所有小部件,并查看CSS机器是否对给定节点有任何规则,假设由选择器和空体{}组成的虚拟样式表。这种方法支持样式表支持的所有选择器,但对小部件样式的选择除外:

代码语言:javascript
运行
复制
QWidgetList select(const QString & selector) {
   static QHash<QString, StyleSheet> cache;
   QWidgetList result;
   QObjectStyleSelector oSel;
   auto it = cache.find(selector);
   if (it == cache.end()) {
      StyleSheet styleSheet;
      Parser parser(selector + "{}");
      if (!parser.parse(&styleSheet))
         return result;
      it = cache.insert(selector, styleSheet);
   }
   oSel.styleSheets.append(*it);

   for (auto top : qApp->topLevelWidgets()) {
      auto widgets = top->findChildren<QWidget*>();
      widgets << top;
      for (auto widget : widgets) {
         StyleSelector::NodePtr n { widget };
         auto rules = oSel.styleRulesForNode(n);
         if (!rules.isEmpty()) result << widget;
      }
   }
   return result;
}

上面的代码不会被小部件上可能存在的任何样式表“分心”--它会考虑到它们的副作用(例如,属性更改),但否则会忽略它们。

您可以按以下方式对其进行测试:

代码语言:javascript
运行
复制
int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   QDialog dialog;
   QPushButton button{"OK", &dialog};
   button.setObjectName("okButton");
   button.setStyleSheet("color: red");

   auto dialog_l = QWidgetList() << &dialog;
   auto button_l = QWidgetList() << &button;
   auto all_l = button_l + dialog_l;
   Q_ASSERT(select("QPushButton#okButton") == button_l);
   Q_ASSERT(select("QDialog QPushButton") == button_l);
   Q_ASSERT(select("QDialog") == dialog_l);
   Q_ASSERT(select("QDialog, QPushButton") == all_l);
}

复写面食先于上面的内容:

代码语言:javascript
运行
复制
// https://github.com/KubaO/stackoverflown/tree/master/questions/css-selector-35129103
#include <QtWidgets>
#include <private/qcssparser_p.h>

using namespace QCss;

// FROM src/widgets/styles/qstylesheetstyle.cpp

#define OBJECT_PTR(node) (static_cast<QObject*>((node).ptr))

static inline QObject *parentObject(const QObject *obj)
{
   if (qobject_cast<const QLabel *>(obj) && qstrcmp(obj->metaObject()->className(), "QTipLabel") == 0) {
      QObject *p = qvariant_cast<QObject *>(obj->property("_q_stylesheet_parent"));
      if (p)
         return p;
   }
   return obj->parent();
}

class QObjectStyleSelector : public StyleSelector
{
public:
   QObjectStyleSelector() { }

   QStringList nodeNames(NodePtr node) const Q_DECL_OVERRIDE
   {
      if (isNullNode(node))
         return QStringList();
      const QMetaObject *metaObject = OBJECT_PTR(node)->metaObject();
#ifndef QT_NO_TOOLTIP
      if (qstrcmp(metaObject->className(), "QTipLabel") == 0)
         return QStringList(QLatin1String("QToolTip"));
#endif
      QStringList result;
      do {
         result += QString::fromLatin1(metaObject->className()).replace(QLatin1Char(':'), QLatin1Char('-'));
         metaObject = metaObject->superClass();
      } while (metaObject != 0);
      return result;
   }
   QString attribute(NodePtr node, const QString& name) const Q_DECL_OVERRIDE
   {
      if (isNullNode(node))
         return QString();

      auto obj = OBJECT_PTR(node);
      auto value = obj->property(name.toLatin1());
      if (!value.isValid()) {
         if (name == QLatin1String("class")) {
            auto className = QString::fromLatin1(obj->metaObject()->className());
            if (className.contains(QLatin1Char(':')))
               className.replace(QLatin1Char(':'), QLatin1Char('-'));
            return className;
         }
      }
      if(value.type() == QVariant::StringList || value.type() == QVariant::List)
         return value.toStringList().join(QLatin1Char(' '));
      else
         return value.toString();
   }
   bool nodeNameEquals(NodePtr node, const QString& nodeName) const Q_DECL_OVERRIDE
   {
      if (isNullNode(node))
         return false;
      auto metaObject = OBJECT_PTR(node)->metaObject();
#ifndef QT_NO_TOOLTIP
      if (qstrcmp(metaObject->className(), "QTipLabel") == 0)
         return nodeName == QLatin1String("QToolTip");
#endif
      do {
         const ushort *uc = (const ushort *)nodeName.constData();
         const ushort *e = uc + nodeName.length();
         const uchar *c = (const uchar *)metaObject->className();
         while (*c && uc != e && (*uc == *c || (*c == ':' && *uc == '-'))) {
            ++uc;
            ++c;
         }
         if (uc == e && !*c)
            return true;
         metaObject = metaObject->superClass();
      } while (metaObject != 0);
      return false;
   }
   bool hasAttributes(NodePtr) const Q_DECL_OVERRIDE
   { return true; }
   QStringList nodeIds(NodePtr node) const Q_DECL_OVERRIDE
   { return isNullNode(node) ? QStringList() : QStringList(OBJECT_PTR(node)->objectName()); }
   bool isNullNode(NodePtr node) const Q_DECL_OVERRIDE
   { return node.ptr == 0; }
   NodePtr parentNode(NodePtr node) const Q_DECL_OVERRIDE
   { NodePtr n; n.ptr = isNullNode(node) ? 0 : parentObject(OBJECT_PTR(node)); return n; }
   NodePtr previousSiblingNode(NodePtr) const Q_DECL_OVERRIDE
   { NodePtr n; n.ptr = 0; return n; }
   NodePtr duplicateNode(NodePtr node) const Q_DECL_OVERRIDE
   { return node; }
   void freeNode(NodePtr) const Q_DECL_OVERRIDE
   { }
};

// END FROM
代码语言:javascript
运行
复制
#cssparser-35129103.pro
QT = widgets gui-private
CONFIG += c++11
TARGET = cssparser-35129103
TEMPLATE = app
SOURCES += main.cpp
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35129103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档