PyQt5:QScrollArea保持Pixmap宽高比

时间:2018-12-24 13:47:21

标签: python pyqt pyqt5 qpixmap qscrollarea

我基于https://stackoverflow.com/a/2714554/6859682使用QAbstractButton创建了一组像素映射按钮(PicButton),并希望将它们添加到滚动区域中,以便用户可以水平滚动。但是,我需要

  1. 像素图按钮的长宽比保持恒定
  2. 像素图按钮应始终占据窗口的整个高度,最大不超过200像素。

我当前代码的问题是,高度过高时,像素图按钮会受到挤压。

当高度足够小以使所有按钮都适合窗口时,我能够使纵横比保持恒定。我在下面附加我的PicButton类。

from PyQt5 import QtCore, QtGui, QtWidgets

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QPainter, QPen

def testPixmap(r = 255,g = 0,b = 0, a = 255,size =(200,200)):
    px = QtGui.QPixmap(size[0],size[1])
    color = QtGui.QColor(r,g,b,a)
    px.fill(color) 
    return px

class PicButton(QtWidgets.QAbstractButton):
    checked = QtCore.pyqtSignal(object, QtCore.QRect)
    def __init__(self, name, parent=None, w = 200, h = 200):
        self.w = w; self.h = h;  self.name = name
        super(PicButton, self).__init__(parent)
        pixmap = testPixmap(255,0,0)
        self.resetPixmaps(pixmap); self.pixmap = pixmap
        self.setCheckable(True);   self.setChecked(False)
        self.pressed.connect(self.update)
        self.released.connect(self.blank)

    def resetPixmaps(self, pixmap):
        self.pixmap_hover = testPixmap(20,125,200,128)
        self.pixmap_pressed = testPixmap(30,180,200,128)

    def blank(self):
        self.setChecked(True)    

    def paintEvent(self, event):        
        pix = self.pixmap_hover if self.underMouse() else self.pixmap        
        if self.isChecked():
            self.checked.emit( self.name, event.rect())    
            pix = self.pixmap_pressed
        size = self.size()        
        scaledPix = pix.scaledToHeight(size.height(), Qt.SmoothTransformation)
        # start painting the label from left upper corner
        point = QtCore.QPoint(0,0)
        point.setX((size.width() - scaledPix.width())/2)
        point.setY((size.height() - scaledPix.height())/2)

        painter = QPainter(self)

        painter.drawPixmap(point, scaledPix)

    def otherBoxChecked(self, func, rect):
        if self.isChecked():
            pix = self.pixmap; painter = QPainter(self); painter.drawPixmap(rect, pix)
            self.setChecked(False)            

    def enterEvent(self, event):
        self.update()

    def leaveEvent(self, event):
        self.update()

    def sizeHint(self):
        return QtCore.QSize(self.w, self.h)

在所有按钮都不能容纳高度的情况下,我想激活滚动条并保持按钮的长宽比。有关如何执行此操作的任何想法?我附上下面的窗口代码以确保完整性 Issue

class Window(QtWidgets.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        buttons = ['str(i)' for i in range(10)]
        HB2layout = QtWidgets.QHBoxLayout()
        self.maskButtons = [PicButton(button) for button in buttons]
        for maskButton, mb in zip(self.maskButtons, range(len(self.maskButtons))):
            for maskConnect, mc in zip(self.maskButtons, range(len(self.maskButtons))):
                if mb!=mc:
                    maskButton.checked.connect(maskConnect.otherBoxChecked)

        for button in self.maskButtons:
            HB2layout.addWidget(button) 
        self.scrollArea = QtWidgets.QScrollArea(self)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scrollArea.setMaximumHeight(200)
        self.scrollArea.setLayout(HB2layout)
        self.scrollArea.show()
        Vlayout = QtWidgets.QVBoxLayout(self)
        Vlayout.addWidget(self.scrollArea)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 800, 200)
    window.show()
    sys.exit(app.exec_())

1 个答案:

答案 0 :(得分:1)

已添加

from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QPainter, QPen




def testPixmap(r = 255,g = 0,b = 0, a = 255,size =(200,200)):
    px = QtGui.QPixmap(size[0],size[1])
    color = QtGui.QColor(r,g,b,a)
    px.fill(color) 
    return px



