【问题标题】:Qt - How to convert from QObject to UI elements?Qt - 如何从 QObject 转换为 UI 元素?
【发布时间】:2014-03-12 10:41:10
【问题描述】:

我在 Qt 4.7 中工作,我的对话框中有一个 QWidget 对象。我需要遍历每个孩子并将当前文本提取到 QStringList 中。每个其他对象都是 QCheckBox,其余的是 QComboBoxes(我只需要两者的文本部分)。到目前为止,我能想到的唯一方法是使用 children() 函数将它们作为 QObject* 并将它们转换,如下所示:

QStringList textlist;
for(int i = 0; i < ui->myWidget->children().size(); i++)
{
    if(i % 2 == 0)
    {
        QCheckBox *q = (QCheckBox *)ui->myWidget->children().at(i);
        textlist.append(q->text());
    }
    else
    {
        QComboBox *q = (QComboBox *)ui->myWidget->children().at(i);
        textlist.append(q->currentText());
    }
}

但是,当我尝试使用它时,它可以正常构建和编译,但在运行时会崩溃。我查了一下,这两个类都是 QObject 的子类(尽管间接通过 QAbstractButton 和 QWidget),它是列表 ui->myWidget->children() 中对象的类型,所以我觉得它们应该能够以这种方式进行转换.我以前没有在这种事情上做过很多工作,所以我不确定是否有更好的方法来做到这一点。如果有人有任何想法,将不胜感激。谢谢!

更新:所以,我无法以这种方式或使用 qobject_cast 进行强制转换。然而,我发现我可以从 QObject 转到 QWidget,并且我认为我应该能够使用 dynamic_cast 从 QWidget 转到所需的对象,但这也不起作用。现在我有这个:

QStringList textlist;
for(int i = 0; i < ui->myWidget->children().size(); i++)
{
    QWidget *qw = qobject_cast<QWidget*>(ui->myWidget->children().at(i)
    if(i % 2 == 0)
    {
        QComboBox *q = dynamic_cast<QComboBox*>(qw);
        if(q)
        {
            textlist.append(q->text());
        }
    }
    else
    {
        QCheckBox *q = dynamic_cast<QCheckBox*>(qw);
        if(q)
        {
            textlist.append(q->currentText());
        }
    }
}

如果有人有任何想法,我将不胜感激。谢谢。

UPDATE2:我还没有在网上找到太多对此有帮助的东西,所以我也不妨问一下,是否有办法在不强制转换的情况下执行此操作,即直接从 QWidget 中以原始类型获取对象,我也很感激。我对我目前的策略或任何事情都不满意,这只是我能想到的唯一方法——我会采取任何在这一点上有效的方法。

【问题讨论】:

  • 使用 qobject_cast&lt;QComboBox*&gt;(ptr) 而不是您正在使用的 C 样式转换,并在访问文本之前检查转换是否成功。您使用 C 风格转换的方式非常危险,因为如果转换失败,则不会发出警告。对于失败的 C 风格转换,当您尝试使用指针时,充其量只会崩溃。在最坏的情况下,您会得到无声的数据损坏。
  • @Slavik81 有什么技巧可以让它发挥作用吗?它给了我诸如“无法从'重载功能'转换为'QCheckBox *'”之类的错误
  • @Slavik81 别在意我的评论,这只是我的一个愚蠢的错字。谢谢!
  • 一般来说,避免在 C++ 代码中强制转换 C 风格,并且永远不要将它与 OOP 对象一起使用。请注意,指向 same 对象实例的指针可能具有不同的值,具体取决于 pointer 的类型。

标签: c++ qt qt4 qwidget


【解决方案1】:

您应该考虑使用qobject_cast。施法后,您还应该检查对象是否有效。

QStringList textlist;
for(int i = 0; i < ui->myWidget->children().size(); i++)
{
    if(i % 2 == 0)
    {
        QCheckBox *q = qobject_cast<QCheckBox*>(ui->myWidget->children().at(i));
        if(q)
           textlist.append(q->text());
    }
    else
    {
        QComboBox *q = qobject_cast<QComboBox*>(ui->myWidget->children().at(i));
        if(q)
           textlist.append(q->currentText());
    }
}

但这对我来说仍然是一个糟糕的设计。包含组合框和复选框的小部件类应该有一个函数,它通过复选框和组合框并返回一个QStringList。然后你就可以调用那个函数了。

这是一个例子

mywidget.h:

namespace Ui {
class MyWidget;
}

class MyWidget : public QWidget
{
    Q_OBJECT

public:
    explicit MyWidget(QWidget *parent = 0);
    ~MyWidget();
    QStringList getComboTextList();
    QStringList getCheckBoxTextList();

private:
    Ui::MyWidget *ui;
    QList<QComboBox*> comboList;
    QList<QCheckBox*> checkList;
};

mywidget.cpp:

MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    this->setLayout(new QVBoxLayout);
    for(int i = 0; i < 5; i++)
    {
        QCheckBox *checkBox = new QCheckBox(this);
        this->layout()->addWidget(checkBox);
        checkBox->setText(QString("Check box #%1").arg(i));
        checkList.append(checkBox);
    }

    for(int i = 0; i < 5; i++)
    {
        QComboBox *comboBox = new QComboBox(this);
        this->layout()->addWidget(comboBox);
        comboBox->addItem("Combo box item 1");
        comboBox->addItem("Combo box item 2");
        comboList.append(comboBox);
    }
}

