Results 1 to 14 of 14

Thread: Reload widget contents

  1. #1
    Join Date
    Feb 2010
    Location
    Brazil
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Reload widget contents

    Hello.
    I am having trouble finding a way to update a widget. I'm modifying the fridge magnets example that comes with the Qt SDK.
    Basically what I want to do is to be able to update the DragWidget contents by pressing a button. By update, I mean redrawing the draggable labels to reflect changes in the text file that it reads in order to draw the labels. For instance, I want to change a word in the text file, and after i click a button, i want the labels to be redrawn based on the changes in the text file.
    In order to do that, what I did was create a new class that would contain both the DragWidget object and the button. I called it wrapwidget, and here's its definition and implementation:

    Qt Code:
    1. class wrapWidget: public QWidget
    2. {
    3. Q_OBJECT
    4. public:
    5. wrapWidget();
    6.  
    7. };
    8.  
    9. wrapWidget::wrapWidget()
    10. {
    11. QGridLayout *gridlayout= new QGridLayout();
    12. DragWidget *w = new DragWidget();
    13. QPushButton *b = new QPushButton("refresh");
    14. gridlayout->addWidget(w,0,0);
    15. gridlayout->addWidget(b,1,0);
    16. setLayout(gridlayout);
    17.  
    18. connect(b,SIGNAL(clicked()),w,SLOT(draw()));
    19. }
    To copy to clipboard, switch view to plain text mode 

    Here's the draw() slot definition:

    Qt Code:
    1. void DragWidget::draw(){
    2. QFile dictionaryFile(":/dictionary/words.txt");
    3. dictionaryFile.open(QFile::ReadOnly);
    4. QTextStream inputStream(&dictionaryFile);
    5.  
    6. int x = 5;
    7. int y = 5;
    8.  
    9. while (!inputStream.atEnd()) {
    10. QString word;
    11. inputStream >> word;
    12. if (!word.isEmpty()) {
    13. DragLabel *wordLabel = new DragLabel(word, this);
    14. wordLabel->move(x, y);
    15. wordLabel->show();
    16. wordLabel->setAttribute(Qt::WA_DeleteOnClose);
    17. x += wordLabel->width() + 2;
    18. if (x >= 245) {
    19. x = 5;
    20. y += wordLabel->height() + 2;
    21. }
    22. }
    23. }
    24. }
    To copy to clipboard, switch view to plain text mode 

    That code was originally in the DragWidget constructor, I moved it out to the draw() method. I tried to set draw() as a slot, and call it by connecting it with the button's clicked() signal. It says there's no such slot though. What am I doing wrong?

    Any tips on how I should be doing that?
    Last edited by tiredtyrant; 8th March 2010 at 20:13. Reason: fixing code

  2. #2
    Join Date
    Feb 2008
    Posts
    491
    Thanks
    12
    Thanked 142 Times in 135 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Reload widget contents

    Did you possibly forget Q_OBJECT in your DragWidget header file?

  3. #3
    Join Date
    Oct 2006
    Location
    New Delhi, India
    Posts
    2,467
    Thanks
    8
    Thanked 334 Times in 317 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Reload widget contents

    Can you show the declaration for class DragWidget ?
    Probably you didnt add slots: to draw()

  4. #4
    Join Date
    Feb 2010
    Location
    Brazil
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Reload widget contents

    @norobro

    Well, apart from moving the label drawing code out of the constructor into the draw() slot, I haven't modified anything in the DragWidget class. In its original form, there's no Q_OBJECT macro in DragWidget declaration, and it compiles and runs as expected. But adding the macro to the DragWidget class, like this:

    Qt Code:
    1. class DragWidget : public QWidget
    2. {
    3. Q_OBJECT
    4. public:
    5. DragWidget(QWidget *parent = 0);
    6.  
    7. public slots:
    8. void draw();
    9.  
    10. protected:
    11. void dragEnterEvent(QDragEnterEvent *event);
    12. void dragMoveEvent(QDragMoveEvent *event);
    13. void dropEvent(QDropEvent *event);
    14. void mousePressEvent(QMouseEvent *event);
    15. void paintEvent(QPaintEvent *event);
    16. };
    To copy to clipboard, switch view to plain text mode 

    gave off this error:

    collect2: ld returned 1 exit status

    @aamer4yu

    But I did, look at the class declaration, its there.
    Last edited by tiredtyrant; 9th March 2010 at 12:34. Reason: fixing code tags

  5. #5
    Join Date
    Oct 2006
    Location
    New Delhi, India
    Posts
    2,467
    Thanks
    8
    Thanked 334 Times in 317 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Reload widget contents

    Did you recompile ?
    run qmake again

  6. #6
    Join Date
    Feb 2010
    Location
    Brazil
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Reload widget contents

    I did recompile, the 'public slots:' declaration was there all the time, I didn't add it just now.
    I ran qmake through Qt Creator, but the same error comes up. This is really weird, I've no idea what I'm doing wrong.

  7. #7
    Join Date
    Feb 2010
    Location
    Brazil
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Reload widget contents

    here's the project if anyone's interested in checking out what's the problem

    http://www.4shared.com/account/file/...gemagnets.html

  8. #8
    Join Date
    Feb 2010
    Location
    Brazil
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Reload widget contents

    Okay, I don't know what manner of esoteric power was holding my computer back, but I added the Q_OBJECT macro to the DragWidget class and this time running qmake and running it again worked fine. Really weird.

    My next step was storing the created labels in a QList and delete them before calling draw(). Seems to be working now. Here's the code to my modified DragWidget class:

    Qt Code:
    1. class DragWidget : public QWidget
    2. {
    3. Q_OBJECT
    4. public:
    5. DragWidget(QWidget *parent = 0);
    6.  
    7. public slots:
    8. void draw();
    9. void store();
    10. void refreshWidget();
    11.  
    12. protected:
    13. void dragEnterEvent(QDragEnterEvent *event);
    14. void dragMoveEvent(QDragMoveEvent *event);
    15. void dropEvent(QDropEvent *event);
    16. void mousePressEvent(QMouseEvent *event);
    17. void paintEvent(QPaintEvent *event);
    18.  
    19. private:
    20. QList<DragLabel*> labels;
    21. };
    To copy to clipboard, switch view to plain text mode 

    and the implementation:

    Qt Code:
    1. DragWidget::DragWidget(QWidget *parent)
    2. : QWidget(parent)
    3. {
    4. store();
    5. draw();
    6. QPalette newPalette = palette();
    7. newPalette.setColor(QPalette::Window, Qt::white);
    8. setPalette(newPalette);
    9.  
    10. setMinimumSize(400, 100);//qMax(200, y));
    11. setWindowTitle(tr("Fridge Magnets"));
    12. setAcceptDrops(true);
    13. }
    14.  
    15. void DragWidget::draw(){
    16. int x = 5;
    17. int y = 5;
    18. foreach(DragLabel* label, labels){
    19. label->move(x,y);
    20. label->show();
    21. label->setAttribute(Qt::WA_DeleteOnClose);
    22. x += label->width() + 2;
    23. if (x >= 245) {
    24. x = 5;
    25. y += label->height() + 2;
    26. }
    27. }
    28. }
    29.  
    30. void DragWidget::refreshWidget(){
    31. store();
    32. draw();
    33. }
    34.  
    35.  
    36. void DragWidget::store(){
    37. foreach(DragLabel* label, labels){
    38. label->deleteLater();
    39. }
    40. QFile dictionaryFile("../words.txt");
    41. dictionaryFile.open(QFile::ReadOnly);
    42. QTextStream inputStream(&dictionaryFile);
    43.  
    44. labels.clear();
    45.  
    46. while (!inputStream.atEnd()) {
    47. QString word;
    48. inputStream >> word;
    49. if (!word.isEmpty()) {
    50. DragLabel *wordLabel = new DragLabel(word, this);
    51. labels.append(wordLabel);
    52. }
    53. }
    54. }
    To copy to clipboard, switch view to plain text mode 

    and the connect statement now calls refreshWidget() as a slot instead of draw(). It works fine now if you don't drag any labels before clicking the button. If i drag a label out of place and click the button, the program crashes. Any idea why that happens?

  9. #9
    Join Date
    Feb 2008
    Posts
    491
    Thanks
    12
    Thanked 142 Times in 135 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Reload widget contents

    Glad that you got it running. I was typing the following (slow typist) while you posted. I'll take a look at your next problem.

    You have a stray comma in the wrapwidget.h that you uploaded:
    Qt Code:
    1. #define WRAPWIDGET_H,
    To copy to clipboard, switch view to plain text mode 
    I removed the comma, uncommented Q_Object in dragwidget.h, reran qmake and it compiled.

  10. #10
    Join Date
    Feb 2010
    Location
    Brazil
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Reload widget contents

    Here's the project, the button works but dragging a label before clicking the button crashes the program

    http://www.4shared.com/file/23766778...magnets_2.html

    I think it's because of the drop, but I'm not really sure what to do to fix this behaviour. I tried to append the new label created by the drop to the QList, but that didn't solve the problem.

  11. #11
    Join Date
    Feb 2008
    Posts
    491
    Thanks
    12
    Thanked 142 Times in 135 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Reload widget contents

    When you drag an item a new QLabel is created in DragWidget::dropEvent. That seems to invalidate your QList "labels" resulting in a segfault.

    Try this:
    Qt Code:
    1. void DragWidget::store(){
    2. QList <QObject *> newList = this->children();
    3. foreach(QObject * label, newList) label->deleteLater();
    4. // foreach(DragLabel* label, labels){
    5. // label->deleteLater();
    6. // }
    To copy to clipboard, switch view to plain text mode 

  12. The following user says thank you to norobro for this useful post:

    tiredtyrant (10th March 2010)

  13. #12
    Join Date
    Feb 2010
    Location
    Brazil
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Reload widget contents

    It worked! I was so sure the error was on dropEvent()!
    Could you elaborate more on why the segfault was happening? Also, you declared a QObject* list, could it have been a DragWidget* list instead?

    How could I go about retrieving a particular set of objects instead of all the children?
    Last edited by tiredtyrant; 9th March 2010 at 21:01.

  14. #13
    Join Date
    Feb 2008
    Posts
    491
    Thanks
    12
    Thanked 142 Times in 135 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Reload widget contents

    Sorry for the delay in responding. Right after my last post I lost my internet connection. Called my ISP and as usual their first reaction was to blame the customer's equipment, in this case my 7 year old modem. So I bought a new modem and they still couldn't get me connected. Had to send out a service tech and of course the problem was on their end.

    Qt Code:
    1. void DragWidget::mousePressEvent(QMouseEvent *event)
    2. {
    3. . . .
    4. if (drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::CopyAction) == Qt::MoveAction)
    5. child->close();
    6. . . .
    To copy to clipboard, switch view to plain text mode 
    When you move a "magnet" a new DragLabel is created and the above statement deletes the old one which leaves you with a dangling pointer in your list "labels". This results in a segfault when you iterate through the list because you are trying to delete a memory location that has already been deallocated. Try commenting out "child->close()" and use your foreach statement in DragWidget::store().

    I tried using a DragLabel list first and got compile errors thus the QObject * list. You make a good point- you might not want to delete all of an object's children. I did find this in the docs so in this case the following should find all of the DragLabel children:
    Qt Code:
    1. QList<DragLabel *> newList = this->findChildren<DragLabel *>();
    To copy to clipboard, switch view to plain text mode 
    Hope this makes sense.
    Last edited by norobro; 10th March 2010 at 19:34. Reason: typo

  15. The following user says thank you to norobro for this useful post:

    tiredtyrant (10th March 2010)

  16. #14
    Join Date
    Feb 2010
    Location
    Brazil
    Posts
    23
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Reload widget contents

    Sorry to hear you had trouble with your ISP, I'm all too familiar with your situation. Nice to have you back on the internets

    I see why the application was crashing now. Thanks a bunch for your help!

Similar Threads

  1. Replies: 2
    Last Post: 11th February 2010, 08:45
  2. Reload a Qt Plugin
    By bunjee in forum Qt Programming
    Replies: 3
    Last Post: 30th December 2009, 16:36
  3. Reload a QTableWidget
    By SailinShoes in forum Qt Programming
    Replies: 1
    Last Post: 18th March 2008, 12:40
  4. Draw contents of widget in another widget
    By gustavosbarreto in forum Qt Programming
    Replies: 1
    Last Post: 6th August 2007, 15:43
  5. How to reload widget plugins?
    By victorng in forum Qt Programming
    Replies: 2
    Last Post: 2nd March 2006, 00:27

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.