[SOLVED] How to place widgets in margins of a QSrollArea (or QAbstractScrollArea)?



  • This is probably simple, but I am stumped. I need to place rulers in the top and bottom margins of a scroll area. I have no problem with the top margin, but I cannot figure out how to get a widget placed in the bottom margin. I have tried using both QGridLayout and QVBoxLayout, but the bottom ruler end up near the middle of the ScrollArea viewport, not in the bottom margin?

    Here is some sample code:

    @
    #include "mainwindow.h"
    #include "ui_mainwindow.h"

    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    scrollArea = new ScrollAreaWithRulers(this);
    setCentralWidget(scrollArea);
    canvas = new Canvas();
    scrollArea->setWidget(canvas);
    scrollArea->addRulers();
    }@

    and:

    @#include "rulerscrollarea.h"

    ScrollAreaWithRulers::ScrollAreaWithRulers(QWidget *parent) :
    QScrollArea(parent)
    {
    setViewportMargins(0,30,0,30);
    topRuler = new Ruler();
    bottomRuler = new Ruler();
    }

    void ScrollAreaWithRulers::addRulers(){

    QVBoxLayout *layout = new QVBoxLayout();
    
    layout->addWidget(topRuler);
    layout->addWidget(viewport());
    layout->addWidget(bottomRuler);
    //layout->setRowStretch(1,1);
    
    setLayout(layout);
    

    }
    @

    The documentation for QAbstractScrollArea implies that this should be easier when it says:

    bq. Sets the margins around the scrolling area to left, top, right and bottom. This is useful for applications such as spreadsheets with "locked" rows and columns. The marginal space is is left blank; put widgets in the unused area.

    So, what is the right way to "put widgets in the unused area"? I am missing something obvious here.



  • You have to position them manually and use the scroll area's resizeEvent()/scrollContentsBy() to adjust the placement as required. Take a look at the Code Editor Example, specifically CodeEditor::resizeEvent().
    http://qt-project.org/doc/qt-4.8/widgets-codeeditor.html



  • @ChrisW67

    Thanks for the example to look at... I had pretty much arrived at the conclusion that I would have to do it manually by looking at the code for QTableView... but the CodeEditor example is easier to parse!

    Glenn



  • Ok, in trying to follow the example of the "code editor" demo, I am now stumped by the refusal of a widget in the margin to move in response to its "scroll" method. Thinking that the problem might be with my ruler widget, I substituted a simple QLabel widget with the same result. The code is as follows:

    @#include "rulerscrollarea.h"

    RulerScrollArea::RulerScrollArea(QWidget *parent) :
    QScrollArea(parent)
    {
    setViewportMargins(80,30,0,0);
    //topRuler = new Ruler(this);
    label = new QLabel("Hello World",this);
    }

    void RulerScrollArea::scrollContentsBy(int dx, int dy){
    label->scroll(dx,0);
    QScrollArea::scrollContentsBy(dx,dy);
    std::cerr << "we're scrolling along \n";
    }

    void RulerScrollArea::resizeEvent(QResizeEvent *evt){
    QScrollArea::resizeEvent(evt);
    }
    @

    If I replace "scroll" with "move", the widget moves! This code works:

    @#include "rulerscrollarea.h"

    RulerScrollArea::RulerScrollArea(QWidget *parent) :
    QScrollArea(parent)
    {
    setViewportMargins(80,30,0,0);
    //topRuler = new Ruler(this);
    label = new QLabel("Hello World",this);
    rulerX = 0;
    }

    void RulerScrollArea::scrollContentsBy(int dx, int dy){
    //label->scroll(dx,0);
    rulerX += dx;
    label->move(rulerX,0);
    QScrollArea::scrollContentsBy(dx,dy);
    std::cerr << "we're scrolling along \n";
    }

    void RulerScrollArea::resizeEvent(QResizeEvent *evt){
    QScrollArea::resizeEvent(evt);
    }
    @

    So why won't these widgets respond to a scroll request?



  • [quote author="ChrisW67" date="1353999614"]You have to position them manually[/quote]You can actually use a QLayout, because QScrollArea isn't using any. You have to specify the alignment to the addWidget function:
    @QVBoxLayout *layout = new QVBoxLayout(this);
    // to remove any margin around the layout
    layout->setContentsMargins(QMargins());
    layout->addWidget(topRuler, 0, Qt::AlignTop);
    layout->addWidget(bottomRuler, 0, Qt::AlignBottom);
    @
    I guess you wouldn't have to handle the resize event any more, only the scrolling.



  • @alexisdm:

    Thanks... that does indeed fix the top and bottom... but the scroll method still doesn't move the widgets. I have to use the move method? Very puzzling. I can work around it with move, but would love to know why the scroll method works in the code editor example, but not here. BTW, I have tried it on both Windows and Mac OS with same results.



  • QWidget::scroll doesn't move the widget (although it might move the child widgets, I think), it allows you to optimize the painting of a widget that displays a scrollable content by copying the already painted part to the new position, and calling the paintEvent function only for the part that was just made visible by the scrolling.

    I wasn't sure of that so I wrote a simple example code to test it:
    @class Ruler : public QWidget
    {
    public:
    explicit Ruler(QWidget *parent = 0) : QWidget(parent)
    {
    // Without the following line QWidget would draw a background first
    // And redraw the whole widget each time it scrolls
    setAttribute(Qt::WA_OpaquePaintEvent);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    }

    QSize sizeHint() const {
        return QSize(30, 30);
    }
    
    void paintEvent(QPaintEvent *evt)
    {
        QPainter painter(this);
        painter.fillRect(evt->rect(), QColor(qrand()%5, qrand()%5, qrand()%5));    
    }
    

    };
    @



  • Aha.. that makes sense... the documentation of the scroll method is clearly not robust! I will propose an improvement in the documentation.

    Thanks Alexis!

    Glenn



  • I have solved all of my problems by directly placing widgets in the scroll frame rather than trying to use layouts... works great


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.