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. Problem with scrolling in QScrollArea
Forum Updated to NodeBB v4.3 + New Features

Problem with scrolling in QScrollArea

Scheduled Pinned Locked Moved Solved General and Desktop
7 Posts 4 Posters 1.3k 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.
  • supergS Offline
    supergS Offline
    superg
    wrote on last edited by superg
    #1

    Hello,
    I'm having a problem with a QScrollArea. What I'm doing is add an object that contains a QFrame to the QScrollArea. This object will store a variable number of other objects that function as rows that have some funcionalities.
    The problem seems very simple: When adding rows to the scroll area to a point that the new row added it's below it's viewport, a method is called that scrolls to the value where the row is so it can be seen, but it fails to do so. It only scrolls to the "top" of the row. I think I found the origin of the error but I don't know how to solve it. It may be related to the range of the scroll area being updated after the method that shows the selected row is executed. So, if it scrolls to the maximum, it will scroll to the old maximum, before it's value was updated. I do not want to hard code the new maximum value, but I can't seem to find a solution.
    Here I provide to images to illustrate how it should behave vs how it's currently behaving when a new row is added.

    1 - How it should behave:

    foto2.png

    2 - How it behaves:

    foto1.png

    Here is the code that is in charge of showing the row:

    void blanqueo::showRow()
    {
        // Get the position of the frame within the scroll area
        QPoint frameInScrollArea = actualRow->mapTo(ui->scrollArea, QPoint(0, 0));
    
        // Calculate the position of the custom object within the scroll area
        QPoint rowPosInScrollArea = frameInScrollArea + actualRow->getActualPoint();
    
        // Get the y-coordinate of the top edge of the custom object
        int yTop = rowPosInScrollArea.y();
    
        // Get the height of the scroll area viewport
        int viewportHeight = ui->scrollArea->viewport()->height();
    
        // Get the current scrollbar value and range
        QScrollBar* scrollbar = ui->scrollArea->verticalScrollBar();
        int currentValue = scrollbar->value();
        int maximumValue = scrollbar->maximum();
    
        // Only adjust the scrollbar value if the selected row is not currently visible
        if (yTop < currentValue || yTop > currentValue + viewportHeight) {
            // Calculate the new scrollbar value that will make the selected row fully visible
            int newValue = qMax(yTop - viewportHeight / 2, 0);
            newValue = qMin(newValue, maximumValue);
    
            // Set the new scrollbar value
    //        scrollbar->setValue(newValue);
            scrollbar->setSliderPosition(newValue);
        }
    
        changeButtonStyle(actualRow->isActualScanned());
        ui->currentTubeLabel->setText( insertTubeText.arg( actualRow->getActualTube() ) );
    }
    

    And this is the method getActualPoint() used:

    QPoint noProtocolBlanqSpec::getActualPoint()
    { // Get position of row in QFrame and add row height
        QPoint rowPosInFrame = br->mapTo(ui->frame, QPoint(0, 0)) + QPoint(0, getActualHeight() );
        qDebug() << rowPosInFrame << getActualHeight();
        return rowPosInFrame;
    }
    

    I'm open to suggestions on how to implement this, because I've seen strange behavior under certain scenarios, which I have fixed by not calling it when the user selects a Row manually, because that would mean they can already see it.

    I hope it's not that confusing, feel free to ask any questions.

    Thank you all in advance.

    M JonBJ 2 Replies Last reply
    0
    • supergS superg

      Hello,
      I'm having a problem with a QScrollArea. What I'm doing is add an object that contains a QFrame to the QScrollArea. This object will store a variable number of other objects that function as rows that have some funcionalities.
      The problem seems very simple: When adding rows to the scroll area to a point that the new row added it's below it's viewport, a method is called that scrolls to the value where the row is so it can be seen, but it fails to do so. It only scrolls to the "top" of the row. I think I found the origin of the error but I don't know how to solve it. It may be related to the range of the scroll area being updated after the method that shows the selected row is executed. So, if it scrolls to the maximum, it will scroll to the old maximum, before it's value was updated. I do not want to hard code the new maximum value, but I can't seem to find a solution.
      Here I provide to images to illustrate how it should behave vs how it's currently behaving when a new row is added.

      1 - How it should behave:

      foto2.png

      2 - How it behaves:

      foto1.png

      Here is the code that is in charge of showing the row:

      void blanqueo::showRow()
      {
          // Get the position of the frame within the scroll area
          QPoint frameInScrollArea = actualRow->mapTo(ui->scrollArea, QPoint(0, 0));
      
          // Calculate the position of the custom object within the scroll area
          QPoint rowPosInScrollArea = frameInScrollArea + actualRow->getActualPoint();
      
          // Get the y-coordinate of the top edge of the custom object
          int yTop = rowPosInScrollArea.y();
      
          // Get the height of the scroll area viewport
          int viewportHeight = ui->scrollArea->viewport()->height();
      
          // Get the current scrollbar value and range
          QScrollBar* scrollbar = ui->scrollArea->verticalScrollBar();
          int currentValue = scrollbar->value();
          int maximumValue = scrollbar->maximum();
      
          // Only adjust the scrollbar value if the selected row is not currently visible
          if (yTop < currentValue || yTop > currentValue + viewportHeight) {
              // Calculate the new scrollbar value that will make the selected row fully visible
              int newValue = qMax(yTop - viewportHeight / 2, 0);
              newValue = qMin(newValue, maximumValue);
      
              // Set the new scrollbar value
      //        scrollbar->setValue(newValue);
              scrollbar->setSliderPosition(newValue);
          }
      
          changeButtonStyle(actualRow->isActualScanned());
          ui->currentTubeLabel->setText( insertTubeText.arg( actualRow->getActualTube() ) );
      }
      

      And this is the method getActualPoint() used:

      QPoint noProtocolBlanqSpec::getActualPoint()
      { // Get position of row in QFrame and add row height
          QPoint rowPosInFrame = br->mapTo(ui->frame, QPoint(0, 0)) + QPoint(0, getActualHeight() );
          qDebug() << rowPosInFrame << getActualHeight();
          return rowPosInFrame;
      }
      

      I'm open to suggestions on how to implement this, because I've seen strange behavior under certain scenarios, which I have fixed by not calling it when the user selects a Row manually, because that would mean they can already see it.

      I hope it's not that confusing, feel free to ask any questions.

      Thank you all in advance.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #5

      @superg said in Problem with scrolling in QScrollArea:

      a method is called that scrolls to the value where the row is so it can be seen, but it fails to do so. It only scrolls to the "top" of the row. I think I found the origin of the error but I don't know how to solve it. It may be related to the range of the scroll area being updated after the method that shows the selected row is executed. So, if it scrolls to the maximum, it will scroll to the old maximum, before it's value was updated.

      This could indeed be a part of the problem.

      Either sort it out, or: maybe you can put the "scroll to visible" code into a QTimer::singleShot(0, ...) call? That delays it till after whatever updating is now going on has taken effect.

      Otherwise if the "scroll till visible" code really only makes the top of the item visible at the bottom of the pane you could then scroll down by the height of an item.

      supergS 1 Reply Last reply
      0
      • supergS superg

        Hello,
        I'm having a problem with a QScrollArea. What I'm doing is add an object that contains a QFrame to the QScrollArea. This object will store a variable number of other objects that function as rows that have some funcionalities.
        The problem seems very simple: When adding rows to the scroll area to a point that the new row added it's below it's viewport, a method is called that scrolls to the value where the row is so it can be seen, but it fails to do so. It only scrolls to the "top" of the row. I think I found the origin of the error but I don't know how to solve it. It may be related to the range of the scroll area being updated after the method that shows the selected row is executed. So, if it scrolls to the maximum, it will scroll to the old maximum, before it's value was updated. I do not want to hard code the new maximum value, but I can't seem to find a solution.
        Here I provide to images to illustrate how it should behave vs how it's currently behaving when a new row is added.

        1 - How it should behave:

        foto2.png

        2 - How it behaves:

        foto1.png

        Here is the code that is in charge of showing the row:

        void blanqueo::showRow()
        {
            // Get the position of the frame within the scroll area
            QPoint frameInScrollArea = actualRow->mapTo(ui->scrollArea, QPoint(0, 0));
        
            // Calculate the position of the custom object within the scroll area
            QPoint rowPosInScrollArea = frameInScrollArea + actualRow->getActualPoint();
        
            // Get the y-coordinate of the top edge of the custom object
            int yTop = rowPosInScrollArea.y();
        
            // Get the height of the scroll area viewport
            int viewportHeight = ui->scrollArea->viewport()->height();
        
            // Get the current scrollbar value and range
            QScrollBar* scrollbar = ui->scrollArea->verticalScrollBar();
            int currentValue = scrollbar->value();
            int maximumValue = scrollbar->maximum();
        
            // Only adjust the scrollbar value if the selected row is not currently visible
            if (yTop < currentValue || yTop > currentValue + viewportHeight) {
                // Calculate the new scrollbar value that will make the selected row fully visible
                int newValue = qMax(yTop - viewportHeight / 2, 0);
                newValue = qMin(newValue, maximumValue);
        
                // Set the new scrollbar value
        //        scrollbar->setValue(newValue);
                scrollbar->setSliderPosition(newValue);
            }
        
            changeButtonStyle(actualRow->isActualScanned());
            ui->currentTubeLabel->setText( insertTubeText.arg( actualRow->getActualTube() ) );
        }
        

        And this is the method getActualPoint() used:

        QPoint noProtocolBlanqSpec::getActualPoint()
        { // Get position of row in QFrame and add row height
            QPoint rowPosInFrame = br->mapTo(ui->frame, QPoint(0, 0)) + QPoint(0, getActualHeight() );
            qDebug() << rowPosInFrame << getActualHeight();
            return rowPosInFrame;
        }
        

        I'm open to suggestions on how to implement this, because I've seen strange behavior under certain scenarios, which I have fixed by not calling it when the user selects a Row manually, because that would mean they can already see it.

        I hope it's not that confusing, feel free to ask any questions.

        Thank you all in advance.

        M Offline
        M Offline
        mpergand
        wrote on last edited by
        #2

        @superg
        Have you tried this method :
        *void QScrollArea::ensureWidgetVisible(QWidget childWidget, int xmargin = 50, int ymargin = 50)
        Scrolls the contents of the scroll area so that the childWidget of QScrollArea::widget() is visible inside the viewport with margins specified in pixels by xmargin and ymargin. If the specified point cannot be reached, the contents are scrolled to the nearest valid position. The default value for both margins is 50 pixels.

        supergS 1 Reply Last reply
        1
        • M mpergand

          @superg
          Have you tried this method :
          *void QScrollArea::ensureWidgetVisible(QWidget childWidget, int xmargin = 50, int ymargin = 50)
          Scrolls the contents of the scroll area so that the childWidget of QScrollArea::widget() is visible inside the viewport with margins specified in pixels by xmargin and ymargin. If the specified point cannot be reached, the contents are scrolled to the nearest valid position. The default value for both margins is 50 pixels.

          supergS Offline
          supergS Offline
          superg
          wrote on last edited by superg
          #3

          @mpergand Thank you for your answer. Yes, I've tried it, but it doesn't work because the widget is not a direct child of the scroll area. It's the child of a QFrame, that is a child of the QScrollArea.

          JoeCFDJ 1 Reply Last reply
          0
          • supergS superg

            @mpergand Thank you for your answer. Yes, I've tried it, but it doesn't work because the widget is not a direct child of the scroll area. It's the child of a QFrame, that is a child of the QScrollArea.

            JoeCFDJ Offline
            JoeCFDJ Offline
            JoeCFD
            wrote on last edited by
            #4

            @superg
            from here
            https://forum.qt.io/topic/33261/solved-how-to-set-a-scrollbar-to-scroll-down-automatically/3
            scrollArea->verticalScrollBar()->setValue( scrollArea->verticalScrollBar()->maximum());

            supergS 1 Reply Last reply
            0
            • supergS superg

              Hello,
              I'm having a problem with a QScrollArea. What I'm doing is add an object that contains a QFrame to the QScrollArea. This object will store a variable number of other objects that function as rows that have some funcionalities.
              The problem seems very simple: When adding rows to the scroll area to a point that the new row added it's below it's viewport, a method is called that scrolls to the value where the row is so it can be seen, but it fails to do so. It only scrolls to the "top" of the row. I think I found the origin of the error but I don't know how to solve it. It may be related to the range of the scroll area being updated after the method that shows the selected row is executed. So, if it scrolls to the maximum, it will scroll to the old maximum, before it's value was updated. I do not want to hard code the new maximum value, but I can't seem to find a solution.
              Here I provide to images to illustrate how it should behave vs how it's currently behaving when a new row is added.

              1 - How it should behave:

              foto2.png

              2 - How it behaves:

              foto1.png

              Here is the code that is in charge of showing the row:

              void blanqueo::showRow()
              {
                  // Get the position of the frame within the scroll area
                  QPoint frameInScrollArea = actualRow->mapTo(ui->scrollArea, QPoint(0, 0));
              
                  // Calculate the position of the custom object within the scroll area
                  QPoint rowPosInScrollArea = frameInScrollArea + actualRow->getActualPoint();
              
                  // Get the y-coordinate of the top edge of the custom object
                  int yTop = rowPosInScrollArea.y();
              
                  // Get the height of the scroll area viewport
                  int viewportHeight = ui->scrollArea->viewport()->height();
              
                  // Get the current scrollbar value and range
                  QScrollBar* scrollbar = ui->scrollArea->verticalScrollBar();
                  int currentValue = scrollbar->value();
                  int maximumValue = scrollbar->maximum();
              
                  // Only adjust the scrollbar value if the selected row is not currently visible
                  if (yTop < currentValue || yTop > currentValue + viewportHeight) {
                      // Calculate the new scrollbar value that will make the selected row fully visible
                      int newValue = qMax(yTop - viewportHeight / 2, 0);
                      newValue = qMin(newValue, maximumValue);
              
                      // Set the new scrollbar value
              //        scrollbar->setValue(newValue);
                      scrollbar->setSliderPosition(newValue);
                  }
              
                  changeButtonStyle(actualRow->isActualScanned());
                  ui->currentTubeLabel->setText( insertTubeText.arg( actualRow->getActualTube() ) );
              }
              

              And this is the method getActualPoint() used:

              QPoint noProtocolBlanqSpec::getActualPoint()
              { // Get position of row in QFrame and add row height
                  QPoint rowPosInFrame = br->mapTo(ui->frame, QPoint(0, 0)) + QPoint(0, getActualHeight() );
                  qDebug() << rowPosInFrame << getActualHeight();
                  return rowPosInFrame;
              }
              

              I'm open to suggestions on how to implement this, because I've seen strange behavior under certain scenarios, which I have fixed by not calling it when the user selects a Row manually, because that would mean they can already see it.

              I hope it's not that confusing, feel free to ask any questions.

              Thank you all in advance.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by JonB
              #5

              @superg said in Problem with scrolling in QScrollArea:

              a method is called that scrolls to the value where the row is so it can be seen, but it fails to do so. It only scrolls to the "top" of the row. I think I found the origin of the error but I don't know how to solve it. It may be related to the range of the scroll area being updated after the method that shows the selected row is executed. So, if it scrolls to the maximum, it will scroll to the old maximum, before it's value was updated.

              This could indeed be a part of the problem.

              Either sort it out, or: maybe you can put the "scroll to visible" code into a QTimer::singleShot(0, ...) call? That delays it till after whatever updating is now going on has taken effect.

              Otherwise if the "scroll till visible" code really only makes the top of the item visible at the bottom of the pane you could then scroll down by the height of an item.

              supergS 1 Reply Last reply
              0
              • JoeCFDJ JoeCFD

                @superg
                from here
                https://forum.qt.io/topic/33261/solved-how-to-set-a-scrollbar-to-scroll-down-automatically/3
                scrollArea->verticalScrollBar()->setValue( scrollArea->verticalScrollBar()->maximum());

                supergS Offline
                supergS Offline
                superg
                wrote on last edited by
                #6

                @JoeCFD Thanks. But this does not work, due to the fact that the scroll area hasn't updated it's maximum value yet!

                1 Reply Last reply
                0
                • JonBJ JonB

                  @superg said in Problem with scrolling in QScrollArea:

                  a method is called that scrolls to the value where the row is so it can be seen, but it fails to do so. It only scrolls to the "top" of the row. I think I found the origin of the error but I don't know how to solve it. It may be related to the range of the scroll area being updated after the method that shows the selected row is executed. So, if it scrolls to the maximum, it will scroll to the old maximum, before it's value was updated.

                  This could indeed be a part of the problem.

                  Either sort it out, or: maybe you can put the "scroll to visible" code into a QTimer::singleShot(0, ...) call? That delays it till after whatever updating is now going on has taken effect.

                  Otherwise if the "scroll till visible" code really only makes the top of the item visible at the bottom of the pane you could then scroll down by the height of an item.

                  supergS Offline
                  supergS Offline
                  superg
                  wrote on last edited by
                  #7

                  @JonB Thank you! I tried QTimer::singleShot(0, ...) and it kind of worked, but still I found that my code had several problems. I have decided to do some refactoring so that I'll be easier to make this and other functionalities work better and easier. I was trying to avoid that but seems like it's the only way. Thanks again for your help, I'll mark it as a solution.

                  1 Reply Last reply
                  0
                  • supergS superg 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