Results 1 to 12 of 12

Thread: [SOLVED] Issues with displaying rich text for a QCheckBox

  1. #1
    Join Date
    Sep 2014
    Posts
    27
    Thanks
    2
    Thanked 2 Times in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default [SOLVED] Issues with displaying rich text for a QCheckBox

    So I've been wrestling with this problem for most of the work day, and at this point I think I need some outside feedback. I've been working with Qt for a couple months now and I'm pretty well versed in C++ so I've got the basics of Qt down and have learned a few of its subtleties, but I can't find an elegant solution to my issue.

    I need to have superscript text displayed in the label of a QCheckBox. Now, your initial thought may be to just place and empty check box next to a label which can display rich text. I have seen this suggested many times in various posts about this issue, but I have two problems with this:

    1. Clicking the label does not toggle the check box.
    2. Hovering over the label does not trigger the hoverstate of the check box


    The first problem is easy enough to solve. You just need to subclass QLabel and implement mouseClickEvent and emit a clicked signal to connect to the check box's toggle slot. The second problem is somewhat tricky however, and I'm pretty stumped.

    My initial instinct was to look for a setState or some such method which would allow me to tell the QCheckBox that it is being hovered over, however no such method exists that I could find. I even tried to use QWidget.setProperty("hover", true but it had no effect. So then I thought that I could place a QCheckBox and a QLabel inside of a custom Widget container which would detect mouseover and if the mouse is over the label I would create a false event containing coordinates of the QCheckBox and pass that to the QCheckBox so it would think it is being hovered over. However you can't explicitly call mouseMoveEvent on a widget. I also tried subclassing QCheckBox and using QTextDocument in the paintEvent to draw rich text next to the checkBox after calling the base class paint event. This worked, but again the checkbox was not counting the drawn text as part of it's contents so hover state was not being triggered.

    I feel like I'm close to finding a workable solution here but I just need a push in the right direction. I don't need anyone to write any code for me, but if there's a method I'm missing or something else I could try while subclassing QCheckBox I would be very grateful to have that pointed out.

    If all else fails I will just have to stick with a clickable label next to a checkbox, but I would like to avoid that because there are many other checkboxes without the need for rich text in my application and it would be great for them all to have the same behavior.

  2. #2
    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: Issues with displaying rich text for a QCheckBox

    Quote Originally Posted by forgottenduck View Post
    So then I thought that I could place a QCheckBox and a QLabel inside of a custom Widget container which would detect mouseover and if the mouse is over the label I would create a false event containing coordinates of the QCheckBox and pass that to the QCheckBox so it would think it is being hovered over. However you can't explicitly call mouseMoveEvent on a widget.
    No, but you could call the event() method (which is the entry point for all events a widget processes) or even us QCoreApplication::sendEvent() to push an event through the normal event processing chain.

    Cheers,
    _

  3. #3
    Join Date
    Sep 2014
    Posts
    27
    Thanks
    2
    Thanked 2 Times in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Issues with displaying rich text for a QCheckBox

    or even us QCoreApplication::sendEvent() to push an event through the normal event processing chain.
    Using send event did allow me to do what I intended but nothing appears to be happening. Here's my class as of right now:

    Qt Code:
    1. CheckBoxTest::CheckBoxTest(QString text, QWidget *parent) :
    2. QWidget(parent)
    3. {
    4. this->setMouseTracking(true);
    5. label = new QLabel(text);
    6. checkBox = new QCheckBox;
    7. QHBoxLayout* layout = new QHBoxLayout;
    8. layout->addWidget(label);
    9. layout->addWidget(checkBox);
    10. this->setLayout(layout);
    11. }
    12.  
    13. void CheckBoxTest::mouseMoveEvent(QMouseEvent *event){
    14. if(label->contentsRect().contains(event->pos())){
    15. QMouseEvent* newEvent = new QMouseEvent(QEvent::MouseMove, checkBox->mapFromGlobal(checkBox->pos()), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
    16. QCoreApplication::sendEvent(checkBox, newEvent);
    17. }else{
    18. event->ignore();
    19. }
    20. }
    To copy to clipboard, switch view to plain text mode 

    Mouse events are passed on to checkBox when not within the label. When within the label the newEvent is created with a mouse position of checkBox's position and I use sendEvent to send it to checkBox which should trigger a hover state whenever the mouse is in the contents of the label. Any idea why nothing seems to be happening?

  4. #4
    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: Issues with displaying rich text for a QCheckBox

    Maybe the trigger is not a mouse event but the enter event.

    After all, "hover" only changes on enter/leave

    Cheers,
    _

  5. #5
    Join Date
    Sep 2014
    Posts
    27
    Thanks
    2
    Thanked 2 Times in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Issues with displaying rich text for a QCheckBox

    I just figured out an acceptable solution so I will explain what I have done. I made 3 classes total, one being simply a container for the custom qcheckbox and custom qlabel.

    I made an extension of QCheckBox called HoverCheckBox which reimplements the paint event and if the private bool isHover is true it will force the QStyle::State_MouseOver onto the style option. Here's the code:

    hovercheckbox.h
    Qt Code:
    1. #ifndef HOVERCHECKBOX_H
    2. #define HOVERCHECKBOX_H
    3.  
    4. #include <QCheckBox>
    5.  
    6. class HoverCheckBox : public QCheckBox
    7. {
    8. Q_OBJECT
    9. public:
    10. explicit HoverCheckBox(QWidget *parent = 0);
    11. private:
    12. virtual void paintEvent(QPaintEvent *);
    13. bool isHover;
    14. public slots:
    15. void setHover(bool state);
    16. };
    17.  
    18. #endif // HOVERCHECKBOX_H
    To copy to clipboard, switch view to plain text mode 
    hovercheckbox.cpp
    Qt Code:
    1. #include "hovercheckbox.h"
    2.  
    3. #include <QStyleOptionButton>
    4. #include <QStylePainter>
    5.  
    6. HoverCheckBox::HoverCheckBox(QWidget *parent) :
    7. QCheckBox(parent)
    8. {
    9. isHover = false;
    10. }
    11. void HoverCheckBox::paintEvent(QPaintEvent *){
    12. QStylePainter p(this);
    13. initStyleOption(&opt);
    14. if(isHover){
    15. opt.state |= QStyle::State_MouseOver;
    16. }
    17. p.drawControl(QStyle::CE_CheckBox, opt);
    18. }
    19. void HoverCheckBox::setHover(bool state){
    20. isHover = state;
    21. repaint();
    22. }
    To copy to clipboard, switch view to plain text mode 


    I also made a simple Clickable label class which emits a clicked() signal on left mouse button release.
    clickablelabel.h
    Qt Code:
    1. #ifndef CLICKABLELABEL_H
    2. #define CLICKABLELABEL_H
    3.  
    4. #include <QLabel>
    5.  
    6. class ClickableLabel : public QLabel
    7. {
    8. Q_OBJECT
    9. public:
    10. explicit ClickableLabel(QWidget *parent = 0);
    11. void mouseReleaseEvent(QMouseEvent*);
    12.  
    13. signals:
    14. void clicked();
    15. public slots:
    16.  
    17. };
    18.  
    19. #endif // CLICKABLELABEL_H
    To copy to clipboard, switch view to plain text mode 
    clickablelabel.cpp
    Qt Code:
    1. #include "clickablelabel.h"
    2.  
    3. #include <QMouseEvent>
    4. ClickableLabel::ClickableLabel(QWidget *parent) :
    5. QLabel(parent)
    6. {
    7. }
    8.  
    9. void ClickableLabel::mouseReleaseEvent(QMouseEvent *event){
    10. if(event->buttons() == Qt::LeftButton){
    11. emit clicked();
    12. }else if(event->button() == Qt::LeftButton){
    13. emit clicked();
    14. }
    15. }
    To copy to clipboard, switch view to plain text mode 


    Lastly I made a container class to wrap the two.
    richtextbox.h
    Qt Code:
    1. #ifndef RICHTEXTCHECKBOX_H
    2. #define RICHTEXTCHECKBOX_H
    3.  
    4. #include <QWidget>
    5.  
    6. class HoverCheckBox;
    7. class QCheckBox;
    8. class ClickableLabel;
    9.  
    10. class RichTextCheckBox : public QWidget
    11. {
    12. Q_OBJECT
    13. public:
    14. explicit RichTextCheckBox(QString text, QWidget *parent = 0);
    15.  
    16. private:
    17. HoverCheckBox* checkBox;
    18. ClickableLabel* label;
    19. virtual void enterEvent(QEvent*);
    20. virtual void leaveEvent(QEvent*);
    21.  
    22. signals:
    23.  
    24. public slots:
    25.  
    26. };
    27.  
    28. #endif // RICHTEXTCHECKBOX_H
    To copy to clipboard, switch view to plain text mode 
    richtextbox.cpp
    Qt Code:
    1. #include "richtextcheckbox.h"
    2. #include "hovercheckbox.h"
    3. #include "clickablelabel.h"
    4. #include <QMouseEvent>
    5. #include <QLabel>
    6. #include <QLayout>
    7.  
    8. #include <QDebug>
    9.  
    10. RichTextCheckBox::RichTextCheckBox(QString text, QWidget *parent) :
    11. QWidget(parent)
    12. {
    13. setMouseTracking(true);
    14. checkBox = new HoverCheckBox;
    15. label = new ClickableLabel;
    16. label->setTextFormat(Qt::RichText);
    17. label->setText(text);
    18. QHBoxLayout* layout = new QHBoxLayout;
    19. layout->setMargin(0);
    20. layout->addWidget(checkBox);
    21. layout->addWidget(label);
    22. setLayout(layout);
    23. connect(label, SIGNAL(clicked()), checkBox, SLOT(toggle()));
    24. }
    25.  
    26. void RichTextCheckBox::enterEvent(QEvent* /*event*/){
    27. checkBox->setHover(true);
    28. }
    29.  
    30. void RichTextCheckBox::leaveEvent(QEvent* /*event*/){
    31. checkBox->setHover(false);
    32. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by forgottenduck; 14th October 2014 at 21:58.

  6. #6
    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: Issues with displaying rich text for a QCheckBox

    Thanks for reporting your solution!

    One small suggestion: use update() in setHover() instead of repaint().
    This is what setters on widgets usually do.

    Cheers,
    _

  7. #7
    Join Date
    Sep 2014
    Posts
    27
    Thanks
    2
    Thanked 2 Times in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Issues with displaying rich text for a QCheckBox

    Thanks for the suggestion, I will modify my solution in my project.

    One other addition that this class could use is to apply "QStyle::State_Sunken;" while the mouse is being pressed on the qlabel, then I think it would completely emulate a rich-text check box. For now, what I have is acceptable, but if I end up adding the sunken state I will try to remember to update the solution I've posted.

  8. #8
    Join Date
    Sep 2014
    Posts
    27
    Thanks
    2
    Thanked 2 Times in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Issues with displaying rich text for a QCheckBox

    I decided to go ahead and add that additional functionality, as well as add a bunch of methods with the same name as the public QCheckBox methods for getting and setting. I also set up some signal forwarding, so you should be able to drop the RichTextCheckBox class in anywhere that QCheckBox is used, and still have everything work even though RichTextCheckBox does not inherit QCheckBox.
    Here's my updated code. Hopefully the next time someone needs to display rich text in the label of a checkbox they will find this thread instead of all the other threads which, IMO, offer inadequate solutions.

    clickablelabel.h
    Qt Code:
    1. #ifndef CLICKABLELABEL_H
    2. #define CLICKABLELABEL_H
    3.  
    4. #include <QLabel>
    5.  
    6. class ClickableLabel : public QLabel
    7. {
    8. Q_OBJECT
    9. public:
    10. explicit ClickableLabel(QWidget *parent = 0);
    11. void mouseReleaseEvent(QMouseEvent*);
    12. void mousePressEvent(QMouseEvent*);
    13. void mouseMoveEvent(QMouseEvent*);
    14.  
    15. signals:
    16. void released();
    17. void pressed();
    18. void left();
    19. public slots:
    20.  
    21. };
    22.  
    23. #endif // CLICKABLELABEL_H
    To copy to clipboard, switch view to plain text mode 
    clickablelabel.cpp
    Qt Code:
    1. #include "clickablelabel.h"
    2.  
    3. #include <QMouseEvent>
    4.  
    5. ClickableLabel::ClickableLabel(QWidget *parent) :
    6. QLabel(parent)
    7. {
    8. }
    9.  
    10. void ClickableLabel::mouseReleaseEvent(QMouseEvent* event){
    11. if(contentsRect().contains(event->pos())){
    12. if(event->buttons() == Qt::LeftButton){
    13. emit released();
    14. }else if(event->button() == Qt::LeftButton){
    15. emit released();
    16. }
    17. }
    18. }
    19.  
    20. void ClickableLabel::mousePressEvent(QMouseEvent* event){
    21. if(event->buttons() == Qt::LeftButton){
    22. emit pressed();
    23. }else if(event->button() == Qt::LeftButton){
    24. emit pressed();
    25. }
    26. }
    27.  
    28. void ClickableLabel::mouseMoveEvent(QMouseEvent* event){
    29. if(contentsRect().contains(event->pos())&&
    30. (event->buttons() == Qt::LeftButton
    31. || event->button() == Qt::LeftButton)){
    32. emit left();
    33. }
    34. }
    To copy to clipboard, switch view to plain text mode 

    hovercheckbox.h
    Qt Code:
    1. #ifndef HOVERCHECKBOX_H
    2. #define HOVERCHECKBOX_H
    3.  
    4. #include <QCheckBox>
    5.  
    6. class HoverCheckBox : public QCheckBox
    7. {
    8. Q_OBJECT
    9. public:
    10. explicit HoverCheckBox(QWidget *parent = 0);
    11. private:
    12. virtual void paintEvent(QPaintEvent *);
    13. bool isHover;
    14. bool isPressed;
    15. public slots:
    16. void setHover();
    17. void setPressed();
    18. void clearPressed();
    19. void clearStates();
    20. };
    21.  
    22. #endif // HOVERCHECKBOX_H
    To copy to clipboard, switch view to plain text mode 
    hovercheckbox.cpp
    Qt Code:
    1. #include "hovercheckbox.h"
    2.  
    3. #include <QStyleOptionButton>
    4. #include <QStylePainter>
    5.  
    6. HoverCheckBox::HoverCheckBox(QWidget *parent) :
    7. QCheckBox(parent)
    8. {
    9. isHover = false;
    10. }
    11. void HoverCheckBox::paintEvent(QPaintEvent *){
    12. QStylePainter p(this);
    13. initStyleOption(&opt);
    14. if(isHover){
    15. opt.state |= QStyle::State_MouseOver;
    16. }
    17. if(isPressed){
    18. opt.state |= QStyle::State_Sunken;
    19. }
    20. p.drawControl(QStyle::CE_CheckBox, opt);
    21. }
    22. void HoverCheckBox::setHover(){
    23. isHover = true;
    24. update();
    25. }
    26. void HoverCheckBox::setPressed(){
    27. isPressed = true;
    28. update();
    29. }
    30. void HoverCheckBox::clearPressed(){
    31. isPressed = false;
    32. update();
    33. }
    34.  
    35. void HoverCheckBox::clearStates(){
    36. isHover = false;
    37. isPressed = false;
    38. update();
    39. }
    To copy to clipboard, switch view to plain text mode 

    richtextcheckbox.h
    Qt Code:
    1. #ifndef RICHTEXTCHECKBOX_H
    2. #define RICHTEXTCHECKBOX_H
    3.  
    4. #include <QWidget>
    5.  
    6. class HoverCheckBox;
    7. class QCheckBox;
    8. class ClickableLabel;
    9.  
    10. class RichTextCheckBox : public QWidget
    11. {
    12. Q_OBJECT
    13. public:
    14. explicit RichTextCheckBox(QString text, QWidget *parent = 0);
    15. HoverCheckBox* getCheckBox(){return checkBox;}
    16. QString text() const;
    17. QString plainText() const;
    18. Qt::CheckState checkState() const;
    19. bool isChecked() const;
    20. void clearStates();
    21.  
    22. private:
    23. HoverCheckBox* checkBox;
    24. ClickableLabel* label;
    25. virtual void enterEvent(QEvent*);
    26. virtual void leaveEvent(QEvent*);
    27.  
    28. signals:
    29. void toggled(bool);
    30. void clicked();
    31.  
    32. public slots:
    33. void setChecked(bool);
    34. void setCheckState(Qt::CheckState state);
    35. void emitToggled(bool);
    36. void emitClicked();
    37.  
    38. };
    39.  
    40. #endif // RICHTEXTCHECKBOX_H
    To copy to clipboard, switch view to plain text mode 
    richtextcheckbox.cpp
    Qt Code:
    1. #include "richtextcheckbox.h"
    2. #include "hovercheckbox.h"
    3. #include "clickablelabel.h"
    4. #include <QMouseEvent>
    5. #include <QLabel>
    6. #include <QLayout>
    7. #include <QTextDocument>
    8.  
    9. RichTextCheckBox::RichTextCheckBox(QString text, QWidget *parent) :
    10. QWidget(parent)
    11. {
    12. setMouseTracking(true);
    13. checkBox = new HoverCheckBox;
    14. label = new ClickableLabel;
    15. label->setTextFormat(Qt::RichText);
    16. label->setText(text);
    17. QHBoxLayout* layout = new QHBoxLayout;
    18. layout->setMargin(0);
    19. layout->addWidget(checkBox);
    20. layout->addWidget(label);
    21. layout->setAlignment(Qt::AlignLeft);
    22. setLayout(layout);
    23. connect(label, SIGNAL(released()), checkBox, SLOT(toggle()));
    24. connect(label, SIGNAL(released()), checkBox, SLOT(clearPressed()));
    25. connect(label, SIGNAL(pressed()), checkBox, SLOT(setPressed()));
    26. connect(label, SIGNAL(left()), checkBox, SLOT(clearStates()));
    27. connect(checkBox, SIGNAL(toggled(bool)),this, SLOT(emitToggled(bool)));
    28. connect(checkBox, SIGNAL(clicked()), this, SLOT(emitClicked()));
    29. connect(label, SIGNAL(released()), this, SLOT(emitClicked()));
    30. }
    31.  
    32. void RichTextCheckBox::emitClicked(){
    33. emit clicked();
    34. }
    35.  
    36. void RichTextCheckBox::emitToggled(bool b){
    37. emit toggled(b);
    38. }
    39.  
    40. bool RichTextCheckBox::isChecked() const{
    41. return checkBox->isChecked();
    42. }
    43.  
    44. Qt::CheckState RichTextCheckBox::checkState() const{
    45. return checkBox->checkState();
    46. }
    47.  
    48. QString RichTextCheckBox::text() const{
    49. return label->text();
    50. }
    51.  
    52. QString RichTextCheckBox::plainText() const{
    53. doc.setHtml(label->text());
    54. return doc.toPlainText();
    55. }
    56.  
    57. void RichTextCheckBox::clearStates(){
    58. checkBox->clearStates();
    59. }
    60.  
    61. void RichTextCheckBox::setCheckState(Qt::CheckState state){
    62. checkBox->setCheckState(state);
    63. }
    64.  
    65. void RichTextCheckBox::setChecked(bool value){
    66. checkBox->setChecked(value);
    67. }
    68.  
    69. void RichTextCheckBox::enterEvent(QEvent* /*event*/){
    70. checkBox->setHover();
    71. }
    72.  
    73. void RichTextCheckBox::leaveEvent(QEvent* /*event*/){
    74. checkBox->clearStates();
    75. }
    To copy to clipboard, switch view to plain text mode 

  9. #9
    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: Issues with displaying rich text for a QCheckBox

    Another suggestion

    instead of
    Qt Code:
    1. connect(label, SIGNAL(released()), this, SLOT(emitClicked()));
    2. }
    3.  
    4. void RichTextCheckBox::emitClicked(){
    5. emit clicked();
    6. }
    To copy to clipboard, switch view to plain text mode 
    i.e. instead of calling a local slot only to emit a signal, you can also "forward" the signal using a signal/signal connection
    Qt Code:
    1. connect(label, SIGNAL(released()), this, SIGNAL(clicked()));
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  10. #10
    Join Date
    Sep 2014
    Posts
    27
    Thanks
    2
    Thanked 2 Times in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Issues with displaying rich text for a QCheckBox

    Haha, I have no idea how I didn't know you could forward a signal that way. There's a few places in my code I need to clean up now.
    Thanks

  11. #11
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Issues with displaying rich text for a QCheckBox

    Thanks for sharing this nice work. This will probably make it possible to label checkboxes with symbols and math formulas in addition to simple sub- and superscripts. If you are willing to post the final code (maybe as a zip file attachment rather than in CODE blocks ), that would be greatly appreciated and help others avoid copy-and-paste issues.

  12. #12
    Join Date
    Sep 2014
    Posts
    27
    Thanks
    2
    Thanked 2 Times in 1 Post
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Issues with displaying rich text for a QCheckBox

    I'd be happy to share my finished code. Here's a zip file with all 3 classes. Feel free to PM me or reply here if you have any questions or suggestions.
    Everything seems to be working just as intended, I've tested it in a horizontal layout with other standard checkboxes and it appears to be spaced in the layout exactly the same. I have not tested it in a vertical layout so an adjustment may need to be made to richtextcheckbox.cpp for a vertical layout, as I had to add extra spacing on the right to achieve the correct look:
    Qt Code:
    1. layout->setContentsMargins(0, 0, 5, 0);
    To copy to clipboard, switch view to plain text mode 

    If an admin or mod could mark this thread as solved it would be appreciated.
    Attached Files Attached Files

  13. The following 2 users say thank you to forgottenduck for this useful post:

    d_stranz (17th October 2014), edice (26th March 2019)

Similar Threads

  1. [SOLVED] QCheckBox Tristate
    By ToddAtWSU in forum Qt Programming
    Replies: 0
    Last Post: 15th January 2014, 19:33
  2. QTabbar with rich text / html tab text
    By Berryblue031 in forum Qt Programming
    Replies: 1
    Last Post: 21st May 2012, 09:46
  3. Rich text with QPainter?
    By sarefo in forum Qt Programming
    Replies: 3
    Last Post: 7th April 2008, 14:40
  4. QTextEdit + paste rich text as plain text only
    By Yong in forum Qt Programming
    Replies: 2
    Last Post: 6th February 2008, 16:45
  5. QWidget pixmap AFTER displaying html ("rich text")
    By gavrilo princep in forum Newbie
    Replies: 0
    Last Post: 17th July 2007, 01:59

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.