Qt - 重新加载小部件内容

Posted

技术标签:

【中文标题】Qt - 重新加载小部件内容【英文标题】:Qt - reloading widget contents 【发布时间】:2010-03-08 15:27:46 【问题描述】:

我正在尝试通过添加一个按钮来修改fridge magnets example,该按钮将重新加载绘制可拖动标签的小部件,反映对其读取的文本文件所做的任何更改。我定义了另一个包含按钮和 DragWidget 对象的类,所以在 main() 中会有这个类的实例而不是 DragWidget:

class wrapWidget: public QWidget

    Q_OBJECT
public:
    wrapWidget();

;

wrapWidget::wrapWidget()

    QGridLayout *gridlayout = new QGridLayout();
    DragWidget *w = new DragWidget();
    QPushButton *b = new QPushButton("refresh");
    gridlayout ->addWidget(w,0,0);
    gridlayout ->addWidget(b,1,0);
    setLayout(gridlayout );

    connect(b,SIGNAL(clicked()),w,SLOT(draw()));

连接调用是我尝试刷新的地方。在最初的冰箱贴示例中,所有的标签绘制代码都在 DragWidget 类的构造函数中。我将该代码移到了一个名为“draw()”的公共方法中,并从构造函数中调用了该方法。下面是 DragWidget 的定义和实现:

#include <QWidget>

QT_BEGIN_NAMESPACE
class QDragEnterEvent;
class QDropEvent;
QT_END_NAMESPACE

class DragWidget : public QWidget

public:
    DragWidget(QWidget *parent = 0);

public slots:
    void draw();

protected:
    void dragEnterEvent(QDragEnterEvent *event);
    void dragMoveEvent(QDragMoveEvent *event);
    void dropEvent(QDropEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *event);
;

DragWidget::DragWidget(QWidget *parent)
    : QWidget(parent)


    draw();

    QPalette newPalette = palette();
    newPalette.setColor(QPalette::Window, Qt::white);
    setPalette(newPalette);

    setMinimumSize(400, 100);//qMax(200, y));
    setWindowTitle(tr("Fridge Magnets"));
    setAcceptDrops(true);


void DragWidget::draw()
    QFile dictionaryFile(":/dictionary/words.txt");
    dictionaryFile.open(QFile::ReadOnly);
    QTextStream inputStream(&dictionaryFile);

    int x = 5;
    int y = 5;

    while (!inputStream.atEnd()) 
        QString word;
        inputStream >> word;
        if (!word.isEmpty()) 
            DragLabel *wordLabel = new DragLabel(word, this);
            wordLabel->move(x, y);
            wordLabel->show();
            wordLabel->setAttribute(Qt::WA_DeleteOnClose);
            x += wordLabel->width() + 2;
            if (x >= 245) 
                x = 5;
                y += wordLabel->height() + 2;
            
        
    

我认为也许调用 draw() 作为插槽就足以重新加载标签,但它不起作用。将 draw() 调用放在小部件的重写 paintEvent() 中而不是构造函数中也没有奏效,程序最终会陷入无限循环。

我所做的显然不是正确的做法,那我应该怎么做呢?

【问题讨论】:

【参考方案1】:

我的快速猜测是,您没有在 dragwidget.h 头文件中添加 Q_OBJECT 宏,没有生成 DragWidget 类的 moc 文件,并且连接失败并出现“no such slot as draw()”错误。

将“CONFIG += 控制台”添加到 .pro 文件可能也是一个好主意 - 您会看到所有警告消息(例如关于连接错误的警告消息),因此跟踪此类错误会更容易。您还可以检查连接的返回值。

【讨论】:

确实,我在项目的 .pro 文件中添加了 CONFIG+=console 东西,当我运行程序时,它显示“没有像 draw() 这样的插槽”错误。 dragwidget.h 头文件大部分与原始示例中的一样,它没有 Q_OBJECT 宏。当我将它添加到代码中时,它发出了这个错误:“collect2:ld 返回 1 退出状态”。将 Q_OBJECT 宏添加到我的自定义 wrapwidget.h 标头中并没有导致任何不同,但仍然会发出相同的错误。 Q_OBJECT 宏扩展为声明所有信号/插槽的魔法所需的方法。这些方法的定义由 moc.exe 程序生成在单独的文件中。您不必自己调用它,qmake 为每个带有 Q_OBJECT 宏的头文件添加了对 makefile 的正确调用。为什么会出现链接器错误? Q_OBJECT 扩展为声明,但未生成定义,因为您在添加 Q_OBJECT 后未运行 qmake,并且未使用对 DragWidget 类的 moc.exe 调用更新 makefile。另外,请确保将 draw() 声明为公共插槽,而不仅仅是公共方法。 为了完整起见,我已经添加了 DragWidget 的其余代码。我还在我的自定义 wrapwidget 类上添加了 Q_OBJECT 宏(但正如我之前所说,它没有导致任何可见的更改),并省略了我在原始示例中没有更改的所有内容。您可以看到我确实将 draw() 声明为公共插槽。我正在使用 Qt Creator 编辑和编译我的代码,所以它不可能是 qmake 问题,除非我不知道 Qt Creator 存在问题。 插槽在 DragWidget 类中,因此 Q_OBJECT 应该在 DragWidget 类中,而不是在 wrapWidget 类中(尽管通常建议将 Q_OBJECT 宏添加到所有 QObject 子类以避免您遇到的问题现在)。 我不知道是不是这个问题。未修改的示例工作正常,原始 DragWidget 声明中没有 Q_OBJECT 宏(但是,原始代码中没有插槽)。除了将一些代码从构造函数重新定位到新创建的 draw() 槽之外,我没有更改 DragWidget 类中的任何内容。将宏添加到 DragWidget 类声明中会出现此错误:collect2: ld returned 1 exit status。显然有些东西不允许我添加那个类的宏,也许它与那个命名空间的东西有关?【参考方案2】:

我注意到你是这样打开文件的:

QFile dictionaryFile(":/dictionary/words.txt");

注意文件名以“:”开头,表示该文件将从你的qrc资源包中读取,而不是从你的本地磁盘中读取。所以如果你对words.txt做了修改,下次编译qrc文件时才会被代码读取。所以你一定知道如何解决它,对吧?祝你好运:)

【讨论】:

正在读取文件,我在再次运行程序之前更改了它,我可以看到标签不同。问题是在程序运行时重绘标签,它说没有这样的插槽 QWidget::draw()。 现在我已经让 draw() 工作了,我确实必须更改文件名。我将其更改为“../words.txt”,现在它读取了正确的文件。阅读一些关于 qrc 文件的信息,似乎资源在最终的可执行文件中被“编译”,但我猜这对于经常修改的文件不一定有好处

以上是关于Qt - 重新加载小部件内容的主要内容,如果未能解决你的问题,请参考以下文章

如何在 QT 设计器中重新绘制小部件

从 Qt 中的文本文件填充表格小部件

如何在另一个小部件更新qt中的相同内容后更新小部件内容

Qt - QScrollArea 小部件剪辑内容

如何正确删除小部件并更新/重新加载小部件

Qt 加载消息应保持在父小部件的顶部并居中