2 种布局中带有橡皮筋的小部件选择问题

问题描述

目前添加了2个布局,在标签的顶部和下方使用FlowLayout添加按钮。 在 Qrubberband 上

当鼠标不动时,没有任何问题。当我拖动时,选择有问题。 问题从何而来?

enter image description here

# -*- coding: utf-8 -*-
from pyside2.QtCore import *
from pyside2.QtGui import *
from pyside2.QtWidgets import *

class QToolButton(QToolButton):
    def __init__(self,label='',icon='',icon_size=100):
        super(QToolButton,self).__init__()
        self.label = label
        self.icon = icon
        self.icon_size = icon_size
        self.create()

    def create(self):
        self.setText(self.label)
        self.setIcon(QIcon(self.icon))
        self.setIconSize(QSize(self.icon_size,self.icon_size))
        self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        self.setCheckable(True)
        self.setFocusPolicy(Qt.NoFocus)

class Window(QMainWindow):
    def __init__(self):
        super(Window,self).__init__()
        self.rubberBand = QRubberBand(QRubberBand.Rectangle,self)
        self.ui()
        self.add_thumbnail()

    def ui(self):
        self.setContentsMargins(2,2,2)
        self.resize(1000,800)

        self.centralwidget = QWidget(self)
        self.gridLayout = qgridLayout(self.centralwidget)
        self.label = QLabel(self.centralwidget)
        self.label.setText('LABEL IMAGE')
        self.label.setMinimumSize(QSize(0,100))
        self.label.setMaximumSize(QSize(16777215,100))
        self.label.setAlignment(Qt.AlignCenter)

        self.gridLayout.addWidget(self.label,1,1)

        self.frame = qframe(self.centralwidget)
        self.frame.setFrameShape(qframe.StyledPanel)
        self.frame.setFrameShadow(qframe.Raised)

        self.gridLayout.addWidget(self.frame,1)
        self.setCentralWidget(self.centralwidget)

        self.flow_layout = FlowLayout()
        self.frame.setLayout(self.flow_layout)

    def add_thumbnail(self):
        for i in range(10):
            button = QToolButton(label='test',icon='test')
            self.flow_layout.addWidget(button)
            button.installEventFilter(self)

    def eventFilter(self,source,event):
        if event.type() == event.MouseButtonPress:
            self.origin = source.mapTo(self,event.pos())
        elif event.type() == event.MouseMove and event.buttons():
            if not self.rubberBand.isVisible():
                distance = (source.mapTo(self,event.pos()) - self.origin).manhattanLength()
                if distance > QApplication.startDragdistance():
                    if isinstance(source,QAbstractButton) and source.isDown():
                        source.setDown(False)
                    self.rubberBand.show()
            if self.rubberBand.isVisible():
                self.resizeRubberBand(source.mapTo(self,event.pos()))
                event.accept()
                return True
        elif event.type() == event.MouseButtonRelease and self.rubberBand.isVisible():
            self.closeRubberBand()
            event.accept()
            return True
        return super(Window,self).eventFilter(source,event)

    def startRubberBand(self,pos):
        self.origin = pos
        self.rubberBand.setGeometry(
            QRect(self.origin,QSize()))
        self.rubberBand.show()

    def resizeRubberBand(self,pos):
        if self.rubberBand.isVisible():
            self.rubberBand.setGeometry(
                QRect(self.origin,pos).normalized())

    def closeRubberBand(self):
        if self.rubberBand.isVisible():
            self.rubberBand.hide()
            selected = []
            rect = self.rubberBand.geometry()
            for child in self.findChildren(QToolButton):
                if rect.intersects(child.geometry()):
                    selected.append(child)
            if selected:
                for i in selected:
                    if i.isChecked():
                        i.setChecked(False)
                    else:
                        i.setChecked(True)

    def mousepressEvent(self,event):
        self.startRubberBand(event.pos())
        QMainWindow.mousepressEvent(self,event)

    def mouseMoveEvent(self,event):
        self.resizeRubberBand(event.pos())
        QMainWindow.mouseMoveEvent(self,event)

    def mouseReleaseEvent(self,event):
        self.closeRubberBand()
        QMainWindow.mouseReleaseEvent(self,event)

class FlowLayout(QLayout):
    def __init__(self,parent=None,margin=0,spacing=-1):
        super(FlowLayout,self).__init__(parent)

        if parent is not None:
            self.setContentsMargins(margin,margin,margin)

        self.setSpacing(spacing)
        self.margin = margin

        # spaces between each item
        self.spaceX = 2
        self.spaceY = 2

        self.itemList = []

    def __del__(self):
        item = self.takeAt(0)
        while item:
            item = self.takeAt(0)

    def addItem(self,item):
        self.itemList.append(item)

    def count(self):
        return len(self.itemList)

    def itemAt(self,index):
        if index >= 0 and index < len(self.itemList):
            return self.itemList[index]

        return None

    def takeAt(self,index):
        if index >= 0 and index < len(self.itemList):
            return self.itemList.pop(index)

        return None

    def expandingDirections(self):
        return Qt.Orientations(Qt.Orientation(0))

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self,width):
        height = self.doLayout(QRect(0,width,0),True)
        return height

    def setGeometry(self,rect):
        super(FlowLayout,self).setGeometry(rect)
        self.doLayout(rect,False)

    def sizeHint(self):
        return self.minimumSize()

    def minimumSize(self):
        size = QSize()

        for item in self.itemList:
            size = size.expandedTo(item.minimumSize())

        size += QSize(2 * self.margin,2 * self.margin)
        return size

    def doLayout(self,rect,testOnly):
        x = rect.x()
        y = rect.y()
        lineHeight = 0

        for item in self.itemList:
            wid = item.widget()
            nextX = x + item.sizeHint().width() + self.spaceX
            if nextX - self.spaceX > rect.right() and lineHeight > 0:
                x = rect.x()
                y = y + lineHeight + self.spaceY
                nextX = x + item.sizeHint().width() + self.spaceX
                lineHeight = 0

            if not testOnly:
                item.setGeometry(QRect(QPoint(x,y),item.sizeHint()))

            x = nextX
            lineHeight = max(lineHeight,item.sizeHint().height())

        return y + lineHeight - rect.y()

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

问题从何而来?

解决方法

鼠标左键时,当是mousePressEvent时,正常工作,当是mouseReleaseEvent时,widget选择有问题。 我现在已经解决了 代码是

def closeRubberBand(self):
    if self.rubberBand.isVisible():
        self.rubberBand.hide()
        selected = []
        rect = self.rubberBand.geometry()
        for child in self.findChildren(QToolButton):
            if self.flow_layout_widget:
                layout_x = self.flow_layout_widget.pos().toTuple()[0]
                layout_y = self.flow_layout_widget.pos().toTuple()[1]
                child_w = child.geometry().size().toTuple()[0]
                child_h = child.geometry().size().toTuple()[1]
                cx,cy,cw,ch = (child.geometry().x() + layout_x,child.geometry().y() + layout_y,child_w,child_h)
                child_rect = QRect(cx,ch)
            else:
                child_rect = child.geometry()

            if rect.intersects(child_rect):
                selected.append(child)
        if selected:
            for i in selected:
                if i.isChecked():
                    i.setChecked(False)
                else:
                    i.setChecked(True)

有没有更简单的方法?

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...