首页 > 解决方案 > QColor 到人类可读的字符串

问题描述

我在 QML 中有一个颜色对象,我认为它是 QColor 的一个实例,使用调试器我可以看到颜色对象包含:

    a                1
    b                0
    g                0
    hslHue           -1
    hslLightness     0
    hslSaturation    0
    hsvHue           -1
    hsvSaturation    0
    hsvValue         0
    r                0

有没有办法将它翻译成人类可读的字符串,例如 Red ?

标签: c++qttostringqcolor

解决方案


颜色是一个很难的话题。(如果您曾经将两个屏幕连接到您的计算机并尝试将它们配置为相同的颜色配置文件,您就会明白我的意思。)

尽管如此,我认为OP的意图是合理的。如果 Qt 可以处理人类可读的颜色名称,为什么不可逆?

起初,我查看了手册 - QColor

可以通过将 RGB 字符串(例如“#112233”)、ARGB 字符串(例如“#ff112233”)或颜色名称(例如“blue”)传递给setNamedColor()函数来设置颜色。颜色名称取自 SVG 1.0 颜色名称。name()函数以“#RRGGBB”格式返回颜色名称。

关于QColor::name()听起来的陈述与 OP 所描述的完全一样。为了完全说服自己,我制作了一个 MCVE,但它并没有改变任何东西。

好的。所以,这不是一个错误——它是一个特性。

如果 Qt 中缺少它,如何添加它?Qt 似乎“知道”所有的名字。因此,如果不能以某种方式利用它,那将会很烦人。

我点击了一下文档。并在文档中找到例如。的QColor::setNamedColor SVG 颜色名称表的链接。

所以,我考虑了一秒钟只是为了复制它。

我还找到了SVG Colors。请注意,它带有

自:Qt 5.14

并且仍然是qt5-dev文档的一部分。(在撰写本文时)。

woboq.org,我偶然发现了以下颜色名称的负责源代码qtbase/src/gui/painting/qcolor.cpp

#ifndef QT_NO_COLORNAMES
/*
  CSS color names = SVG 1.0 color names + transparent (rgba(0,0,0,0))
*/
#ifdef rgb
#  undef rgb
#endif
#define rgb(r,g,b) (0xff000000 | (r << 16) |  (g << 8) | b)
static const struct RGBData {
    const char name[21];
    uint  value;
} rgbTbl[] = {
    { "aliceblue", rgb(240, 248, 255) },
    { "antiquewhite", rgb(250, 235, 215) },
    { "aqua", rgb( 0, 255, 255) },

    { "yellow", rgb(255, 255, 0) },
    { "yellowgreen", rgb(154, 205, 50) }
};
static const int rgbTblSize = sizeof(rgbTbl) / sizeof(RGBData);
#undef rgb

最后,我最终进入了QColor::colorNames()

QStringList QColor::colorNames() [静态]

返回包含 Qt 知道的颜色名称的QStringList 。

另请参见预定义颜色

使用所有颜色名称的列表(Qt 可以识别)很容易构建反向映射表。

我制作了一个MCVE testQColorName.cc来证明这一点:

#include <functional>
#include <unordered_map>

// Qt header:
#include <QtWidgets>

namespace std {

template <> struct hash<QColor> {
  size_t operator()(const QColor &color) const
  {
    return std::hash<QRgb>()(color.rgb());
  }
};

} // namespace std

typedef std::unordered_map<QColor, QString> ColorNameMap;

class ColorButton: public QPushButton {
  private:
    QColor _qColor;

  public:
    explicit ColorButton(
      const QString &text = QString(), const QColor &qColor = Qt::black,
      QWidget *pQParent = nullptr):
      QPushButton(text, pQParent)
    {
      setColor(qColor);
    }
    virtual ~ColorButton() = default;
    ColorButton(const ColorButton&) = delete;
    ColorButton& operator=(const ColorButton&) = delete;

    const QColor& color() const { return _qColor; }
    void setColor(const QColor &qColor)
    {
      _qColor = qColor;
      QFontMetrics qFontMetrics(font());
      const int h = qFontMetrics.height();
      QPixmap qPixmap(h, h);
      qPixmap.fill(_qColor);
      setIcon(qPixmap);
    }

    QColor chooseColor()
    {
      setColor(QColorDialog::getColor(_qColor, this, text()));
      return _qColor;
    }
};

// main application
int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // setup data
  const ColorNameMap qMapColorNames = []() {
    ColorNameMap qMapColorNames;
    const QStringList qColorNames = QColor::colorNames();
    for (const QString &qColorName : qColorNames) {
      qMapColorNames[QColor(qColorName)] = qColorName;
      qDebug() << qColorName;
    }
    return qMapColorNames;
  }();
  // setup GUI
  QWidget qWinMain;
  qWinMain.setWindowTitle(QString::fromUtf8("Test Color Name"));
  QHBoxLayout qHBox;
  QLabel qLblColor(QString::fromUtf8("Color:"));
  qHBox.addWidget(&qLblColor);
  QLineEdit qEditColor;
  qHBox.addWidget(&qEditColor, 1);
  ColorButton qBtnColor;
  qHBox.addWidget(&qBtnColor);
  qWinMain.setLayout(&qHBox);
  qWinMain.show();
  qEditColor.setText(qBtnColor.color().name());
  // install signal handlers
  QObject::connect(&qBtnColor, &QPushButton::clicked,
    [&]() {
      const QColor qColor = qBtnColor.chooseColor();
      const ColorNameMap::const_iterator iter = qMapColorNames.find(qColor);
      qEditColor.setText(iter != qMapColorNames.end() ? iter->second : qColor.name());
    });
  QObject::connect(&qEditColor, &QLineEdit::textEdited,
    [&](const QString &text) {
      const QColor qColor(text);
      qBtnColor.setColor(qColor);
    });
  // runtime loop
  return app.exec();
}

