QGraphicsScene未显示在窗口左上角的问题排查
问题描述
我参考Stack Overflow上的折线绘制示例编写了PyQt5绘图代码,但绘制的图形并未显示在窗口左上角。我尝试通过scene = QGraphicsScene(0,0, self.width, self.height)设置场景范围,但问题依旧。请指出需要修改的内容,让图形显示在正确位置。
原始代码
#!/usr/bin/python3 # from PyQt5.QtGui import QColor, QFont, QPainter, QPainterPath, QPainterPathStroker, QPen, QPolygonF ####NEW from PyQt5.QtCore import Qt, QPointF from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsPathItem, QGraphicsView, QMainWindow import sys class plot(QMainWindow): # def plot_parameters(self, data, width, height): len_data = len(data) # pixel_ratio changes the raw data x-value to a screen x-value pixel_ratio_x = width/len_data # transform ratio for x-axis min_y = min(data) max_y = max(data) # pixel_ratio changes the raw data y-value to a screen y-value pixel_ratio_y = height/(max_y-min_y) return pixel_ratio_x, pixel_ratio_y, min_y, max_y, len_data # def y_axis_data(self, min_y, max_y): # Y labels - a plotdata must be >= 0 - TODO y_labels = [max_y] yl_increment='1' # label increment lenlblvalue=len(str(int(min_y))) # label length if min_y>0.0: lenlblvalue=len(str(int(max_y))) min_y=0.0 yunit=len(str(max(int(max_y), abs(int(min_y)))))-1 # maximum units of y values for i in range(0, yunit): # create increment yl_increment+='0' lblvalue=int((int(str(max_y)[0])+1)*int(yl_increment))# first lblvalue yl_increment=int(yl_increment)*.25 while lblvalue>=max_y: lblvalue-=yl_increment while (lblvalue>min_y and lblvalue<max_y): #draw value labels and lines lblvalue -= yl_increment y_labels.append(lblvalue) # y axis line tick marks return y_labels,yl_increment def plot_decoration(self, scene, data, min_y, max_y, width, height): # create a y-axis with tick marks, labels and lines pen = QPen(Qt.gray, 0.5) # calculate the y-axis line positions y_labels,yl_increment = self.y_axis_data(min_y, max_y) # initial line position on y-axis y_position = 0 # add a tick mark and label at y_position for l in list(y_labels): y_position = l line = scene.addLine(0,height-(y_position*self.pixel_ratio_y), width, height-(y_position*self.pixel_ratio_y)) line.setPen(pen) txt = scene.addText(str(l), QFont('sans',8,QFont.Light)) #/27612052/ txt.setPos(0,height-(y_position*self.pixel_ratio_y)-12) # -12 to line up with tick mark y_position += yl_increment # move to next position # def create_plot(self): self.width = 700 self.height = 400 poly_plot_data = [] # create scene and view scene = QGraphicsScene(0,0, self.width, self.height) #/10443894/ view = QGraphicsView(scene) view.show() # raw data data = [-10, -12, 0, -5, -10, -20] # get parameters of data for plotting self.pixel_ratio_x, self.pixel_ratio_y, min_y, max_y, len_data = self.plot_parameters(data, self.width, self.height) # create polyline data for d in range(0, len_data): poly_plot_data.append(QPointF(int(d*self.pixel_ratio_x), ((self.height)-(data[d])*self.pixel_ratio_y))) # draw the axes - TODO x-axis self.plot_decoration(scene, data, min_y, max_y, self.width, self.height) # draw polyline poly = QPolygonF(poly_plot_data) # /68704191/ path = QPainterPath() path.addPolygon(poly) new_item = QGraphicsPathItem(path, None) new_item.setPen(QPen(QColor("red"), 1)) scene.addItem(new_item) return view # def __init__(self): super().__init__() plot = self.create_plot() self.setCentralWidget(plot) self.show() ########################################### if __name__ == '__main__': app = QApplication(sys.argv) ex = plot() sys.exit(app.exec_())
修复方案
问题核心是Y轴坐标转换未考虑数据的最小值偏移,导致图形超出场景可见范围,同时存在视图重复显示的问题。需要修改以下几点:
1. 修正Y轴坐标转换逻辑
原始代码直接使用data[d]计算屏幕Y坐标,未处理数据中的负数偏移,导致图形被推到场景下方(超出视图可见区域)。需将数据相对于min_y做偏移:
在create_plot方法中,修改折线点的Y坐标计算:
poly_plot_data.append(QPointF(int(d*self.pixel_ratio_x), self.height - (data[d] - min_y) * self.pixel_ratio_y))
2. 修正Y轴刻度的坐标计算
同样在plot_decoration方法中,刻度线和标签的Y坐标也需要基于min_y偏移:
# 替换原line和txt的pos计算 y_screen_pos = height - (y_position - min_y) * self.pixel_ratio_y line = scene.addLine(0, y_screen_pos, width, y_screen_pos) txt.setPos(0, y_screen_pos - 12)
3. 移除重复的视图显示调用
create_plot中调用的view.show()会与主窗口的self.show()冲突,导致窗口显示异常,删除该行即可。
4. 确保视图与场景左上角对齐(可选)
为避免视图自动居中场景,添加对齐设置:
view = QGraphicsView(scene) view.setAlignment(Qt.AlignTop | Qt.AlignLeft)
修改后的完整代码
#!/usr/bin/python3 # from PyQt5.QtGui import QColor, QFont, QPainter, QPainterPath, QPainterPathStroker, QPen, QPolygonF from PyQt5.QtCore import Qt, QPointF from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsPathItem, QGraphicsView, QMainWindow import sys class plot(QMainWindow): # def plot_parameters(self, data, width, height): len_data = len(data) pixel_ratio_x = width/len_data min_y = min(data) max_y = max(data) pixel_ratio_y = height/(max_y-min_y) return pixel_ratio_x, pixel_ratio_y, min_y, max_y, len_data # def y_axis_data(self, min_y, max_y): y_labels = [max_y] yl_increment='1' lenlblvalue=len(str(int(min_y))) if min_y>0.0: lenlblvalue=len(str(int(max_y))) min_y=0.0 yunit=len(str(max(int(max_y), abs(int(min_y)))))-1 for i in range(0, yunit): yl_increment+='0' lblvalue=int((int(str(max_y)[0])+1)*int(yl_increment)) yl_increment=int(yl_increment)*.25 while lblvalue>=max_y: lblvalue-=yl_increment while (lblvalue>min_y and lblvalue<max_y): lblvalue -= yl_increment y_labels.append(lblvalue) return y_labels,yl_increment def plot_decoration(self, scene, data, min_y, max_y, width, height): pen = QPen(Qt.gray, 0.5) y_labels,yl_increment = self.y_axis_data(min_y, max_y) for l in y_labels: y_position = l y_screen_pos = height - (y_position - min_y) * self.pixel_ratio_y line = scene.addLine(0, y_screen_pos, width, y_screen_pos) line.setPen(pen) txt = scene.addText(str(l), QFont('sans',8,QFont.Light)) txt.setPos(0, y_screen_pos - 12) # def create_plot(self): self.width = 700 self.height = 400 poly_plot_data = [] scene = QGraphicsScene(0,0, self.width, self.height) view = QGraphicsView(scene) view.setAlignment(Qt.AlignTop | Qt.AlignLeft) data = [-10, -12, 0, -5, -10, -20] self.pixel_ratio_x, self.pixel_ratio_y, min_y, max_y, len_data = self.plot_parameters(data, self.width, self.height) for d in range(0, len_data): poly_plot_data.append(QPointF(int(d*self.pixel_ratio_x), self.height - (data[d] - min_y) * self.pixel_ratio_y)) self.plot_decoration(scene, data, min_y, max_y, self.width, self.height) poly = QPolygonF(poly_plot_data) path = QPainterPath() path.addPolygon(poly) new_item = QGraphicsPathItem(path, None) new_item.setPen(QPen(QColor("red"), 1)) scene.addItem(new_item) return view # def __init__(self): super().__init__() plot_view = self.create_plot() self.setCentralWidget(plot_view) self.show() ########################################### if __name__ == '__main__': app = QApplication(sys.argv) ex = plot() sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

