【问题标题】:How to properly compare Q_ENUM and QStringList如何正确比较 Q_ENUM 和 QStringList
【发布时间】:2021-01-28 03:59:39
【问题描述】:

我有一个小例子.ui,用户可以使用QGraphicsProxyWidget 将一个特定的小部件(在我的例子中是QTableWidget)从QListWidget 拖放到QGraphicsView,如下所示。

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

如果我拖放“Imgaes”,QTableWidget 上的 QGraphicsView 将有 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&amp; comp); 函数并尝试将工作委托给 switch - case 语句的原因,但这也没有像我预期的那样工作,我仍然看到相同的 QtableWidget 掉到QGraphicsView.

当然,我做了更多的研究,发现了this 来源,最重要的是this post,这对于理解基本比较很有用,在这篇文章之后,我决定继续尝试应用Q_ENUM - QString 甚至QStringList 作为一个有价值的工具。但我无法弄清楚我做错了什么。

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

【问题讨论】:

  • 我认为给定的代码甚至不会产生错误的输出。 tabs 只是一个空列表,那么对于tabs 中的每个元素,显示一个表格?
  • 我假设comp 是“图像”或“路径”,为什么使用toUpper()
  • 您好@NgocMinhNguyen,感谢您停下来阅读这个问题。是的comp 用于“图像”或“路径”。我遇到的问题是我试图将其与使用 template&lt;typename QEnum&gt; 函数结合起来。与QEnumQString 相比,这是我练习使用template&lt;&gt; 的一种方式,但是缺少一些东西,无法弄清楚可能是什么。
  • 你还没有回答我的问题
  • 对不起,你是对的 :) 好的,所以:1) 是的,tabs 中的每个元素都会显示一个表格。 2) 我使用toUpper() 的方式使从QListWidget 选择(例如“图像”、“路径”)到QGraphicsView 的darg-drop 区分大小写。因此,如果有“图像”而不是“图像”,MetaEnum 应该抛出错误,因此template&lt;typename QEnum&gt; 应该能够处理。

标签: c++11 qt5 qtablewidget qstring qenum


【解决方案1】:

我在您的代码中看到了两个问题:

  1. 错误的参数传递给keyToValue()。由于您的枚举中有ImagePath,因此传递给keyToValue() 的有效值为“Image”(返回0)和“Path”(返回1),其他值将返回-1。

  2. 在函数Scene::compare() 中,tabs 只是创建为一个空的QStringList,因此循环内的代码for (const QString &amp;color : tabs) 永远不会执行

下面是一个测试程序来告诉你我的意思:

主窗口.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

主窗口.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

【讨论】:

  • 感谢您抽出宝贵时间回答我的问题。我现在明白你对Q_ENUM 的意思以及如何正确使用它了。非常感谢您的时间:)。另外,如果您认为我的问题很清楚,请给我一个大拇指:)
猜你喜欢
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
  • 2015-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-18
  • 1970-01-01
相关资源
最近更新 更多