class PicButton(QtWidgets.QAbstractButton):
    checked = QtCore.pyqtSignal(object, QtCore.QRect)
    def __init__(self, name, parent=None, w = 200, h = 200):
        self.w = w; self.h = h;  self.name = name
        super(PicButton, self).__init__(parent)
        pixmap = testPixmap(255,0,0)
        self.resetPixmaps(pixmap); self.pixmap = pixmap
        self.setCheckable(True);   self.setChecked(False)
        self.pressed.connect(self.update)
        self.released.connect(self.blank)

    def resetPixmaps(self, pixmap):
        self.pixmap_hover = testPixmap(20,125,200,128)
        self.pixmap_pressed = testPixmap(30,180,200,128)

    def blank(self):
        self.setChecked(True)    

    def paintEvent(self, event):        
        pix = self.pixmap_hover if self.underMouse() else self.pixmap        
        if self.isChecked():
            self.checked.emit( self.name, event.rect())    
            pix = self.pixmap_pressed
        size = self.size()        
        scaledPix = pix.scaledToHeight(size.height(), Qt.SmoothTransformation)
        # start painting the label from left upper corner
        point = QtCore.QPoint(0,0)
        point.setX((size.width() - scaledPix.width())/2)
        point.setY((size.height() - scaledPix.height())/2)

        painter = QPainter(self)

        painter.drawPixmap(point, scaledPix)

    def otherBoxChecked(self, func, rect):
        if self.isChecked():
            pix = self.pixmap; painter = QPainter(self); painter.drawPixmap(rect, pix)
            self.setChecked(False)            

    def enterEvent(self, event):
        self.update()

    def leaveEvent(self, event):
        self.update()

    def sizeHint(self):
        return QtCore.QSize(self.w, self.h)


class View(QtWidgets.QGraphicsView):
    def __init__(self):
        super(View,self).__init__()        
        self.pic_scene = QtWidgets.QGraphicsScene()
        self.neighborhood = 200
        buttons = ['str(i)' for i in range(10)]

        self.maskButtons = [PicButton(button) for button in buttons]
        for maskButton, mb in zip(self.maskButtons , range(len(self.maskButtons ))):
            for maskConnect, mc in zip(self.maskButtons , range(len(self.maskButtons ))):
                if mb!=mc:
                    maskButton.checked.connect(maskConnect.otherBoxChecked)

        self.pic_scene.setSceneRect(0,0,10000,200)
        for i,item in enumerate(self.maskButtons ):
            item.setGeometry(self.neighborhood*i,item.geometry().y(),item.geometry().width(),item.geometry().height())            
            self.pic_scene.addWidget(item)

        self.setScene(self.pic_scene)
        self.setMaximumHeight(200)
        self.setGeometry(500,500,5000,200)
    def paintEvent(self,event):
        for k,i in enumerate(self.maskButtons ):

            rect = i.geometry()         
            #eventually,width = height
            rect.setSize(QtCore.QSize(self.height(),self.height()))   
            self.neighborhood = self.height()               
            rect.setX(self.height()*k)
            rect.setY(rect.y())
            i.setGeometry(rect)   
            self.pic_scene.addWidget(i)     
        return QtWidgets.QGraphicsView.paintEvent(self,event)



if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = View()
    window.setGeometry(500, 300, 800, 200)   
    window.show()
    sys.exit(app.exec_())

很抱歉没有一次填写您想要的答案。

QAbstractButton版本

是的,我没有使用QAbstractButton,这已经挂在我头上了。 这是QAbstractButton版本。您将能够自定义所需的按钮。

从PyQt5导入QtCore,QtGui,QtWidgets

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QPainter, QPen

class PicButton(QtWidgets.QAbstractButton):
    def __init__(self,x=0,y=0,width=200,height=200):
        super(PicButton,self).__init__()
        self.setGeometry(x,y,width,height)

    def paintEvent(self,event):        
        painter = QtGui.QPainter()
        if not painter.isActive():
            painter.begin(self)
        brush = QtGui.QBrush()     
        brush.setColor(QtGui.QColor(Qt.red))
        brush.setStyle(Qt.SolidPattern)        
        painter.setBrush(brush)
        painter.drawRect(QtCore.QRect(0,0,200,200))
        painter.end()


class View(QtWidgets.QGraphicsView):
    def __init__(self):
        super(View,self).__init__()        
        self.pic_scene = QtWidgets.QGraphicsScene()
        self.neighborhood = 200
        self.rect_items = [PicButton() for i in range(10)]
        self.pic_scene.setSceneRect(0,0,10000,200)
        for i,item in enumerate(self.rect_items):
            item.setGeometry(self.neighborhood*i,item.geometry().y(),item.geometry().width(),item.geometry().height())            
            self.pic_scene.addWidget(item)

        self.setScene(self.pic_scene)
        self.setMaximumHeight(200)
        self.setGeometry(500,500,5000,200)
    def paintEvent(self,event):
        for k,i in enumerate(self.rect_items):

            rect = i.geometry()         
            #eventually,width = height
            rect.setSize(QtCore.QSize(self.height(),self.height()))   
            self.neighborhood = self.height()               
            rect.setX(self.height()*k)
            rect.setY(rect.y())
            i.setGeometry(rect)   
            self.pic_scene.addWidget(i)     
        return QtWidgets.QGraphicsView.paintEvent(self,event)



if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = View()
    window.setGeometry(500, 300, 800, 200)   
    window.show()
    sys.exit(app.exec_())

因为我接受了评论,所以我尝试阐述QGraphicsView和QGraphicsScene的场合。

但这只是结果。此代码可能不受欢迎。 无论如何,我希望您执行此代码。 希望你喜欢。

如果您想了解详细信息,请写评论。

