tags:

views:

130

answers:

2

I'm trying to modify the fridge magnets example by adding a button that will reload the widget where the draggable labels are drawn, reflecting any changes made to the text file it reads. I defined another class that would contain the button and the DragWidget object, so there would be an instance of this class instead of DragWidget in main():

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()));
}

The call to connect is where I'm trying to do the refresh thing. In the original fridge magnets example, all the label drawing code was inside the constructor of the DragWidget class. I moved that code to a public method that I named 'draw()', and called this method from the constructor instead. Here's DragWidget definition and implementation:

#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;
            }
        }
    }
}

I thought that maybe calling draw() as a slot would be enough to reload the labels, but it didn't work. Putting the draw() call inside the widget's overriden paintEvent() instead of the constructor didn't work out as well, the program would end up in an infinite loop.

What I did was obviously not the right way of doing it, so what should I be doing instead?

+2  A: 

My quick guess is, you haven't added Q_OBJECT macro to dragwidget.h header, the moc file for DragWidget class wasn't generated and the connect failed with "no such slot as draw()" error.

It might be also a good idea to add "CONFIG += console" to .pro file - you'll see all warning messages (like the one about connect error), so tracking such mistakes would be easier. You might also check return value of connect.

chalup
Indeed, I added the CONFIG+=console thing to the project's .pro file, and when I run the program it shows the "no such slot as draw()" error.The dragwidget.h header was left mostly as it was in the original example, it didn't have the Q_OBJECT macro. When I added it to the code, it gave off this error: "collect2: ld returned 1 exit status".Adding the Q_OBJECT macro to my custom wrapwidget.h header instead haven't resulted in anything different, still gives off the same error.
David McDavidson
Q_OBJECT macro expands to declarations of methods that are needed for all the magic of signals/slots to work. The definitions of these methods are generated in separate files by moc.exe program. You don't have to call it yourself, qmake adds proper calls to makefile for every header with Q_OBJECT macro.Why do you get linker error? Q_OBJECT expands to declaration, but definitions are not generated, cause you didn't run qmake after adding Q_OBJECT and makefile wasn't updated with moc.exe call for DragWidget class.Also, make sure you declare draw() as public slot, not just public method.
chalup
I've added the rest of the DragWidget code for completeness. I also added the Q_OBJECT macro on my custom wrapwidget class (but as I said before, it didn't result in any visible change), and ommited everything I didn't change from the original example. You can see that I did declare draw() as a public slot. I'm editing and compiling my code with Qt Creator, so it can't be a qmake problem, unless there's a issue with Qt Creator I'm not aware of.
David McDavidson
The slot is in the DragWidget class, so the Q_OBJECT should be in DragWidget class, not in wrapWidget class (although it's generally recommended to add Q_OBJECT macro to all QObject subclasses to avoid the problems you're having right now).
chalup
I don't know if that's the problem. The unmodified example works fine, and there's no Q_OBJECT macro in the original DragWidget declaration (but then, there's no slot in the original code). I haven't changed anything in the DragWidget class apart from relocating some code from the constructor to the newly created draw() slot. Adding the macro to the DragWidget class declaration gives this error: collect2: ld returned 1 exit status. Apparently there's something that won't let me add the macro that class, maybe it has something to do with that namespace thing?
David McDavidson
DId you add your wrapWidget files (header and cpp) to .pro file? I just compiled the similar code (although I didn't used separate class for the wrapping widget, I just added layout + button in main.cpp) with no problems at all.You can also try forcing qmake execution from QtCreator (should be in project right-click menu).
chalup
I opened the .pro file to check, I didn't manually add the wrapwidget files but they were there, Qt Creator probably adds them automatically when you create the files. My code compiles and runs, but the reload thing I wanted to happen doesn't work. Because of the CONFIG+=console thing, I can see the "no such slot" error. I'm not even expecting that calling the draw() slot will be enough to erase and redraw the draggable labels as I wanted it to, but its really weird that I can't make it recognize draw() as a slot.
David McDavidson
Can you send me the whole project? I'm really curious what's wrong :)
chalup
sure, I'll upload it somewhere. I'll have to do it tomorrow though, its in my work PC.
David McDavidson
Here's the filehttp://www.4shared.com/file/237492040/e9df9c13/fridgemagnets.htmlplease, take a look and tell me what's wrong
David McDavidson
Uncomment Q_OBJECT macro in dragwidget.h, run qmake, recompile. Works on my machine
chalup
Man, this is really weird, I did the same thing yesterday and it was giving errors off. It worked now... thanks a lot mate!One more thing, now that it recognized my slot(), it draws the new labels, but the previous labels are still there. How can I remove them before drawing the new labels?
David McDavidson
You need to store the created labels (for example in QList<DragLabel*> member of DragWidget) and delete all stored labels at the beginning of draw().
chalup
It's working now, thanks!
David McDavidson
+1  A: 

I noticed that you opened file this way:

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

Note that the file name starts with ":", and it means that the file will be read from your qrc resource package instead of your local disk. So if you made the change on words.txt, it will be read by code only when you compiled qrc file next time. So you must have understood how to fix it, right? Good Luck:)

Mason Chang
The file is being read, I changed it before running the program again and I could see that the labels were different. The problem is with redrawing the labels while the program is running, it says there's no such slot QWidget::draw().
David McDavidson
Now that i got draw() to work, i did have to change the file name. I changed it to "../words.txt" and now it reads the correct file. Reading a bit about the qrc file, seems like the resources get 'compiled-in' on the final executable, but that isn't necessarily good for frequently modified files i guess
David McDavidson