Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Trouble with custom QSlider
Forum Updated to NodeBB v4.3 + New Features

Trouble with custom QSlider

Scheduled Pinned Locked Moved Unsolved General and Desktop
16 Posts 3 Posters 3.3k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    Smeeth
    wrote on last edited by
    #1

    I create a custom class that extends QSlider in order to write values next to the tick marks. Here is what the widget looks like:

    0_1558724516260_87cb4290-a72b-4e42-8647-4e65d92f8a78-image.png

    Here is my method paintEvents that overrides QSlider::paintEvent

    void AlarmLimitsSlider::paintEvent(QPaintEvent *ev) {
        QSlider::paintEvent(ev);
    
        auto painter = new QPainter(this);
        painter->setPen(QPen(Qt::black));
    
        auto rect = this->geometry();
    
        int numTicks = (maximum() - minimum())/tickInterval();
    
        QFontMetrics fontMetrics = QFontMetrics(this->font());
    
        if (this->orientation() == Qt::Horizontal) {
    
           ...not important....
    
        } else if (this->orientation() == Qt::Vertical) {
    
            int sliderHeight = rect.height();
            int heightOffset = 15;
    
            for (int i=0; i<=numTicks; i++){
    
                int tickNum = maximum() - (tickInterval() * i);
    
                QString toWrite = QString::number(tickNum);
                if (isPercentage) toWrite.append("%");
    
                double percentageOfHeight = static_cast<double>(i) / static_cast<double>(numTicks);
                int heightIntervalOffset = static_cast<int>(15 * percentageOfHeight);
    
                auto tickX = 0;
                auto tickY = heightOffset + ((sliderHeight/numTicks) * i) - heightIntervalOffset;
    
                painter->drawText(QPoint(tickX, tickY), toWrite);
            }
        } else {
            return;
        }
    
    }
    

    Here is my GUI setup for the Slider

    .....in constructor...
    mvLowSld(new AlarmLimitsSlider(Qt::Vertical)),
    mvHighSld(new AlarmLimitsSlider(Qt::Vertical)),
    mvMarkerSld(new AlarmLimitsSlider(Qt::Vertical)),
    
    .....
    
    mvLowSld->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    mvHighSld->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    mvMarkerSld->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    

    And here is where I create the Widget that contains the QSliders.

    QWidget*AlarmLimitsPanel::createMVLimitsPanel(){
    
        QLabel *mvLowLbl = new QLabel("MV Low");
        mvLowLbl->setObjectName("titleLbl");
        QLabel *mvHighLbl = new QLabel("MV High");
        mvHighLbl->setObjectName("titleLbl");
        QLabel *mvMarkerLbl = new QLabel("MV Marker");
        mvMarkerLbl->setObjectName("titleLbl");
    
        QGridLayout *mainLayout = new QGridLayout;
    
        mainLayout->addWidget(mvLowLbl, 0, 0, Qt::AlignHCenter);
        mainLayout->addWidget(mvLowValLbl, 1, 0, Qt::AlignHCenter);
        mainLayout->addWidget(mvLowSld, 2, 0, Qt::AlignHCenter);
    
        mainLayout->addWidget(mvHighLbl, 0, 1, Qt::AlignHCenter);
        mainLayout->addWidget(mvHighValLbl, 1, 1, Qt::AlignHCenter);
        mainLayout->addWidget(mvHighSld, 2, 1, Qt::AlignHCenter);
    
        mainLayout->addWidget(mvMarkerLbl, 0, 2, Qt::AlignHCenter);
        mainLayout->addWidget(mvMarkerValLbl, 1, 2, Qt::AlignHCenter);
        mainLayout->addWidget(mvMarkerSld, 2, 2, Qt::AlignHCenter);
    
        QWidget*mvLimitsPanel = new QWidget;
        mvLimitsPanel->setLayout(mainLayout);
    
        return mvLimitsPanel;
    
    }
    

    When I try to change the QSlider stylesheet to make the QSlider handle thinner and taller, the handle does not change shape.

                    "QSlider{font: 20px Verdana; padding: 25px}"
                    "QSlider::handle {"
                       "max-width: 5px;"
                       "height: 50px;"
                       "background-color: blue;"
                    "}"
    

    The background color changes, but the handle remains the same shape.

    I also get these errors in the console that print a bunch of times when the .paintEvent method is being called:

    QBackingStore::endPaint() called with active painter on backingstore paint device
    

    and when I end my application, I get:

    QPaintDevice: Cannot destroy paint device that is being painted
    

    These errors do not cause any issues in the application, but I wonder if they are related to my problems?

    So why is the handle shape not changing? When I change the SizePolicy of the AlarmLimitsSlider, the handle always extends the full horizontal length of the widget. Is there some other settings to change the width of the QSlider handle?

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      You should use your subclass class name in your style sheet.

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      S 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi,

        You should use your subclass class name in your style sheet.

        S Offline
        S Offline
        Smeeth
        wrote on last edited by
        #3

        @SGaist Strangely enough, when I replace "QSlider" with "AlarmLimitsSlider" in the stylesheet, the style is not applied and all characteristics are the default, even though all sliders are of type AlarmLimitsSlider and are initialized using the AlarmLimitsSlider constructor. Is this indicative of some other problem?

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          So after re-reading and checking:

          • You painter issue is because you are creating a new painter on the heap each time paintEvent is called without deleting it when done. Put it on the stack so it gets properly destroyed once the event is finished.
          • As for your style sheet, get back to QSlider and use the groove selector.
          "QSlider {font: 20px Verdana; padding: 25px}"
                          "QSlider::groove {"
                             "max-width: 2px;"
                             "height: 5px;"
                             "background-color: blue;"
                          "}"
          

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          S 1 Reply Last reply
          2
          • SGaistS SGaist

            So after re-reading and checking:

            • You painter issue is because you are creating a new painter on the heap each time paintEvent is called without deleting it when done. Put it on the stack so it gets properly destroyed once the event is finished.
            • As for your style sheet, get back to QSlider and use the groove selector.
            "QSlider {font: 20px Verdana; padding: 25px}"
                            "QSlider::groove {"
                               "max-width: 2px;"
                               "height: 5px;"
                               "background-color: blue;"
                            "}"
            
            S Offline
            S Offline
            Smeeth
            wrote on last edited by
            #5

            @SGaist Sorry, by "put it on the stack" do you mean use a member variable? Or somehow access the painter object without instantiating it each time?

            I went back to QSlider but setting the max-width for the groove doesn't change the width of the handle, it still extends to the wide size policy of the widget.

            A 1 Reply Last reply
            0
            • S Smeeth

              @SGaist Sorry, by "put it on the stack" do you mean use a member variable? Or somehow access the painter object without instantiating it each time?

              I went back to QSlider but setting the max-width for the groove doesn't change the width of the handle, it still extends to the wide size policy of the widget.

              A Offline
              A Offline
              arsinte_andrei
              wrote on last edited by arsinte_andrei
              #6

              @Smeeth
              I think he is referring to the

              auto painter = new QPainter(this);
              

              like that painter get destroyed only with the form
              so you should change that ...
              and also is getting a new place in memory everytime you touch the slider - careful with the memory management

              S 1 Reply Last reply
              1
              • A arsinte_andrei

                @Smeeth
                I think he is referring to the

                auto painter = new QPainter(this);
                

                like that painter get destroyed only with the form
                so you should change that ...
                and also is getting a new place in memory everytime you touch the slider - careful with the memory management

                S Offline
                S Offline
                Smeeth
                wrote on last edited by
                #7

                @arsinte_andrei Got it. So how can I get the painter without calling new QPainter(this)?

                A 1 Reply Last reply
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  QPainter painter(this);

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply
                  2
                  • S Smeeth

                    @arsinte_andrei Got it. So how can I get the painter without calling new QPainter(this)?

                    A Offline
                    A Offline
                    arsinte_andrei
                    wrote on last edited by
                    #9

                    @Smeeth here you have two options -

                    1. delete
                    private:
                    QPainter *painter;
                    

                    and

                    painter = new QPainter(this);
                    

                    and inside the paint event add

                    void AlarmLimitsSlider::paintEvent(QPaintEvent *ev) {
                    QPainter painter;
                    //TODO the painting
                    
                    1. options
                      you have declared the painter as a global variable... so make a global init

                    so in your constructor add

                    painter = new QPainter(this);
                    

                    and delete it from the paint event

                    S 1 Reply Last reply
                    0
                    • A arsinte_andrei

                      @Smeeth here you have two options -

                      1. delete
                      private:
                      QPainter *painter;
                      

                      and

                      painter = new QPainter(this);
                      

                      and inside the paint event add

                      void AlarmLimitsSlider::paintEvent(QPaintEvent *ev) {
                      QPainter painter;
                      //TODO the painting
                      
                      1. options
                        you have declared the painter as a global variable... so make a global init

                      so in your constructor add

                      painter = new QPainter(this);
                      

                      and delete it from the paint event

                      S Offline
                      S Offline
                      Smeeth
                      wrote on last edited by
                      #10

                      @arsinte_andrei Oh I see, for some reason I thought you had to create a new Painter for each time the paint event is triggered. I will try this solution.

                      1 Reply Last reply
                      0
                      • SGaistS Offline
                        SGaistS Offline
                        SGaist
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        Based on the documentation of QPainter:

                        The common use of QPainter is inside a widget's paint event: Construct and customize (e.g. set the pen or the brush) the painter. Then draw. Remember to destroy the QPainter object after drawing. For example:
                        

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        1 Reply Last reply
                        2
                        • A Offline
                          A Offline
                          arsinte_andrei
                          wrote on last edited by
                          #12

                          so as SGaist sugest.. and he is right... at option 2 keep

                          painter = new QPainter(this);
                          

                          the first line in the paintEvent and add

                          delete painter;
                          

                          as your last line in the paint event...

                          but anyway I do not understand why will you want option 2 when option 1 is the best???

                          SGaistS 1 Reply Last reply
                          0
                          • A arsinte_andrei

                            so as SGaist sugest.. and he is right... at option 2 keep

                            painter = new QPainter(this);
                            

                            the first line in the paintEvent and add

                            delete painter;
                            

                            as your last line in the paint event...

                            but anyway I do not understand why will you want option 2 when option 1 is the best???

                            SGaistS Offline
                            SGaistS Offline
                            SGaist
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            @arsinte_andrei said in Trouble with custom QSlider:

                            so as SGaist sugest.. and he is right... at option 2 keep

                            painter = new QPainter(this);
                            

                            the first line in the paintEvent and add

                            delete painter;
                            

                            as your last line in the paint event...

                            but anyway I do not understand why will you want option 2 when option 1 is the best???

                            It's not what I suggested, use a stack base painter, there's really no need to allocate if on the heap.

                            Interested in AI ? www.idiap.ch
                            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                            A 1 Reply Last reply
                            2
                            • SGaistS SGaist

                              @arsinte_andrei said in Trouble with custom QSlider:

                              so as SGaist sugest.. and he is right... at option 2 keep

                              painter = new QPainter(this);
                              

                              the first line in the paintEvent and add

                              delete painter;
                              

                              as your last line in the paint event...

                              but anyway I do not understand why will you want option 2 when option 1 is the best???

                              It's not what I suggested, use a stack base painter, there's really no need to allocate if on the heap.

                              A Offline
                              A Offline
                              arsinte_andrei
                              wrote on last edited by arsinte_andrei
                              #14

                              @SGaist you pointed at the option 2.. but if you look at option 1 is exactly what you have said.. this is what I've recommended...

                              void AlarmLimitsSlider::paintEvent(QPaintEvent *ev) {
                              QPainter painter;
                              //TODO the painting
                              

                              or

                              void AlarmLimitsSlider::paintEvent(QPaintEvent *ev) {
                              QPainter painter(this);
                              //TODO the painting
                              

                              same thing.. - except the second one has parent

                              1 Reply Last reply
                              0
                              • SGaistS Offline
                                SGaistS Offline
                                SGaist
                                Lifetime Qt Champion
                                wrote on last edited by
                                #15

                                It's not the same thing. It's not a parent, it's the paint device that the painter will be active on. If you don't pass it, you will have to call begin and end explicitly. See the constructor documentation.

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                1 Reply Last reply
                                3
                                • A Offline
                                  A Offline
                                  arsinte_andrei
                                  wrote on last edited by
                                  #16

                                  Hmm.... After years pf doing Qt programming I have to agree that I still have a lot to learn about... I do apologize for the wrong information that I've provided....
                                  Best explanation... God bless SGaist...

                                  1 Reply Last reply
                                  1

                                  • Login

                                  • Login or register to search.
                                  • First post
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • Users
                                  • Groups
                                  • Search
                                  • Get Qt Extensions
                                  • Unsolved