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

PyQt5绘图应用动态适配屏幕几何及光标画线偏移问题求助

解决PyQt5绘图应用分辨率变化时光标与绘制位置不匹配的问题

我明白你遇到的问题了——当屏幕分辨率切换后,绘图时光标位置和实际画出的线条对不上,这本质是因为你的绘图画布(QImage)没有跟着窗口尺寸同步更新,而且初始化时的固定尺寸也没适配当前屏幕的实际分辨率。下面是具体的解决方案:

核心问题分析

  1. 你初始化时self.image是用固定的1920x1080尺寸创建的,当窗口全屏切换到其他分辨率(比如1280x720)时,画布尺寸还是旧的,导致坐标映射出错。
  2. 没有处理窗口尺寸变化的事件,分辨率调整或窗口大小改变时,画布没有同步缩放更新。

具体修改步骤

1. 初始化时适配屏幕实际分辨率

把初始化时硬编码的宽高改成获取当前屏幕的几何尺寸,确保画布从一开始就适配当前屏幕:

# 去掉固定的top/left/width/height设置,直接全屏后获取窗口实际尺寸
self.showFullScreen()
self.image= QImage(self.size(), QImage.Format_RGB32)
self.image.fill(Qt.white)

2. 重写resizeEvent方法,同步更新画布

当窗口尺寸变化(包括分辨率切换)时,创建新的适配当前尺寸的画布,同时把旧画布的内容缩放绘制到新画布上,保证之前的绘图内容不会丢失:

def resizeEvent(self, event):
    # 创建新的适配当前窗口尺寸的画布
    new_image = QImage(self.size(), QImage.Format_RGB32)
    new_image.fill(Qt.white)
    # 用QPainter把旧画布的内容缩放绘制到新画布
    painter = QPainter(new_image)
    painter.drawImage(new_image.rect(), self.image, self.image.rect())
    # 更新当前画布为新画布
    self.image = new_image
    super().resizeEvent(event)

3. 修复快捷键冲突

你的代码中黑色和蓝色的快捷键都是Ctrl+B,这会导致功能冲突,我把蓝色的快捷键改成了Ctrl+Shift+B:

blueAction.setShortcut("Ctrl+Shift+B")

完整修改后的代码

