PyQt5:QScrollArea保持Pixmap宽高比 [英] PyQt5: QScrollArea Keep Pixmap Aspect Ratio

查看:222
本文介绍了PyQt5:QScrollArea保持Pixmap宽高比的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've created a set of pixmap buttons (PicButton) using QAbstractButton based on this https://stackoverflow.com/a/2714554/6859682 and want to add them in a scroll area such that the user can scroll horizontally. However, I need

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

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

The issue with my current code is that the pixmap buttons get squeezed when the height becomes too much.

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

I was able to get the aspect ratio to be constant when the height is small enough for all the buttons to fit in the window. I am attaching my PicButton class below.

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)

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

In the scenario when the height is too much for all the buttons to fit scenario, I want to activate the scroll bar instead and keep the aspect ratio of the buttons. Any ideas on how to do this? I'm attaching the window code below for completeness

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_())

推荐答案

已添加

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_())

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

I'm sorry for not enbedding answer you want at one time.

QAbstractButton版本

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

Yes, I didn't use QAbstractButton.This has being hung on my head. Here is the QAbstractButton version.You will be able to customize the buttons you want.

从PyQt5导入QtCore,QtGui,QtWidgets

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 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.

Because I accepted the comments, so I tried to elaborate the occasion of QGraphicsView & QGraphicsScene.

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

But this is only the result.This code may not have any popularity. At any rate, I want to you to execute this code. I hope you like it.

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

If you want to know the detail,please write comments.

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_())


上一个

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

I'm not sure about what you want,do you want to do this? If it is not,I will delete this answer or rewrite.

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_())

这篇关于PyQt5:QScrollArea保持Pixmap宽高比的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