输出:

testQColorName 的快照(文本输入后)

testQColorName 的快照(使用颜色按钮选择颜色#ff0000 后)

控制台输出:

Qt Version: 5.13.0
"aliceblue"
"antiquewhite"
"aqua"
"aquamarine"
"azure"
"beige"
"bisque"
"black"
"blanchedalmond"
"blue"
"blueviolet"
"brown"
"burlywood"
"cadetblue"
"chartreuse"
"chocolate"
"coral"
"cornflowerblue"
"cornsilk"
"crimson"
"cyan"
"darkblue"
"darkcyan"
"darkgoldenrod"
"darkgray"
"darkgreen"
"darkgrey"
"darkkhaki"
"darkmagenta"
"darkolivegreen"
"darkorange"
"darkorchid"
"darkred"
"darksalmon"
"darkseagreen"
"darkslateblue"
"darkslategray"
"darkslategrey"
"darkturquoise"
"darkviolet"
"deeppink"
"deepskyblue"
"dimgray"
"dimgrey"
"dodgerblue"
"firebrick"
"floralwhite"
"forestgreen"
"fuchsia"
"gainsboro"
"ghostwhite"
"gold"
"goldenrod"
"gray"
"green"
"greenyellow"
"grey"
"honeydew"
"hotpink"
"indianred"
"indigo"
"ivory"
"khaki"
"lavender"
"lavenderblush"
"lawngreen"
"lemonchiffon"
"lightblue"
"lightcoral"
"lightcyan"
"lightgoldenrodyellow"
"lightgray"
"lightgreen"
"lightgrey"
"lightpink"
"lightsalmon"
"lightseagreen"
"lightskyblue"
"lightslategray"
"lightslategrey"
"lightsteelblue"
"lightyellow"
"lime"
"limegreen"
"linen"
"magenta"
"maroon"
"mediumaquamarine"
"mediumblue"
"mediumorchid"
"mediumpurple"
"mediumseagreen"
"mediumslateblue"
"mediumspringgreen"
"mediumturquoise"
"mediumvioletred"
"midnightblue"
"mintcream"
"mistyrose"
"moccasin"
"navajowhite"
"navy"
"oldlace"
"olive"
"olivedrab"
"orange"
"orangered"
"orchid"
"palegoldenrod"
"palegreen"
"paleturquoise"
"palevioletred"
"papayawhip"
"peachpuff"
"peru"
"pink"
"plum"
"powderblue"
"purple"
"red"
"rosybrown"
"royalblue"
"saddlebrown"
"salmon"
"sandybrown"
"seagreen"
"seashell"
"sienna"
"silver"
"skyblue"
"slateblue"
"slategray"
"slategrey"
"snow"
"springgreen"
"steelblue"
"tan"
"teal"
"thistle"
"tomato"
"transparent"
"turquoise"
"violet"
"wheat"
"white"
"whitesmoke"
"yellow"
"yellowgreen"

笔记:

似乎QColor它既没有提供 less(允许用作 key in std::map)也没有提供专门化std::hash(允许用作 key in std::unordered_map)。std::hash所以,我不得不专攻QColor.

SO:如何为无序容器中的用户定义类型专门化 std::hash::operator()?)


推荐阅读