2016-05-23 29 views
0

我正在开发一个PyQt5应用程序,该应用程序需要在顶部有一个横幅。横幅只是一个宽的图像,其宽度应该始终是窗口的宽度,并且其高度应该是固定的比例。换句话说,横幅图像的高度应该取决于窗口的宽度。横幅下面的小部件(主要内容)应该伸展以填充所有可用的垂直空间。如何使窗口小部件的高度与其宽度成一定比例

我基本上移植this SO answer到PyQt5:

class Banner(QWidget): 

    def __init__(self, parent): 
     super(Banner, self).__init__(parent) 

     self.setContentsMargins(0, 0, 0, 0) 

     pixmap = QPixmap('banner-1071797_960_720.jpg') # see note below 

     self._label = QLabel(self) 
     self._label.setPixmap(pixmap) 
     self._label.setScaledContents(True) 
     self._label.setFixedSize(0, 0) 
     self._label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 

     self._resizeImage() 

    def resizeEvent(self, event): 
     super(Banner, self).resizeEvent(event) 
     self._resizeImage() 

    def _resizeImage(self): 
     pixSize = self._label.pixmap().size() 
     pixSize.scale(self.size(), Qt.KeepAspectRatio) 
     self._label.setFixedSize(pixSize) 

(在这个例子中,我使用this免费旗帜的形象,但没有什么特别的地方。)

我已经把旗帜在下面的应用程序代码,其中,一个标签用作用于主要内容的占位符:

if __name__ == '__main__': 

    app = QApplication(sys.argv) 

    widget = QWidget() 
    widget.setContentsMargins(0, 0, 0, 0) 
    layout = QVBoxLayout(widget) 

    banner = Banner(widget) 
    bannerSizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) 
    bannerSizePolicy.setHeightForWidth(True) 
    banner.setSizePolicy(bannerSizePolicy) 
    layout.addWidget(banner) 

    label = QLabel('There should be a banner above') 
    label.setStyleSheet('QLabel { background-color: grey; color: white; }'); 
    layout.addWidget(label) 
    layout.setStretch(0, 1) 

    widget.resize(320, 200) 
    widget.move(320, 200) 
    widget.setWindowTitle('Banner Tester') 
    widget.show() 

    sys.exit(app.exec_()) 

的问题是,标签填充的100%窗口 - 横幅根本不可见。

我已经尝试了许多不同尺寸的政策和拉伸因素,并完全删除尺寸政策,但还没有找到如何去做我所需要的。横幅中的图像应按比例缩放以适合窗口的宽度,并且标签应填充窗口中剩余的垂直空间。

想法?

+1

您的小部件实现是不完整的,所以它不能正常工作与布局。你需要适当地实现'hasHeightForWidth';见例如[这个答案](http://stackoverflow.com/a/18923122/1329652)。 –

回答

0

@ kuba-ober的评论是正确的:我必须在Banner类中实现hasHeightForWidth()heightForWidth()

这是修改的代码,它以我想要的方式工作。所有的修改在代码中都有注释。

class Banner(QWidget): 

    def __init__(self, parent): 
     super(Banner, self).__init__(parent) 

     self.setContentsMargins(0, 0, 0, 0) 

     pixmap = QPixmap('banner-1071797_960_720.jpg') 

     # First, we note the correct proportion for the pixmap 
     pixmapSize = pixmap.size() 
     self._heightForWidthFactor = 1.0 * pixmapSize.height()/pixmapSize.width() 

     self._label = QLabel('pixmap', self) 
     self._label.setPixmap(pixmap) 
     self._label.setScaledContents(True) 
     self._label.setFixedSize(0, 0) 
     self._label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 

     self._resizeImage(self.size()) 

    def hasHeightForWidth(self): 
     # This tells the layout manager that the banner's height does depend on its width 
     return True 

    def heightForWidth(self, width): 
     # This tells the layout manager what the preferred and minimum height are, for a given width 
     return math.ceil(width * self._heightForWidthFactor) 

    def resizeEvent(self, event): 
     super(Banner, self).resizeEvent(event) 
     # For efficiency, we pass the size from the event to _resizeImage() 
     self._resizeImage(event.size()) 

    def _resizeImage(self, size): 
     # Since we're keeping _heightForWidthFactor, we can code a more efficient implementation of this, too 
     width = size.width() 
     height = self.heightForWidth(width) 
     self._label.setFixedSize(width, height) 

if __name__ == '__main__': 

    app = QApplication(sys.argv) 

    widget = QWidget() 
    widget.setContentsMargins(0, 0, 0, 0) 
    layout = QVBoxLayout(widget) 

    banner = Banner(widget) 
    # Turns out we don't need the bannerSizePolicy now 
# bannerSizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) 
# bannerSizePolicy.setHeightForWidth(True) 
# banner.setSizePolicy(bannerSizePolicy) 
    layout.addWidget(banner) 

    label = QLabel('There should be a banner above') 
    label.setStyleSheet("QLabel { background-color: grey; color: white; }"); 
    layout.addWidget(label) 
    layout.setStretch(1, 1) 

    widget.resize(320, 200) 
    widget.move(320, 200) 
    widget.setWindowTitle('Banner Tester') 
    widget.show() 

    sys.exit(app.exec_()) 
相关问题