You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过QMainWindow在QGraphicsView上实现绘图操作?

Solution for Your QGraphicsView & QMainWindow Setup

Got it, let's break down your requirements step by step and fix this for you—adding scrollbars to QGraphicsView, routing all mouse events to QMainWindow, and drawing on the view via the main window—with concrete, working code examples.

1. Enable Scrollbars in QGraphicsView

QGraphicsView comes with scrollbars out of the box, but they only show up when your QGraphicsScene is larger than the view's visible area. If you want to force them to stay visible (regardless of scene size), you can set their policies explicitly:

class Window(QtGui.QGraphicsView):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.scene = QtGui.QGraphicsScene(self)
        self.setScene(self.scene)
        
        # Force scrollbars to remain visible (optional, adjust as needed)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        
        # Set a larger scene size to trigger scrollbars by default
        self.scene.setSceneRect(0, 0, 1000, 1000)

2. Route All Mouse Events to QMainWindow

Since you want QMainWindow to handle every mouse interaction, you need to override the mouse event methods in your QGraphicsView class and forward events up to the parent main window. We'll use custom signals here for cleaner, more modular code:

class Window(QtGui.QGraphicsView):
    # Define custom signals to emit mouse event data
    mousePressed = QtCore.pyqtSignal(QtCore.QPoint)
    mouseMoved = QtCore.pyqtSignal(QtCore.QPoint)
    mouseReleased = QtCore.pyqtSignal(QtCore.QPoint)

    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.scene = QtGui.QGraphicsScene(self)
        self.setScene(self.scene)
        # ... scrollbar setup from step 1 ...

    # Override mouse events to emit signals
    def mousePressEvent(self, event):
        self.mousePressed.emit(event.pos())
        super(Window, self).mousePressEvent(event)  # Keep default view behavior if needed

    def mouseMoveEvent(self, event):
        self.mouseMoved.emit(event.pos())
        super(Window, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        self.mouseReleased.emit(event.pos())
        super(Window, self).mouseReleaseEvent(event)

Then connect these signals to your QMainWindow's handler methods:

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.view = Window(self)
        self.setCentralWidget(self.view)
        
        # Link view signals to main window handlers
        self.view.mousePressed.connect(self.handleMousePress)
        self.view.mouseMoved.connect(self.handleMouseMove)
        self.view.mouseReleased.connect(self.handleMouseRelease)

    def handleMousePress(self, pos):
        # Convert view coordinates to scene coordinates (critical for scrollbars!)
        scene_pos = self.view.mapToScene(pos)
        print(f"Mouse pressed at scene position: {scene_pos.x()}, {scene_pos.y()}")
        # Add drawing logic here (see next section)

    def handleMouseMove(self, pos):
        scene_pos = self.view.mapToScene(pos)
        print(f"Mouse moved to scene position: {scene_pos.x()}, {scene_pos.y()}")

    def handleMouseRelease(self, pos):
        scene_pos = self.view.mapToScene(pos)
        print(f"Mouse released at scene position: {scene_pos.x()}, {scene_pos.y()}")

3. Draw on QGraphicsView via QMainWindow

The proper way to draw in QGraphicsView is to add items to its QGraphicsScene (the view is just a viewport for the scene). From your QMainWindow, you can access the view's scene directly to add shapes, lines, or custom graphics items.

Example: Draw a Red Line on Mouse Drag

Modify the MainWindow handlers to add interactive drawing:

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("Graphics View with Main Window Control")
        self.setGeometry(100, 100, 800, 600)
        
        self.view = Window(self)
        self.setCentralWidget(self.view)
        
        self.view.mousePressed.connect(self.handleMousePress)
        self.view.mouseMoved.connect(self.handleMouseMove)
        self.view.mouseReleased.connect(self.handleMouseRelease)
        
        self.current_line = None  # Track the line being drawn

    def handleMousePress(self, pos):
        scene_pos = self.view.mapToScene(pos)
        # Create a new line item starting at the press position
        self.current_line = QtGui.QGraphicsLineItem(QtCore.QLineF(scene_pos, scene_pos))
        self.current_line.setPen(QtGui.QPen(QtCore.Qt.red, 2))
        self.view.scene.addItem(self.current_line)

    def handleMouseMove(self, pos):
        if self.current_line is not None:
            scene_pos = self.view.mapToScene(pos)
            # Update the line's end position as the mouse moves
            line = self.current_line.line()
            line.setP2(scene_pos)
            self.current_line.setLine(line)

    def handleMouseRelease(self, pos):
        self.current_line = None  # Reset after drawing is done

Full Working Code

Putting it all together, here's the complete, runnable code:

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore

class Window(QtGui.QGraphicsView):
    mousePressed = QtCore.pyqtSignal(QtCore.QPoint)
    mouseMoved = QtCore.pyqtSignal(QtCore.QPoint)
    mouseReleased = QtCore.pyqtSignal(QtCore.QPoint)

    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.scene = QtGui.QGraphicsScene(self)
        self.setScene(self.scene)
        # Enable scrollbars
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        # Set large scene size to test scrollbars
        self.scene.setSceneRect(0, 0, 1000, 1000)

    def mousePressEvent(self, event):
        self.mousePressed.emit(event.pos())
        super(Window, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        self.mouseMoved.emit(event.pos())
        super(Window, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        self.mouseReleased.emit(event.pos())
        super(Window, self).mouseReleaseEvent(event)

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle("Graphics View with Main Window Control")
        self.setGeometry(100, 100, 800, 600)
        
        self.view = Window(self)
        self.setCentralWidget(self.view)
        
        self.view.mousePressed.connect(self.handleMousePress)
        self.view.mouseMoved.connect(self.handleMouseMove)
        self.view.mouseReleased.connect(self.handleMouseRelease)
        
        self.current_line = None

    def handleMousePress(self, pos):
        scene_pos = self.view.mapToScene(pos)
        self.current_line = QtGui.QGraphicsLineItem(QtCore.QLineF(scene_pos, scene_pos))
        self.current_line.setPen(QtGui.QPen(QtCore.Qt.red, 2))
        self.view.scene.addItem(self.current_line)

    def handleMouseMove(self, pos):
        if self.current_line is not None:
            scene_pos = self.view.mapToScene(pos)
            line = self.current_line.line()
            line.setP2(scene_pos)
            self.current_line.setLine(line)

    def handleMouseRelease(self, pos):
        self.current_line = None

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    main_win = MainWindow()
    main_win.show()
    sys.exit(app.exec_())

Quick Notes:

  • Always use mapToScene() when converting mouse positions from the view to the scene—this accounts for scrollbar offsets and any zoom you might add later.
  • Drawing via QGraphicsScene items is far more flexible than painting directly on the view; you can easily move, edit, or delete items later.
  • The signal-based approach keeps your code decoupled, so you can adjust event handling or drawing logic without rewriting the entire view class.

内容的提问来源于stack exchange,提问作者Aquarius_Girl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:21:32