PyQt5绘图应用动态适配屏幕几何及光标画线偏移问题求助
解决PyQt5绘图应用分辨率变化时光标与绘制位置不匹配的问题
我明白你遇到的问题了——当屏幕分辨率切换后,绘图时光标位置和实际画出的线条对不上,这本质是因为你的绘图画布(QImage)没有跟着窗口尺寸同步更新,而且初始化时的固定尺寸也没适配当前屏幕的实际分辨率。下面是具体的解决方案:
核心问题分析
- 你初始化时
self.image是用固定的1920x1080尺寸创建的,当窗口全屏切换到其他分辨率(比如1280x720)时,画布尺寸还是旧的,导致坐标映射出错。 - 没有处理窗口尺寸变化的事件,分辨率调整或窗口大小改变时,画布没有同步缩放更新。
具体修改步骤
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
相关产品推荐
相关产品推荐

