QLabel showing an image inside a QScrollArea

2019-04-29 19:42发布

I've successfully implemented a Image Viewer (for DICOM) in Qt. I can see the image and I can zoom in and out correctly.

Now, I want to see scroll bars if the image is too big to show when I zoom in.

I've used the UI. I placed a QScrollArea. Inside, the QLabel. The verticalScrollBarPolicy is ScrollBarAsNeeded. The horizontalScrollBarPolicy is ScrollBarAsNeeded.

The problem is: it doesn't work. I zoom in, but no scrollbar appears.

Second try: using a layout inside the QScrollArea.

So now there's a QWidget between the QScrollArea and the QLabel: a horizontal layout. Opened the same image, now I can see a vertical scroll bar on the right. The image is streched from left to right. When I zoom the image gets its correct proportion.

BUT... I zoom out and the scroll bar is the same, even if I can see the whole image. The horizontal scroll bar never appears.

Resizing the QLabel doesn't seem to affect. But if I resize the QScrollArea (resizing the main window) the horizontal scroll bar appears.

I've been checking some numbers:

In the QScrollArea

  • Its size changes: below 599 width (why this number? I can't see it anywhere) the horizontal bar appears.
  • sizeHint() always returns the same values: 33x41

In the QLabel

  • The dimensions change, but that doesn't affect.
  • sizeHint() always returns the same values: 560x1558

Here is the code in XML from the UI designer:

<widget class="QWidget" name="centralWidget">
   <property name="autoFillBackground">
    <bool>false</bool>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <property name="margin">
     <number>0</number>
    </property>
    <item>
     <widget class="QScrollArea" name="scrollArea">
      <property name="widgetResizable">
       <bool>true</bool>
      </property>
      <property name="alignment">
       <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
      </property>
      <widget class="QWidget" name="scrollAreaWidgetContents">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>637</width>
         <height>649</height>
        </rect>
       </property>
       <layout class="QHBoxLayout" name="horizontalLayout_2">
        <item>
         <widget class="QLabel" name="miImagen">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="autoFillBackground">
           <bool>true</bool>
          </property>
          <property name="scaledContents">
           <bool>true</bool>
          </property>
          <property name="alignment">
           <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
          </property>
         </widget>
        </item>
       </layout>
      </widget>
     </widget>
    </item>
   </layout>
  </widget>

What am I missing? Thank you.

2条回答
叼着烟拽天下
2楼-- · 2019-04-29 20:21

Have you tried following Qt's scroll area example? If you're using a QLabel to display your image, then the use of QScrollArea is pretty much the standard way of achieving what you want. You use it like so (from the example):

 imageLabel = new QLabel;
 imageLabel->setBackgroundRole(QPalette::Base);
 imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
 imageLabel->setScaledContents(true);

 scrollArea = new QScrollArea;
 scrollArea->setBackgroundRole(QPalette::Dark);
 scrollArea->setWidget(imageLabel);
 setCentralWidget(scrollArea);

Then zooming is handled like so:

 void ImageViewer::zoomIn() { 
    scaleImage(1.25);
 }

 void ImageViewer::zoomOut() {
     scaleImage(0.8);
 }

 void ImageViewer::scaleImage(double factor)
 {
     Q_ASSERT(imageLabel->pixmap());
     scaleFactor *= factor;
     imageLabel->resize(scaleFactor * imageLabel->pixmap()->size());

     adjustScrollBar(scrollArea->horizontalScrollBar(), factor);
     adjustScrollBar(scrollArea->verticalScrollBar(), factor);

     zoomInAct->setEnabled(scaleFactor < 3.0);
     zoomOutAct->setEnabled(scaleFactor > 0.333);
 }

 void ImageViewer::adjustScrollBar(QScrollBar *scrollBar, double factor) {
     scrollBar->setValue(int(factor * scrollBar->value()
                         + ((factor - 1) * scrollBar->pageStep()/2)));
 }

You can, of course, get a better idea of what's going on by looking at the example, but that's the gist of it. I think perhaps the adjustScrollBar() function might be the most helpful thing for you.

Your last comment on the original post is correct, the QScrollArea doesn't magically notice the change in size of its contents. Look at how the example uses adjustScrollBar() to compensate for this fact.

查看更多
走好不送
3楼-- · 2019-04-29 20:28

I know this is an old post - but in case you or anyone is still having a problem, it might help to set QScrollArea::widgetResizable to false.

At least, when I tried a similar thing, my vertical scrollbar was always disabled (even though I set the size of the scrollable widget to have a height larger than the viewport) until I set this to false.

When it's true, I think it updates the size of the scrollable widget, thus the scrollbars should not be needed. This allows you to do what it does in the example I guess, and implement a stretch-to-fit function. (actually what I'm trying to do is fit to width, with just a vertical scroll bar)

查看更多
登录 后发表回答