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. How to apply QLinearGradient on a round QWidget border using style sheet?
Forum Updated to NodeBB v4.3 + New Features

How to apply QLinearGradient on a round QWidget border using style sheet?

Scheduled Pinned Locked Moved Solved General and Desktop
2 Posts 1 Posters 518 Views 1 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.
  • C Offline
    C Offline
    CPPUIX
    wrote on last edited by CPPUIX
    #1

    Hi,

    Here's my situation:

    Context:

    I am trying to animate a timer progress on a QPushButton border, using style sheet and QLinearGradient.

    Here's how I'm doing it:

    #include <QApplication>
    #include <QPushButton>
    #include <QTimer>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QPushButton *btn = new QPushButton("Animation Button");
    
        float A=0.99,b=0.01;
        QTimer *t = new QTimer();
        int border=1;
    
        btn->setMinimumSize(200,50);
    
        btn->connect(t,&QTimer::timeout,[btn,&A,&b,&border](){
            if(border==2 || border==3)
            {
                if(b+0.01>1)
                {
                    b=0;
                    border=border++%4+1;
                }
                b+=0.01;
            }
            else
            {
                if(A-0.01<0.01)
                {
                    A=1;
                    border=border%4+1;
                }
                A-=0.01;
            }
    
            switch (border)
            {
                case 1:
                    btn->setStyleSheet(QString("border: 2px solid white;"
                                                          //"border-radius: 5px;"
                                                          "border-top: 2px solid qlineargradient(x0:0, x2:1,"
                                                          "stop: 0 green,"
                                                          "stop: %1 green,"
                                                          "stop: %2 white,"
                                                          "stop: 1 white);"
                                                          "background: black;").arg(A).arg(A+0.01));
                    break;
                case 2:
                    btn->setStyleSheet(QString("border: 2px solid white;"
                                                          //"border-radius: 5px;"
                                                          "border-left: 2px solid qlineargradient(y0:0, y2:1,"
                                                          "stop: 0 white,"
                                                          "stop: %1 white,"
                                                          "stop: %2 green,"
                                                          "stop: 1 green);"
                                                          "background: black;").arg(b).arg(b+0.01));
    
                    break;
                case 3:
                    btn->setStyleSheet(QString("border: 2px solid white;"
                                                          //"border-radius: 5px;"
                                                          "border-bottom: 2px solid qlineargradient(x0:0, x2:1,"
                                                          "stop: 0 white,"
                                                          "stop: %1 white,"
                                                          "stop: %2 green,"
                                                          "stop: 1 green);"
                                                          "background: black;").arg(b).arg(b+0.01));
                    break;
                case 4:
                    btn->setStyleSheet(QString("border: 2px solid white;"
                                                          //"border-radius: 5px;"
                                                          "border-right: 2px solid qlineargradient(y0:0, y2:1,"
                                                          "stop: 0 green,"
                                                          "stop: %1 green,"
                                                          "stop: %2 white,"
                                                          "stop: 1 white);"
                                                          "background: black;").arg(A).arg(A+0.01));
                    break;
            }
        });
    
        t->start(50);
    
        btn->show();
    
        return a.exec();
    }
    

    Here's the logic I came up with to create this animation:

    A and b are values that control green and white color range in QLinearGradient, green is the progress, and white is the actual border color. The basic idea, is that I'm making the white recede, and the green advance, or vice versa. There is a small fraction between their values to avoid the gradient effect, hence why I 'm using b and b+0.1 for example. If A or b reach the limit of a range (1 or 0), they reset to the default . border is a variable that allows me to iterate through the 4 borders in my switch case, just a simple circular counter. All of this loops using a QTimer.

    Here's the result:

    animationButton.gif

    Problem:

    I need round borders, but when I use them, it looks like this:

    borderanimation.gif

    The borders seem to form another side of the button on their own, as if with round borders, the button now has 8 sides, because the animation on the round borders seem to be synced with the border that's currently being animated, instead of being animated when the animation reaches them. It also looks like a mirror effect.

    Goal:
    How do I animate the round borders the same way as the not round ones?

    I'm open to alternatives to the way I'm currently animating the borders, if my current one is too messy or there is a much simpler one, to achieve the same result.

    I'd be glad to answer any further questions, share more details, and clarify ambiguities.

    Thank you for your time, and effort!

    1 Reply Last reply
    0
    • C Offline
      C Offline
      CPPUIX
      wrote on last edited by
      #2

      Since setting border radius using stylesheets has unwanted effects, you could make your widget borders round without it, and use paintEvent instead, here's how:

      You could draw a rounded rect with a color same as the widget parent's background, this acts as if it's hiding those sharp corners, and make them look round.

      One downside of this method is that it limits how round the corners can get, because if the painter draws a too rounded rect, it will mask the widget itself or cause sharp edges.

      It is possible to slightly get around that by increasing the border size, to get more space, thus, making it possible to increase the border radius when using a painter without ruining the widget edges.

      There is an upside for using this method. It prevents the widget background from poking out the border.

      Here's an example of subclass derived from QPushButton with a custom paintEvent:

      class button : public QPushButton
      {
          Q_OBJECT
      
      public:
          button (QWidget *parent = nullptr) : QPushButton(parent) {}
      
      
      protected:
          void paintEvent(QPaintEvent *event) override
          {
              QPushButton::paintEvent(event);
      
              QRectF r = rect();
              r.adjust(-1,-1,+1,+1);
      
              QPainter p(this);
              QColor color = parentWidget()->palette().brush(QPalette::Window).color();
              p.setPen(QPen(color,2));
              p.setRenderHint(QPainter::Antialiasing);
              p.drawRoundedRect(r, 6, 6);
          }
      };
      

      Here's the result, where the bottom button is a normal QPushButton with no border radius, just to increase the difference visibility:

      Round corners using paintEvent

      1 Reply Last reply
      0
      • C CPPUIX has marked this topic as solved on

      • Login

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