如何正确比较 Q_ENUM 和 QStringList

How to properly compare Q_ENUM and QStringList

我有一个小例子 .ui,用户可以使用 QGraphicsProxyWidgetQListWidget 拖放到 QGraphicsView 一个特定的小部件(在我的例子中是a QTableWidget) 如下图。

基本上我一直在寻找的行为是:

如果我拖放“Imgaes”,那么 QGraphicsView 上的 QTableWidget 将有 2 列和 2 行; (哪个是正确的) 如果我拖放“路径”,那么 QGraphicsView 上的 QTableWidget 将有 3 列和 3 行; (这是错误的)

[1] : https://imgur.com/NQ1DZpx

下面选择“路径”,仍然给出2行2列,而不是3行3列

[2] : https://imgur.com/d4YcOiL

代码下方:

scene.h

class Scene : public QGraphicsScene {

    enum LaserTableWidget {
      Images,
      Path
    };
    Q_ENUM(LaserTableWidget)

public:
  Scene(QObject *parent = nullptr);

  void compare(const QString& comp);

  template<typename QEnum>
  std::string QtEnumToString (const QEnum value)
  {
    return std::string(QMetaEnum::fromType<QEnum>().valueToKey(value));
  }

protected:
  void dropEvent(QGraphicsSceneDragDropEvent *event);

scene.cpp

Scene::Scene(QObject *parent) : QGraphicsScene(parent) {
    setBackgroundBrush(Qt::lightGray);
}

void Scene::compare(const QString &comp)
{
    // get information about the enum named "LaserTableWidget"
    QMetaObject MetaObject = this->staticMetaObject;
    QMetaEnum MetaEnum = MetaObject.enumerator(MetaObject.indexOfEnumerator("LaserTableWidget"));
    QStringList tabs;

    switch (MetaEnum.keyToValue(comp.toUpper().toLatin1()))
    // or simply switch (MetaEnum.keyToValue(word)) if no string modification is needed
    {
        case Images:
        for (const QString &color : tabs) {
            QPoint initPos(0,0);

            QTableWidget *wgt = new QTableWidget;
            QGraphicsRectItem *proxyControl = addRect(initPos.x(), initPos.y(), wgt->width(), 20, QPen(Qt::black), QBrush(Qt::darkGreen)); // widget->width() works properly here because of the resize(layout->sizeHint()) that we have used inside it
            proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
            proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);

            wgt->setColumnCount(2);
            wgt->setRowCount(2);
            for (int ridx = 0 ; ridx < wgt->rowCount() ; ridx++ )
            {
                for (int cidx = 0 ; cidx < wgt->columnCount() ; cidx++)
                {
                    QTableWidgetItem* item = new QTableWidgetItem();
                    item->setText(QString("%1").arg(ridx));
                    wgt->setItem(ridx,cidx,item);
                }
            }
            QGraphicsProxyWidget * const proxy = addWidget(wgt);
            // In my case the rectangular graphics item is supposed to be above my widget so the position of the widget is shifted along the Y axis based on the height of the rectangle of that graphics item
            proxy->setPos(initPos.x(), initPos.y()+proxyControl->rect().height());
            proxy->setParentItem(proxyControl);
        }

        break;
        case Path:
        for (const QString &color : tabs) {
            QPoint initPos(0,0);

            QTableWidget *wgt = new QTableWidget;
            QGraphicsRectItem *proxyControl = addRect(initPos.x(), initPos.y(), wgt->width(), 20, QPen(Qt::black), QBrush(Qt::darkGreen)); // widget->width() works properly here because of the resize(layout->sizeHint()) that we have used inside it
            proxyControl->setFlag(QGraphicsItem::ItemIsMovable, true);
            proxyControl->setFlag(QGraphicsItem::ItemIsSelectable, true);

            wgt->setColumnCount(3);
            wgt->setRowCount(3);
            for (int ridx = 0 ; ridx < wgt->rowCount() ; ridx++ )
            {
                for (int cidx = 0 ; cidx < wgt->columnCount() ; cidx++)
                {
                    QTableWidgetItem* item = new QTableWidgetItem();
                    item->setText(QString("%1").arg(ridx));
                    wgt->setItem(ridx,cidx,item);
                }
            }
            QGraphicsProxyWidget * const proxy = addWidget(wgt);
            // In my case the rectangular graphics item is supposed to be above my widget so the position of the widget is shifted along the Y axis based on the height of the rectangle of that graphics item
            proxy->setPos(initPos.x(), initPos.y()+proxyControl->rect().height());
            proxy->setParentItem(proxyControl);
        }
        break;

        default:
        break;
    }
}