from PyQt5.QtWidgets import QMainWindow, QApplication, QMenu, QMenuBar, QAction, QFileDialog, QDesktopWidget, QLabel, QGridLayout, QActionGroup
from PyQt5.QtGui import QIcon, QImage, QPainter, QPen, QBrush
from PyQt5.QtCore import Qt, QPoint
from PyQt5 import QtWidgets
from PyQt5 import QtGui
import sys

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        title="Draw!"
        icon="icons/paint.png"
        self.setWindowTitle(title)
        self.setWindowIcon(QIcon(icon))
        
        # 直接全屏显示,初始化适配当前窗口尺寸的画布
        self.showFullScreen()
        self.image= QImage(self.size(), QImage.Format_RGB32)
        self.image.fill(Qt.white)
        
        self.drawing= False
        self.brushSize= 2
        self.brushColor= Qt.black
        self.lastPoint= QPoint()

        mainMenu=self.menuBar()
        fileMenu=mainMenu.addMenu("File")
        brushSize=mainMenu.addMenu("Brush Size")
        brushColor=mainMenu.addMenu("Brush Color")

        quitAction= QtWidgets.QAction("Quit", self.window())
        quitAction.setShortcut("Esc")
        fileMenu.addAction(quitAction)
        quitAction.triggered.connect(self.exit)

        saveAction=QAction(QIcon("icons/save.png"), "Save",self)
        saveAction.setShortcut("Ctrl+S")
        fileMenu.addAction(saveAction)
        saveAction.triggered.connect(self.save)

        clearAction=QAction(QIcon("icons/clear.png"), "Clear",self)
        clearAction.setShortcut("Ctrl+C")
        fileMenu.addAction(clearAction)
        clearAction.triggered.connect(self.clear)

        eraseAction=QAction(QIcon("icons/erase.png"), "Erase",self)
        eraseAction.setShortcut("Ctrl+E")
        fileMenu.addAction(eraseAction)
        eraseAction.triggered.connect(self.erase)

        threepxAction=QAction(QIcon("icons/threepx.png"), "3px", self)
        brushSize.addAction(threepxAction)
        threepxAction.triggered.connect(self.threePixel)

        fivepxAction=QAction(QIcon("icons/fivepx.png"), "5px", self)
        brushSize.addAction(fivepxAction)
        fivepxAction.triggered.connect(self.fivePixel)

        sevenpxAction=QAction(QIcon("icons/sevenpx.png"), "7px", self)
        brushSize.addAction(sevenpxAction)
        sevenpxAction.triggered.connect(self.sevenPixel)

        ninepxAction=QAction(QIcon("icons/ninepx.png"), "9px", self)
        brushSize.addAction(ninepxAction)
        ninepxAction.triggered.connect(self.ninePixel)

        elevenpxAction=QAction(QIcon("icons/elevenpx.png"), "11px", self)
        brushSize.addAction(elevenpxAction)
        elevenpxAction.triggered.connect(self.elevenPixel)

        twentypxAction=QAction(QIcon("icons/twentypx.png"), "20px", self)
        brushSize.addAction(twentypxAction)
        twentypxAction.triggered.connect(self.twentyPixel)

        bucketpxAction=QAction(QIcon("icons/bucketpx.png"), "Bucket", self)
        brushSize.addAction(bucketpxAction)
        bucketpxAction.triggered.connect(self.bucketPixel)

        blackAction=QAction(QIcon("icons/black.png"), "Black", self)
        blackAction.setShortcut("Ctrl+B")
        brushColor.addAction(blackAction)
        blackAction.triggered.connect(self.blackColor)

        whiteAction=QAction(QIcon("icons/white.png"), "White", self)
        whiteAction.setShortcut("Ctrl+W")
        brushColor.addAction(whiteAction)
        whiteAction.triggered.connect(self.whiteColor)

        redAction=QAction(QIcon("icons/red.png"), "Red", self)
        redAction.setShortcut("Ctrl+R")
        brushColor.addAction(redAction)
        redAction.triggered.connect(self.redColor)

        greenAction=QAction(QIcon("icons/green.png"), "Green", self)
        greenAction.setShortcut("Ctrl+G")
        brushColor.addAction(greenAction)
        greenAction.triggered.connect(self.greenColor)

        yellowAction=QAction(QIcon("icons/yellow.png"), "Yellow", self)
        yellowAction.setShortcut("Ctrl+Y")
        brushColor.addAction(yellowAction)
        yellowAction.triggered.connect(self.yellowColor)

        blueAction=QAction(QIcon("icons/blue.png"), "Blue", self)
        blueAction.setShortcut("Ctrl+Shift+B")
        brushColor.addAction(blueAction)
        blueAction.triggered.connect(self.blueColor)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drawing= True
            self.lastPoint= event.pos()

    def mouseMoveEvent(self, event):
        if(event.buttons() & Qt.LeftButton) & self.drawing:
            painter=QPainter(self.image)
            painter.setPen(QPen(self.brushColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
            painter.drawLine(self.lastPoint, event.pos())
            self.lastPoint= event.pos()
            self.update()

    def mouseReleaseEvent(self, event):
        if event.button() ==Qt.LeftButton:
            self.drawing= False

    def paintEvent(self, event):
        canvasPainter=QPainter(self)
        canvasPainter.drawImage(self.rect(), self.image, self.image.rect())

    def resizeEvent(self, event):
        # 窗口尺寸变化时更新画布并保留原有内容
        new_image = QImage(self.size(), QImage.Format_RGB32)
        new_image.fill(Qt.white)
        painter = QPainter(new_image)
        painter.drawImage(new_image.rect(), self.image, self.image.rect())
        self.image = new_image
        super().resizeEvent(event)

    def save(self):
        filePath, _=QFileDialog.getSaveFileName(self, "Save Image", "", "PNG(*.png);;JPEG(*.jpg *.jpeg);;All Files(*.*)")
        if filePath=="":
            return
        self.image.save(filePath)

    def exit(self):
        QtWidgets.qApp.quit()

    def clear(self):
        self.image.fill(Qt.white)
        self.update()

    def erase(self):
        self.brushSize= 5
        self.brushColor=Qt.white

    def threePixel(self):
        self.brushSize= 3

    def fivePixel(self):
        self.brushSize= 5

    def sevenPixel(self):
        self.brushSize= 7

    def ninePixel(self):
        self.brushSize= 9

    def elevenPixel(self):
        self.brushSize = 11

    def twentyPixel(self):
        self.brushSize = 20

    def blackColor(self):
        self.brushColor=Qt.black

    def whiteColor(self):
        self.brushColor=Qt.white

    def redColor(self):
        self.brushColor=Qt.red

    def greenColor(self):
        self.brushColor=Qt.green

    def yellowColor(self):
        self.brushColor=Qt.yellow

    def blueColor(self):
        self.brushColor=Qt.blue

    def bucketPixel(self):
        self.image.fill(self.brushColor)

if __name__=="__main__":
    app=QApplication(sys.argv)
    window= Window()
    window.show()
    app.exec()

现在你切换屏幕分辨率时,画布会自动适配新的窗口尺寸,光标位置和绘制的线条就能完全匹配了,而且之前的绘图内容也会保留并缩放适配新尺寸。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 17:07:40