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 make progress tracker/custom loader

How to make progress tracker/custom loader

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 3 Posters 878 Views
  • 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.
  • A Offline
    A Offline
    abanksdev
    wrote on last edited by
    #1

    Hi all,

    I'm new to Qt and have been reading a bunch of different posts about making custom shapes in Qt, but figured I would have a much stronger head start if I ask a question here directly instead of guessing.

    I want to make a loader/progress tracker that looks like this:
    0_1531864312525_loader.png

    Where the blue represents the amount completed and updates as more of the process is completed. What is the simplest way to achieve this in Qt?

    1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by VRonin
      #2
      class CircleProgress : public QWidget{
          Q_OBJECT
          Q_DISABLE_COPY(CircleProgress)
      public:
          explicit CircleProgress(QWidget* parent = Q_NULLPTR)
              :QWidget(parent) //initialise the base class and set some default values to the parameters
              , m_emptyColor(Qt::gray)
              , m_fullColor(Qt::blue)
              , m_maxValue(100)
              , m_progress(0)
              , m_minValue(0)
          {}
      
      //! sets the range progress can move into
          void setRange(int minValue,int maxValue){
              if(maxValue<minValue) //invert min and max if the user inverted the arguments
                  std::swap(maxValue,minValue);
              setMaxValue(maxValue);
              setMinValue(minValue);
          }
      //! returns the maximum value of progress
          int maxValue() const
          {
              return m_maxValue;
          }
      // sets the maximum value of progress
          void setMaxValue(int maxValue)
          {
              m_maxValue = maxValue;
              if(m_progress>m_maxValue) // restrict the progress value to the new maximum
                  m_progress=m_maxValue;
              if(m_minValue>m_maxValue) // if min is more than the max, set the min to the same value as max
                  m_minValue=m_maxValue;
              update();
          }
      //! returns the minimum value of progress
          int minValue() const
          {
              return m_minValue;
          }
      // sets the minimum value of progress
          void setMinValue(int minValue)
          {
              m_minValue = minValue;
              if(m_progress<m_minValue) // restrict the progress value to the new minimum 
                  m_progress=m_minValue;
              if(m_maxValue<m_minValue) // if max is less than the min, set the min to the same value as max
                  m_maxValue=m_minValue;
              update();
          }
      //! the current progress value
          int progress() const
          {
              return m_progress;
          }
      //! sets the value of progress
          void setProgress(int progress)
          {
      // restrict progress to be between min and max
              m_progress = qMax(m_minValue,qMin(m_maxValue,progress));
              update();
          }
      
      //! returns the color used to paint the the non-completed part
          const QColor& emptyColor() const
          {
              return m_emptyColor;
          }
      //! sets the color used to paint the the non-completed part
          void setEmptyColor(const QColor& emptyColor)
          {
              m_emptyColor = emptyColor;
              update();
          }
      //! returns the color used to paint the the completed part
          const QColor& fullColor() const
          {
              return m_fullColor;
          }
      //! sets the color used to paint the the completed part
          void setFullColor(const QColor& fullColor)
          {
              m_fullColor = fullColor;
              update();
          }
      
      protected:
          void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE{
              Q_ASSERT(m_maxValue>=m_minValue); // make sure max is the same or more than the min
              QWidget::paintEvent(event); // call the base class implementation
              QPainter painter(this); // set a painter to paint on the widget
              painter.setRenderHint(QPainter::Antialiasing); // since we are drawing arches Antialiasing makes the look a lot better
              QPen archPen(QBrush(m_fullColor), qMin(rect().width(),rect().height())/8,Qt::SolidLine,Qt::FlatCap); // create a pen with the width equal to 1/8 of the minimum between the widget width and height
              const int margin = 10+archPen.width()/2; // give a 10 pixel margin from the borders of the widget
              const QRect widRect = rect().marginsRemoved(QMargins(margin,margin,margin,margin));
      
              painter.setPen(archPen);
      // QPainter::drawArc works in 1/16th of a degree so we calculate the % of progress and then multiply by 360 and 16
              const int progressDegrees = (m_maxValue==m_minValue ? 0 : (m_progress-m_minValue)*360*16/(m_maxValue-m_minValue));
              if(progressDegrees>0)
                  painter.drawArc(widRect,90*16,-progressDegrees); // draw the completed part
              if(progressDegrees<360*16){
                  archPen.setColor(m_emptyColor); // set the color to the non-completed one
                  painter.setPen(archPen);
                  painter.drawArc(widRect,90*16-progressDegrees,-(360*16)+progressDegrees); // draw the non completed part
              }
      
          }
      private:
          QColor m_emptyColor; // color used to paint the the non-completed part
          QColor m_fullColor; // color used to paint the the completed part
          int m_maxValue; // maximum value of progress
          int m_minValue; // minimum value of progress
          int m_progress; // current progress
      };
      

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      5
      • A Offline
        A Offline
        abanksdev
        wrote on last edited by
        #3

        @VRonin can you walk me through what all of this is doing/means?

        Thank you!

        VRoninV 1 Reply Last reply
        0
        • A abanksdev

          @VRonin can you walk me through what all of this is doing/means?

          Thank you!

          VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #4

          @abanksdev Commented the code

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          2
          • A Offline
            A Offline
            abanksdev
            wrote on last edited by
            #5

            @VRonin thanks so much for commenting the code, it certainly works. I'm just having a slight issue adjusting the size of the circle, it's quite squished. Due to my complete lack of experience it's not immediately obvious to me how to adjust the size.

            Right now it looks like this:
            0_1533053386153_Screen Shot 2018-07-31 at 12.01.25 PM.png

            Is it possible to adjust where it shows up on the screen and make it perfectly circular rather than squished?

            Thank you!

            1 Reply Last reply
            0
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by
              #6

              http://doc.qt.io/qt-5/layout.html

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              1 Reply Last reply
              2
              • mrjjM Offline
                mrjjM Offline
                mrjj
                Lifetime Qt Champion
                wrote on last edited by mrjj
                #7

                Hi
                Its just its default size when you create it.
                CircleProgress * cp= new CircleProgress(centralWidget()); // note use central for parent
                // resize it to have same width and height
                cp->resize(128,128);

                But for any real application, you should look into layouts as @VRonin links to.
                It makes application adapt to any screen size automatically.

                1 Reply Last reply
                2
                • A Offline
                  A Offline
                  abanksdev
                  wrote on last edited by
                  #8

                  Any ideas on how to implement this in QML and Qt Quick? I'm referencing this doc: http://doc.qt.io/qt-5/qquickpainteditem.html

                  but can't figure out how to get the CircleProgress paint object to the CircleProgress QML element

                  1 Reply Last reply
                  0

                  • Login

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