Results 1 to 19 of 19

Thread: Subclassing a QWidget

  1. #1
    Join Date
    Jan 2013
    Posts
    43
    Thanks
    27
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Subclassing a QWidget

    Hi
    I'm trying to understand how to subclass a QWidget.
    I want to create a widget with 2 buttons allong with some drawing elements.
    How does it work in terms of layout for the subclassed widget.
    I ask because aparently the first layout that i use becomes the main layout!
    I attach small small example: layoutwidget.zip

  2. #2
    Join Date
    May 2008
    Location
    Tripoli Libya
    Posts
    70
    Thanks
    10
    Thanked 8 Times in 8 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Subclassing a QWidget

    Qt Code:
    1. #ifndef DESENHO_H
    2. #define DESENHO_H
    3.  
    4. #include <QWidget>
    5. #include <QVBoxLayout>
    6. #include <QSpacerItem>
    7. #include <QPushButton>
    8.  
    9.  
    10. class Widget : public QWidget
    11. {
    12. Q_OBJECT
    13.  
    14. public:
    15. Widget(QWidget *parent = 0);
    16. ~Widget();
    17. void draw(QPainter *painter);
    18.  
    19. protected:
    20. void paintEvent(QPaintEvent *event);
    21.  
    22. private:
    23. QPushButton *btn1, *btn2;
    24. QSpacerItem *spacer;
    25. QVBoxLayout *verticalLayout;
    26. QHBoxLayout *horizontalLayout;
    27. };
    28.  
    29. #endif
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. #include <QtGui>
    2.  
    3. #include "widget.h"
    4.  
    5. Widget::Widget(QWidget *parent)
    6. : QWidget(parent)
    7. {
    8. btn1 = new QPushButton(this);
    9. btn2 = new QPushButton(this);
    10. spacer = new QSpacerItem(0,100);
    11. verticalLayout = new QVBoxLayout(this);
    12. horizontalLayout=new QHBoxLayout;
    13. verticalLayout->addStretch(1);
    14. // horizontalLayout->addItem(spacer);
    15. horizontalLayout->addWidget(btn1);
    16. horizontalLayout->addWidget(btn2);
    17. verticalLayout->addLayout(horizontalLayout);
    18. this->setLayout(verticalLayout);
    19. //verticalLayout->addItem(spacer);
    20. //verticalLayout->addWidget(btn1);
    21. //verticalLayout->addWidget(btn2);
    22. }
    23.  
    24. Widget::~Widget()
    25. {
    26.  
    27. }
    28.  
    29. void Widget::paintEvent(QPaintEvent * /* event */)
    30. {
    31. QPainter painter(this);
    32. painter.setRenderHint(QPainter::Antialiasing, true);
    33.  
    34.  
    35. draw(&painter);
    36. }
    37.  
    38. void Widget::draw(QPainter *painter)
    39. {
    40.  
    41.  
    42. }
    To copy to clipboard, switch view to plain text mode 

  3. The following user says thank you to alrawab for this useful post:

    aguleo (18th February 2013)

  4. #3
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Subclassing a QWidget

    You need to re-implement paintEvent of "some drawing elements" and let the "main layout" take care the laying out pushbuttons and "drawing elements".
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  5. The following user says thank you to Santosh Reddy for this useful post:

    aguleo (18th February 2013)

  6. #4
    Join Date
    May 2010
    Location
    Romania
    Posts
    1,021
    Thanks
    62
    Thanked 260 Times in 246 Posts
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: Subclassing a QWidget

    You set create a "main" layout and within that you can add another layout if you want to, tell us more about what are you trying to achieve and also take a look at documentation

    Also, you can use forward declaration in headers for all classes that have only pointers or references or are passed as parameter to member function (this makes the compilation faster for bigger projects):
    Qt Code:
    1. #ifndef DESENHO_H
    2. #define DESENHO_H
    3.  
    4. #include <QWidget> //you need this header included because you derive from QWidget
    5. /* you don't need these headers included in your header
    6. -- include those in the .cpp file
    7. #include <QVBoxLayout>
    8. #include <QSpacerItem>
    9. #include <QPushButton>
    10. */
    11. //here you only use forward declaration:
    12. //and so on
    13. class Widget : public QWidget
    14. {
    15. Q_OBJECT
    16.  
    17. public:
    18. Widget(QWidget *parent = 0);
    19. ~Widget();
    20. void draw(QPainter *painter);
    21.  
    22. protected:
    23. void paintEvent(QPaintEvent *event);
    24.  
    25. private:
    26. QPushButton *btn1, *btn2;
    27. QSpacerItem *spacer;
    28. QVBoxLayout *verticalLayout;
    29. };
    30.  
    31. #endif
    To copy to clipboard, switch view to plain text mode 

  7. The following user says thank you to Zlatomir for this useful post:

    aguleo (18th February 2013)

  8. #5
    Join Date
    Jan 2013
    Posts
    43
    Thanks
    27
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Subclassing a QWidget

    There was something missing above also.
    I was passing this into horizontalLayout and getting a "QLayout: Attempting to add QLayout "" to Widget "", which already has a layout
    ".

    Here is the new version with the contributions above.
    widget.h
    Qt Code:
    1. #ifndef WIDGET_H
    2. #define WIDGET_H
    3.  
    4. #include <QWidget>
    5.  
    6.  
    7. class Widget : public QWidget
    8. {
    9. Q_OBJECT
    10.  
    11. public:
    12. Widget(QWidget *parent = 0);
    13. ~Widget();
    14. void draw(QPainter *painter);
    15.  
    16. protected:
    17. void paintEvent(QPaintEvent *event);
    18.  
    19. private:
    20. QPushButton *btn1, *btn2;
    21. QVBoxLayout *verticalLayout;
    22. QHBoxLayout *horizontalLayout;
    23.  
    24. };
    25.  
    26. #endif
    To copy to clipboard, switch view to plain text mode 

    widget.cpp
    Qt Code:
    1. #include <QtGui>
    2.  
    3. #include "widget.h"
    4.  
    5. Widget::Widget(QWidget *parent)
    6. : QWidget(parent)
    7. {
    8. btn1 = new QPushButton(this);
    9. btn2 = new QPushButton(this);
    10. verticalLayout = new QVBoxLayout(this);
    11. horizontalLayout = new QHBoxLayout();
    12. verticalLayout->addStretch(1);
    13. horizontalLayout->addWidget(btn1);
    14. horizontalLayout->addWidget(btn2);
    15. verticalLayout->addLayout(horizontalLayout);
    16. this->setLayout(verticalLayout);
    17. }
    18.  
    19. Widget::~Widget()
    20. {
    21.  
    22. }
    23.  
    24. void Widget::paintEvent(QPaintEvent * /* event */)
    25. {
    26. QPainter painter(this);
    27. painter.setRenderHint(QPainter::Antialiasing, true);
    28. //...
    29.  
    30. draw(&painter);
    31. }
    32.  
    33. void Widget::draw(QPainter *painter)
    34. {
    35.  
    36.  
    37. }
    To copy to clipboard, switch view to plain text mode 


    Added after 11 minutes:


    By the way, showld i be using this line?
    Qt Code:
    1. #include <QtGui>
    To copy to clipboard, switch view to plain text mode 
    Last edited by aguleo; 18th February 2013 at 15:02.

  9. #6
    Join Date
    May 2010
    Location
    Romania
    Posts
    1,021
    Thanks
    62
    Thanked 260 Times in 246 Posts
    Qt products
    Qt5
    Platforms
    MacOS X Unix/X11 Windows Android

    Default Re: Subclassing a QWidget

    Those two lines are basically doing the same thing:
    Qt Code:
    1. verticalLayout = new QVBoxLayout(this);
    2.  
    3. //this second line isn't necessary the layout is already set (you passed this pointer to the QVBoxLayout's constructor)
    4. //this->setLayout(verticalLayout);
    To copy to clipboard, switch view to plain text mode 

    As for: #include <QtGui>, i recommend that you include as few headers as possible (and even use the forward declaration wherever possible) so this is not a good solution and on top of slow compilation some people complained that code completion in Creator is slow when including all headers for a module.

    Also your issue is only with the layout system or as Santosh Reddy guessed you have issues with drawing (paintEvent) too?

  10. The following user says thank you to Zlatomir for this useful post:

    aguleo (18th February 2013)

  11. #7
    Join Date
    Jan 2013
    Posts
    43
    Thanks
    27
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Subclassing a QWidget

    To be honest ...
    You need to re-implement paintEvent of "some drawing elements" and let the "main layout" take care the laying out pushbuttons and "drawing elements".
    ... i'm not shore what he was talkin about!
    Drawing is ok ... the problem arrised when i added extra widgets. Then i had problems placing them and the layout question emerged.

  12. #8
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Subclassing a QWidget

    I want to create a widget with 2 buttons allong with some drawing elements.
    Show where and how are you drawing "some drawing elements"
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  13. #9
    Join Date
    Jan 2013
    Posts
    43
    Thanks
    27
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Subclassing a QWidget

    Something like this ... a blue box arround the widget.
    Qt Code:
    1. #include <QtGui>
    2.  
    3. #include "widget.h"
    4.  
    5. Widget::Widget(QWidget *parent)
    6. : QWidget(parent)
    7. {
    8. btn1 = new QPushButton(this);
    9. btn2 = new QPushButton(this);
    10. verticalLayout = new QVBoxLayout(this);
    11. horizontalLayout = new QHBoxLayout();
    12. verticalLayout->addStretch(1);
    13. horizontalLayout->addWidget(btn1);
    14. horizontalLayout->addWidget(btn2);
    15. verticalLayout->addLayout(horizontalLayout);
    16. this->setFixedSize(200, 100);
    17. this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    18. }
    19.  
    20. Widget::~Widget()
    21. {
    22.  
    23. }
    24.  
    25. void Widget::paintEvent(QPaintEvent * /* event */)
    26. {
    27. QPainter painter(this);
    28. painter.setRenderHint(QPainter::Antialiasing, true);
    29. painter.setPen(Qt::blue);
    30. draw(&painter);
    31. }
    32.  
    33. void Widget::draw(QPainter *painter)
    34. {
    35. QPointF points[4] = {
    36. QPointF(0.0, 0.0),
    37. QPointF(200.0, 0.0),
    38. QPointF(200.0, 100.0),
    39. QPointF(0.0, 100.0)
    40. };
    41. painter->drawConvexPolygon(points, 4);
    42.  
    43. }
    To copy to clipboard, switch view to plain text mode 

  14. #10
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Subclassing a QWidget

    Don't implement the paint for the widget for which the layout managers are set. You need to paint the widget with no layout on it.
    Qt Code:
    1. #include <QWidget>
    2. #include <QPainter>
    3. #include <QPaintEvent>
    4. #include <QPushButton>
    5. #include <QGridLayout>
    6. #include <QApplication>
    7.  
    8. class DrawingWidget : public QWidget
    9. {
    10. public:
    11. DrawingWidget(QWidget *parent = 0) : QWidget(parent) {}
    12.  
    13. protected:
    14. void paintEvent(QPaintEvent *event) // <<<<<<<<<<<<< Do drawing here on this widget (which does not has layout)
    15. {
    16. QPainter painter(this);
    17. painter.setRenderHint(QPainter::Antialiasing, true);
    18. painter.setPen(Qt::blue);
    19.  
    20. QSize size = event->rect().size(); // <<<<<<<<<< always do painting in side the event->rect()
    21.  
    22. QPointF points[4] = {
    23. QPointF(0.0, 0.0),
    24. QPointF(size.width(), 0.0),
    25. QPointF(size.width(), size.height()),
    26. QPointF(0.0, size.height())
    27. };
    28. painter.drawConvexPolygon(points, 4);
    29. }
    30. };
    31.  
    32. class Widget : public QWidget
    33. {
    34. Q_OBJECT
    35.  
    36. public:
    37. Widget(QWidget *parent = 0)
    38. : QWidget(parent)
    39. , layout(new QGridLayout(this)) // This will be your main layout, you could change this to a combination on VBox/Hbox, I used grid for its flexibility to act as both
    40. {
    41. layout->addWidget(new DrawingWidget, 0, 0, 1, 2); // <<<<<<<<<<<<< Drawing Widget
    42. layout->addWidget(new QPushButton("< Prev"), 1, 0, 1, 1);
    43. layout->addWidget(new QPushButton("Next >"), 1, 1, 1, 1);
    44. }
    45.  
    46. private:
    47. QGridLayout *layout;
    48. };
    49.  
    50. int main(int argc, char *argv[])
    51. {
    52. QApplication app(argc, argv);
    53. Widget w;
    54.  
    55. w.show();
    56. return app.exec();
    57. }
    58.  
    59. #include "main.moc"
    To copy to clipboard, switch view to plain text mode 
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

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

    aguleo (19th February 2013)

  16. #11
    Join Date
    Jan 2013
    Posts
    43
    Thanks
    27
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Subclassing a QWidget

    You separated drawing form the rest of the widgets and the way thay are set ia a layout. Correct?

    But why do it like that?
    Apart from a good coding example, setting hierarchical relations between classes, i can not clearly see the advantages.
    Please point them to help me understand the experts

  17. #12
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Subclassing a QWidget

    Please refer to my earlier statement
    Don't implement the paint for the widget for which the layout managers are set. You need to paint the widget with no layout on it.
    If you implement the painting for a widget and also use layout managers on it, then layout managers will over write the painting you do

  18. #13
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Subclassing a QWidget

    If you want to paint "below" the widgets, then call the super class' paintEvent after your call to draw().

    Cheers,
    _

  19. The following user says thank you to anda_skoa for this useful post:

    aguleo (19th February 2013)

  20. #14
    Join Date
    Jan 2013
    Posts
    43
    Thanks
    27
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Wink Re: Subclassing a QWidget

    New version:
    • keep the layouts;
    • don't separate drawing from other widgets;
    • painting "below" the widgets


    widget.h
    Qt Code:
    1. #ifndef WIDGET_H
    2. #define WIDGET_H
    3.  
    4. #include <QWidget>
    5.  
    6. class QSize;
    7.  
    8. class Widget : public QWidget
    9. {
    10. Q_OBJECT
    11.  
    12. public:
    13. Widget(QWidget *parent = 0);
    14. ~Widget();
    15. void draw(QPainter *painter, QPaintEvent *event);
    16.  
    17. protected:
    18. void paintEvent(QPaintEvent *event);
    19.  
    20. private:
    21. QPushButton *btn1, *btn2;
    22. QVBoxLayout *verticalLayout;
    23. QHBoxLayout *horizontalLayout;
    24.  
    25. };
    26.  
    27. #endif
    To copy to clipboard, switch view to plain text mode 

    widget.cpp
    Qt Code:
    1. #include <QtGui>
    2.  
    3. #include "widget.h"
    4.  
    5. Widget::Widget(QWidget *parent)
    6. : QWidget(parent)
    7. {
    8. btn1 = new QPushButton(this);
    9. btn2 = new QPushButton(this);
    10. verticalLayout = new QVBoxLayout(this);
    11. horizontalLayout = new QHBoxLayout();
    12. verticalLayout->addStretch(1);
    13. horizontalLayout->addWidget(btn1);
    14. horizontalLayout->addWidget(btn2);
    15. verticalLayout->addLayout(horizontalLayout);
    16. }
    17.  
    18. Widget::~Widget()
    19. {
    20.  
    21. }
    22.  
    23. void Widget::paintEvent(QPaintEvent *event)
    24. {
    25. QPainter painter(this);
    26. painter.setRenderHint(QPainter::Antialiasing, true);
    27. painter.setPen(Qt::blue);
    28. draw(&painter, event);
    29. }
    30.  
    31. void Widget::draw(QPainter *painter, QPaintEvent *event)
    32. {
    33.  
    34. QSize size = event->rect().size();
    35. QPointF points[4] = {
    36. QPointF(0.0, 0.0),
    37. QPointF(size.width(), 0.0),
    38. QPointF(size.width(), size.height()),
    39. QPointF(0.0, size.height())
    40. };
    41. painter->drawConvexPolygon(points, 4);
    42. painter->drawLine(0.0, 0.0, size.width(), size.height());
    43. painter->drawLine(size.width(), 0.0, 0.0, size.height());
    44. }
    To copy to clipboard, switch view to plain text mode 

    Hope i get an ok now

  21. #15
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Subclassing a QWidget

    Hope i get an ok now
    This might seem ok for you, for now, but I am sure this not the final thing you wanted. You will for sure later add more drawing in the paint function, then how would you avoid drawing on the QPushButtons. There are ways to avoid it, but the question is do you what to do so?
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  22. #16
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Subclassing a QWidget

    Quote Originally Posted by aguleo View Post
    New version:
    • keep the layouts;
    • don't separate drawing from other widgets;
    • painting "below" the widgets
    Are you sure about the last point? I don't see a call to QWidget::paintEvent() inside Widget::paintEvent()

    Cheers,
    _
    Last edited by wysota; 20th February 2013 at 19:04. Reason: reformatted to look better

  23. #17
    Join Date
    Jan 2013
    Posts
    43
    Thanks
    27
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Subclassing a QWidget

    I think this is working like planed.
    Perhaps we are having a communication problem with the word "below"
    Please take a look at the attachment: widgetQt5.tar.bz2

  24. #18
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Subclassing a QWidget

    So it means that you wanted the QPushButtons to be over the custom painting (done in the parent widget's paint event).

    So all set, you have what you wanted
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  25. #19
    Join Date
    Jan 2013
    Posts
    43
    Thanks
    27
    Thanked 6 Times in 5 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Subclassing a QWidget

    I was exploring Santosh Reddy's example and a question came to my mind!
    How will the Widget and the DrawingWidget communicate?

    Imagine that buttonx controls the position of an object in the DrawingWidget. Showld i go for the setter/getter approach or start emitting custom signals?

Similar Threads

  1. Replies: 0
    Last Post: 28th October 2011, 18:46
  2. Replies: 1
    Last Post: 16th September 2010, 15:57
  3. Subclassing QWidget and QPushButton
    By ber0y in forum Newbie
    Replies: 7
    Last Post: 24th July 2009, 10:25
  4. subclassing QWidget
    By BeS in forum Qt Programming
    Replies: 2
    Last Post: 23rd February 2009, 20:38
  5. Replies: 1
    Last Post: 2nd May 2006, 21:11

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.