Results 1 to 10 of 10

Thread: Problem repainting a subclassed QCalendarWidget

  1. #1
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Problem repainting a subclassed QCalendarWidget

    I've sublcassed a QCalendarWidget, and reimplemented it's paintCell routine to display text on certain days. So far so good right? Now when the text changes i should call the "update()" method to repaint the widget, right?

    Well that doesn't work 100% of the time. I've even tried calling the "repaint()" method as well. Same results. Occasionally it will respond and repaint the correct changes, but more often then not I need to click on the date's cell to have it redraw.

    I've noticed that Qt uses a custom model/view in the private implementation of QCalendarWidget, but that's untouchable in my subclass.

    What I'm guessing is that QCalendarWidget was never meant for this level of interactivity?? I hope not, because I really don't feel like coding my own version of the calendar widget.... sigh.

    [using Qt/X11 4.3.1]

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problem repainting a subclassed QCalendarWidget

    But where and why are you calling repaint/update? If you reimplement paintCell(), Qt should call your implemention itself - you needn't do anything more. For instance to make a calendar widget that paints sundays on a red background all you'd have to do is:

    Qt Code:
    1. class RedSundaysCalendarWidget : public QCalendarWidget{
    2. public:
    3. RedSundaysCalendarWidget(QWidget *parent=0) : QCalendarWidget(parent){}
    4. protected:
    5. void paintCell ( QPainter * painter, const QRect & rect, const QDate & date ) const{
    6. if(date.dayOfWeek()==Qt::Sunday){
    7. painter->fillRect(rect, Qt::red);
    8. painter->save();
    9. painter->setPen(Qt::green);
    10. painter->drawText(rect, Qt::AlignCenter, QString::number(date.day()));
    11. painter->restore();
    12. } else QCalendarWidget::paintCell(painter, rect, date);
    13. }
    14. };
    To copy to clipboard, switch view to plain text mode 

  3. #3
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Problem repainting a subclassed QCalendarWidget

    But i'm doing a bit more then that. My class look something like this:

    Qt Code:
    1. class EventCalendarWidget : public QCalendarWidget
    2. {
    3. Q_OBJECT
    4. public:
    5. EventCalendarWidget(QWidget *parent = 0) : QCalendarWidget(parent) {}
    6. ~EventCalendarWidget() {}
    7.  
    8. void addEvent(QDate date, QString event) {
    9. _events.insert(date, event);
    10. update(); //this doesn't always work
    11. }
    12.  
    13. protected:
    14. void paintCell(QPainter *painter, const QRect &rect, const QDate &date) const {
    15. if (_events.contains(date)) {
    16. QList<QString> events = _events.values(date);
    17. QRect r = rect;
    18. QRect br;
    19. painter->save();
    20. foreach(QString event, events) {
    21. r.adjust(0, br.height(), 0, 0);
    22. painter->drawText(r, Qt::TextSingleLine, event, &br);
    23. }
    24. painter->restore();
    25. } else {
    26. QCalendarWidget::paintCell(painter, rect, date);
    27. }
    28. }
    29.  
    30. private:
    31. QMultiMap<QDate, QString> _events;
    32.  
    33. };
    To copy to clipboard, switch view to plain text mode 
    Last edited by darkadept; 28th September 2007 at 20:27. Reason: minor bug in my code

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problem repainting a subclassed QCalendarWidget

    Your code seems fine. If you don't get the effect you want, that's probably because you might be drawing outside rect. And your loop seems incorrect. I'd implement it like so:
    Qt Code:
    1. int y=rect.top();
    2. foreach(QString event, events){
    3. QRect br;
    4. painter->drawText(QRect(rect.left(), y, rect.width(), rect.height()-y), ..., &br);
    5. y+=br.height()+1;
    6. }
    To copy to clipboard, switch view to plain text mode 

  5. #5
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Problem repainting a subclassed QCalendarWidget

    The drawing code loop actually works, but yes your way works equally as well, if not better. =) But the problem here is with the call to update(), which IS what the qt docs say to use. repaint() has the same problem as update().

    I've been studying the Qt source for QCalendarWidget and it seems that it doesn't reimplement it's paintEvent() method from QWidget. Instead it uses a custom view and adds that to QCalendarWidget in a layout. See the QCalendarWidget constructor in the Qt sources.

    Looking at QCalendarWidget::setDateTextFormat(....) it seems that it does something else to initiate redrawing.
    Qt Code:
    1. void QCalendarWidget::setDateTextFormat(const QDate &date, const QTextCharFormat &format)
    2. {
    3. d->m_model->m_dateFormats[date] = format;
    4. d->m_view->viewport()->update();
    5. d->m_view->updateGeometry();
    6. }
    To copy to clipboard, switch view to plain text mode 
    But I don't have access to the private 'd' object and therefore don't have access to update the custom view's viewport.

    Hmm, looking at this function:
    Qt Code:
    1. bool QCalendarWidget::event(QEvent *event)
    2. {
    3. switch (event->type()) {
    4. case QEvent::LocaleChange:
    5. d->cachedSizeHint = QSize();
    6. d->m_navigator->setLocale(locale());
    7. d->updateMonthMenuNames();
    8. d->updateNavigationBar();
    9. d->m_view->updateGeometry();
    10. break;
    11. case QEvent::FontChange:
    12. case QEvent::ApplicationFontChange:
    13. d->cachedSizeHint = QSize();
    14. d->m_view->updateGeometry();
    15. break;
    16. case QEvent::StyleChange:
    17. d->cachedSizeHint = QSize();
    18. d->m_view->updateGeometry();
    19. default:
    20. break;
    21. }
    22. return QWidget::event(event);
    23. }
    To copy to clipboard, switch view to plain text mode 
    I might be able to fake a font or style change to get it to call it's private updateGeometry() method.

    So really (if I understand my Qt properly) QCalendarWidget is just a simple container widget that holds a private custom view and calling QCalendarWidget::update() does nothing to update that custom view.

  6. #6
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Problem repainting a subclassed QCalendarWidget

    darn... faking a font change event doesn't do it either.

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problem repainting a subclassed QCalendarWidget

    Yes, you understand correctly

    I think you should file a bug (or suggestion) report to Trolltech. There should be some invalidate() method available to invalidate the drawing.

    But as a temporary solution something like this should work:
    Qt Code:
    1. void ...::addEvent(const QDate &date, const QString &event){
    2. _events.insert(date, event);
    3. QAbstractItemView *view = qFindChild<QAbstractItemView*>(this);
    4. if(view){
    5. view->viewport()->update();
    6. } else update(); // fallback
    7. }
    To copy to clipboard, switch view to plain text mode 
    If this doesn't work, you'll have to hack into accessing protected methods of the view... but try the above code first.


    BTW. Nice idea with the event calendar widget.

  8. #8
    Join Date
    May 2006
    Posts
    70
    Thanks
    12
    Thanked 4 Times in 2 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Problem repainting a subclassed QCalendarWidget

    Works so beautifully!!!! Thanks a ton for this.

    Of course I can see this is hardly the optimal solution for this problem.

    I've sent a message to the qt-interest mailing list documenting this problem as well.

    btw, where do I send bug reports to?

  9. #9
    Join Date
    Sep 2007
    Location
    Vancouver B.C., Canada
    Posts
    4
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Problem repainting a subclassed QCalendarWidget

    Quote Originally Posted by darkadept View Post
    btw, where do I send bug reports to?

    You can file a bug report here: http://trolltech.com/developer/bugreport-form

  10. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Problem repainting a subclassed QCalendarWidget

    Quote Originally Posted by darkadept View Post
    Works so beautifully!!!! Thanks a ton for this.
    Great.

    Of course I can see this is hardly the optimal solution for this problem.
    Actually it is kind of optimal (ok... suboptimal), only that there should be a protected method to do that.

    btw, where do I send bug reports to?
    http://www.trolltech.com/developer/task-tracker

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.