from PyQt5 import QtCore, QtGui, QtWidgets

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QPainter, QPen

class PicRectItem(QtWidgets.QGraphicsRectItem):
    def __init__(self,x=0,y=0,width=200,height=200):
        super(PicRectItem,self).__init__()
        self.setRect(x,y,width,height)
        brush = QtGui.QBrush()        
        brush.setColor(QtGui.QColor(Qt.red))
        brush.setStyle(Qt.SolidPattern)        
        self.setBrush(brush)
class View(QtWidgets.QGraphicsView):
    def __init__(self):
        super(View,self).__init__()        
        self.pic_scene = QtWidgets.QGraphicsScene()
        self.neighborhood = 200
        self.rect_items = [PicRectItem() for i in range(10)]
        for i,item in enumerate(self.rect_items):
            item.setRect(self.neighborhood*i,item.y(),item.rect().width(),item.rect().height())
        for i in self.rect_items:
            self.pic_scene.addItem(i)
        self.setScene(self.pic_scene)
        self.setMaximumHeight(200)
    def paintEvent(self,event):
        for k,i in enumerate(self.rect_items):
            rect = i.rect()
            #eventually,width = height
            rect.setSize(QtCore.QSizeF(self.height(),self.height()))   
            self.neighborhood = self.height()               
            i.setRect(rect)                 
            self.pic_scene.addItem(i)           
            rect = i.rect()
            rect.setX(self.height()*k)
            rect.setY(rect.y())
            i.setRect(rect)        
        return QtWidgets.QGraphicsView.paintEvent(self,event)



if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    window = View()
    window.setGeometry(500, 300, 800, 200)   
    window.show()
    sys.exit(app.exec_())

上一个

我不确定您想要什么,您要这样做吗? 如果不是,我将删除此答案或重写。

from PyQt5 import QtCore, QtGui, QtWidgets

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QPainter, QPen

def testPixmap(r = 255,g = 0,b = 0, a = 255,size =(200,200)):
    px = QtGui.QPixmap(size[0],size[1])
    color = QtGui.QColor(r,g,b,a)
    px.fill(color) 
    return px

class PicButton(QtWidgets.QAbstractButton):
    checked = QtCore.pyqtSignal(object, QtCore.QRect)
    def __init__(self, name, parent=None, w = 200, h = 200):
        self.w = w; self.h = h;  self.name = name
        super(PicButton, self).__init__(parent)
        pixmap = testPixmap(255,0,0)
        self.resetPixmaps(pixmap); self.pixmap = pixmap
        self.setCheckable(True);   self.setChecked(False)
        self.pressed.connect(self.update)
        self.released.connect(self.blank)

    def resetPixmaps(self, pixmap):
        self.pixmap_hover = testPixmap(20,125,200,128)
        self.pixmap_pressed = testPixmap(30,180,200,128)

    def blank(self):
        self.setChecked(True)    

    def paintEvent(self, event):        
        pix = self.pixmap_hover if self.underMouse() else self.pixmap        
        if self.isChecked():
            self.checked.emit( self.name, event.rect())    
            pix = self.pixmap_pressed
        size = self.size()        
        scaledPix = pix.scaledToHeight(size.height(), Qt.SmoothTransformation)
        # start painting the label from left upper corner
        point = QtCore.QPoint(0,0)
        point.setX((size.width() - scaledPix.width())/2)
        point.setY((size.height() - scaledPix.height())/2)

        painter = QPainter(self)

        painter.drawPixmap(point, scaledPix)

    def otherBoxChecked(self, func, rect):
        if self.isChecked():
            pix = self.pixmap; painter = QPainter(self); painter.drawPixmap(rect, pix)
            self.setChecked(False)            

    def enterEvent(self, event):
        self.update()

    def leaveEvent(self, event):
        self.update()

    def sizeHint(self):
        return QtCore.QSize(self.w, self.h)
class Window(QtWidgets.QWidget):
    def __init__(self):
        super(Window, self).__init__()

        buttons = ['str(i)' for i in range(10)]
        HB2layout = QtWidgets.QHBoxLayout()

        self.maskButtons = [PicButton(button) for button in buttons]
        for maskButton, mb in zip(self.maskButtons, range(len(self.maskButtons))):
            for maskConnect, mc in zip(self.maskButtons, range(len(self.maskButtons))):
                if mb!=mc:
                    maskButton.checked.connect(maskConnect.otherBoxChecked)

        for button in self.maskButtons:
            HB2layout.addWidget(button) 
        self.scrollChildArea = QtWidgets.QWidget()
        self.scrollChildArea.setLayout(HB2layout)
        self.scrollArea = QtWidgets.QScrollArea()
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scrollArea.setMaximumHeight(200)

        self.scrollArea.setWidget(self.scrollChildArea)
        self.scrollArea.show()
        Vlayout = QtWidgets.QVBoxLayout()
        Vlayout.addWidget(self.scrollArea)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 800, 200)

    sys.exit(app.exec_())