void Scene::dropEvent(QGraphicsSceneDragDropEvent *event) {

  QByteArray encoded =
      event->mimeData()->data("application/x-qabstractitemmodeldatalist");
  QDataStream stream(&encoded, QIODevice::ReadOnly);

  QStringList rosTables;

  while (!stream.atEnd()) {
    int row, col;
    QMap<int, QVariant> roleDataMap;
    stream >> row >> col >> roleDataMap;
    rosTables << roleDataMap[Qt::DisplayRole].toString();
  }

  compare(const QString &comp)
}

我尝试使用在头文件中声明的 template 函数,为了完整起见,我还在下面附上:

  template<typename QEnum>
  std::string QtEnumToString (const QEnum value)
  {
    return std::string(QMetaEnum::fromType<QEnum>().valueToKey(value));
  }

也许我的模板函数选择错误?如果可能的话,我试图找到一种使用它的方法。

这就是我切换到 void compare(const QString& comp); 函数并尝试将工作委托给 switch - case 语句的原因,但这也没有像我预期的那样工作,我仍然看到完全相同的情况QtableWidget 掉落到 QGraphicsView.

当然,我做了更多的研究,发现了 this source and above all ,这对理解基本比较很有用,然后 post 我决定继续尝试应用 Q_ENUM - QString甚至 QStringList 作为一个有价值的工具。但是我不知道我做错了什么。

谁能阐明哪种方法更好? (或者也许他们都是正确的)并尝试解释我缺少什么来解决这个问题。

我在您的代码中发现了两个问题:

  1. 传递给 keyToValue() 的参数错误。由于您的枚举中有 ImagePath,因此传递给 keyToValue() 的有效值是“图像”(returns 0)和“路径”(return1),其他值会returns -1.

  2. 在函数Scene::compare()中,tabs只是被创建为空的QStringList,所以循环for (const QString &color : tabs)中的代码永远不会执行

下面是一个测试程序,向您展示我的意思:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMetaEnum>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    enum LaserTableWidget
    {
        Images,
        Path
    };
    Q_ENUM(LaserTableWidget)

    template<typename enum_type>
    QString QtEnumToString (const enum_type value)
    {
        return QMetaEnum::fromType<enum_type>().valueToKey(value);
    }
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"

#include <QDebug>
#include <QStringList>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // First problem: wrong parameter passed to keyToValue()

    qDebug() << 1 << QtEnumToString<LaserTableWidget>(Images);
    qDebug() << 2 << QtEnumToString<LaserTableWidget>(Path);

    QMetaObject MetaObject = this->staticMetaObject;
    QMetaEnum MetaEnum = MetaObject.enumerator(MetaObject.indexOfEnumerator("LaserTableWidget"));

    qDebug() << 3 << MetaEnum.keyToValue(QtEnumToString<LaserTableWidget>(Path).toUpper().toLatin1());
    qDebug() << 4 << MetaEnum.keyToValue(QtEnumToString<LaserTableWidget>(Path).toStdString().c_str());

    switch (MetaEnum.keyToValue(QtEnumToString<LaserTableWidget>(Path).toUpper().toLatin1()))
    {
        case Images:
            qDebug() << "switch Images";
            break;
        case Path:
            qDebug() << "switch Path";
            break;
        default:
            qDebug() << "switch default";
            break;
    }

    // Second problem: tabs is empty
    QStringList tabs;
    for (const QString &color : tabs)
        qDebug() << color; // this line is never executed
}

MainWindow::~MainWindow()
{
}

输出:

1 "Images"
2 "Path"
3 -1
4 1
switch default