MyWidget::~MyWidget()
{
    delete ui;
}

QStringList MyWidget::getComboTextList()
{
    QStringList returnList;
    for(int i = 0; i < comboList.length(); i++)
    {
        returnList << comboList[i]->currentText();
    }
    return returnList;
}

QStringList MyWidget::getCheckBoxTextList()
{
    QStringList returnList;
    for(int i = 0; i < checkList.length(); i++)
    {
        returnList << checkList[i]->text();
    }
    return returnList;
}

然后在您的其他班级中,您可以像这样调用getCheckBoxTextListgetComboTextList

QStringList comboTextList = myWidget->getComboBoxList();
QStringList checkTextList = myWidget->getCheckBoxTextList();

【讨论】:

  • 谢谢,我也有同样的想法,但在 QWidget 中找不到类似的功能。另外,就像我在上面问过的 Slavik 一样,是否有让 qobject_cast 正常工作的技巧?
  • 实际上,很遗憾我需要撤回最后一条评论。我正在运行更多测试,if 语句阻止它崩溃,但是强制转换似乎仍然不起作用,当我在 if(q) 中放入 else 时,它​​转到 else 语句:( 记录,我有上面答案的格式,只是添加了 else 语句与 if(q) 语句一起编辑:但是,我发现它可以成功地从 QObject* 转换为 QWidget*,所以如果我可以弄清楚如何从 QWidget* 到 QCheckBox* 我会设置。
  • @thnkwthprtls 您的转换失败的原因是因为您试图将某个对象转换为QCheckBox,即使它是完全不同的类型。这是因为你的逻辑不起作用。将其投射到 QWidget frist 对您没有帮助。您可以删除您的 if(i %2 == 0) 语句和相应的 else 语句,然后检查演员表是否有效。但我仍然建议您将QWidget 子类化,在其中添加QCheckBoxQComboBox 对象,并添加一个通过它们并返回QStringList 的函数。这样您就不必进行任何强制转换,而且会更加 OOP。
  • 但是 QCheckBox 和 QComboBox 不是已经是 QWidget 的子类了吗?
  • ...好吧,老实说我完全不知道为什么,但是昨天下午当我尝试这个时它没有工作......现在今天早上它可以了哈哈。我没有更改代码中的任何内容,可能是编译的目标文件有问题或其他什么......老实说我不知道​​,但现在你的代码可以工作了,谢谢!
猜你喜欢
  • 1970-01-01
  • 2013-02-13
  • 2023-04-04
  • 1970-01-01
  • 2017-02-17
  • 2016-12-31
  • 1970-01-01
  • 2011-09-24
  • 2016-11-08
相关资源
最近更新 更多