【问题标题】:Select items with RubberBandDrag only when it's released仅在释放时使用 RubberBandDrag 选择项目
【发布时间】:2022-01-05 07:57:56
【问题描述】:

我有一个 QGraphicsScene,我有 QGraphicsItems 并启用了 RubberBand 选择。 我想通过橡皮筋选择来选择这些项目,但我希望它们仅在释放橡皮筋时才被选中。现在它可以实时选择/取消选择项目。因此,只有在我松开橡皮筋时才能选择项目。我想我可能需要彻底改变添加橡皮筋的方式,但我不太清楚如何。


ui_path = "C:/Users/User/ui/button_test.ui"

class Test(QtWidgets.QWidget):
    def __init__(self):
        super(Test, self).__init__()

        loader = QtUiTools.QUiLoader()
        self.ui = loader.load(ui_path, self)

        self.scene = QtWidgets.QGraphicsScene()
        self.ui.graphics_view.setScene(self.scene)

        self.ui.create_rect.clicked.connect(self.itemAdd) # create_rect is a QPushButton
    
        self.ui.graphics_view.setDragMode(QGraphicsView.RubberBandDrag)

        self.setWindowFlags(QtCore.Qt.Window | QtCore.Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint)

    def itemAdd(self, event):
        
        pen = QPen(Qt.GlobalColor.lightGray)
        pen.setWidth(10)

        brush = QBrush(Qt.GlobalColor.lightGray)

        rect = self.scene.addRect(0, 0, 40, 40, pen, brush)
      
        rect.setFlag(QGraphicsItem.ItemIsMovable)
        rect.setFlag(QGraphicsItem.ItemIsFocusable)
        rect.setFlag(QGraphicsItem.ItemIsSelectable)
        


if __name__ == '__main__':
    win = Test()
    win.ui.show()

我还想让我的橡皮筋区域着色和半透明。 我已阅读文档,但无法正确实现我已阅读的所有内容。任何帮助将不胜感激!

【问题讨论】:

    标签: python pyqt5 pyside2 qgraphicsscene qrubberband


    【解决方案1】:

    一种可能的解决方案是创建一个“假”橡皮筋,它是视图(或者,更好的是,视口)的子小部件。

    虽然 QGraphicsView 在paintEvent 中执行此操作(在视图上绘制“虚拟”矩形),但使用子小部件可避免覆盖绘制事件并提供对其行为的更多控制。

    class Test(QWidget):
        def __init__(self):
            # ...
            self.ui.graphics_view.viewport().installEventFilter(self)
            self.rubberBand = None
    
        def eventFilter(self, obj, event):
            if event.type() == event.MouseButtonPress and event.button() == Qt.LeftButton:
                # if there is no item at the mouse position, create a rubber band
                if not self.ui.graphics_view.itemAt(event.pos()) and not self.rubberBand:
                    self.createRubberBand(event.pos())
            elif event.type() == event.MouseMove and self.rubberBand:
                self.updateRubberBand(event.pos())
            elif event.type() == event.MouseButtonRelease and self.rubberBand:
                self.finalizeRubberBand()
            return super().eventFilter(obj, event)
    
        def createRubberBand(self, pos):
            # create a rubber band as child widget of the *viewport*
            self.rubberBand = QWidget(self.ui.graphics_view.viewport())
            # store the start position to get the proper rectangle when dragging
            self.rubberBand.start = pos
    
            # use the palette to get the default selection color and
            # make it semi transparent for the background
            background = self.palette().color(QPalette.Highlight)
            background.setAlphaF(.5)
            self.rubberBand.setStyleSheet('''
                border: 1px solid palette(highlight); 
                background: {};
            '''.format(background.name(background.HexArgb)))
    
            self.rubberBand.setGeometry(pos.x(), pos.y(), 0, 0)
            self.rubberBand.show()
    
        def updateRubberBand(self, pos):
            # update the rectangle based on start and mouse position, since the result
            # could be a rectangle with negative width or height, we need to "normalize"
            # as widget geometries can only have positive dimensions
            rect = QRect(self.rubberBand.start, pos).normalized()
            self.rubberBand.setGeometry(rect)
    
        def finalizeRubberBand(self):
            # map the geometry of the rubber band to the scene
            area = self.ui.graphics_view.mapToScene(self.rubberBand.geometry())
            path = QPainterPath()
            path.addPolygon(area)
            self.scene.setSelectionArea(path)
            # remove the rubber band
            self.rubberBand.deleteLater()
            self.rubberBand = None
    

    【讨论】:

    • 非常感谢您的回答,特别是代码!我几乎成功地使用了你的代码,我通常可以选择 QGraphicsItems 但 RubberBand 不可见:D 你能告诉我如何解决这个问题吗?
    • @galaxy 这很奇怪,尝试更改为background = QColor(0, 0, 255) 而不是使用调色板。此外,在创建 self.rubberBand.show() 之后调用它真的很重要。
    • 我修改了调色板部分,但没有任何改变。我是否也应该更改样式表中的某些内容?
    • @galaxy 你在使用我的 exact 代码吗?不幸的是,您的原始代码不是minimal reproducible example,所以我必须弥补缺失的部分,您可能正在做一些干扰正确绘图的事情。我建议您编辑您的问题并添加一个完整的 MRE,以便我们可以正确测试它。
    • 当然,我使用了您的确切代码,很抱歉打扰您。唯一缺少的部分是我加载窗口的部分,并且我在上面设置了标志,所以它会保持在顶部,但我认为这些不会影响我的问题,所以我一开始没有添加它们。我想我有一些特定的问题必须自己解决。无论如何,非常感谢你!您的帮助是无价的。
    猜你喜欢
    • 1970-01-01
    • 2022-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 2019-12-16
    • 1970-01-01
    相关资源
    最近更新 更多