gpt4 book ai didi

python - 调整大小时,paint 方法不会绘制整个小部件

转载 作者:行者123 更新时间:2023-12-01 00:33:51 24 4
gpt4 key购买 nike

我在 Qt Designer 中内置了一个 PyQt 窗口,并且正在编写一个自定义绘制方法。主窗口创建一个标签并将其设置为中央小部件。然后我重写paint方法来绘制一个简单的柱形图。

在调整大小之前,该小部件运行良好。小部件调用调整大小方法并按预期重新绘制,但它使用与调整大小之前相同大小的矩形。有一个大的黑色区域——调整大小的部分——没有被绘制。

enter image description here

为了测试这一点,我捕获了小部件的矩形,并绘制了一个大矩形,其中填充了浅蓝色,外面有红线。当调整窗口大小时,外部矩形的一部分也会丢失。

调试语句显示新矩形的大小正确,并且宽度和高度值已正确输入到绘制事件中。

但是当我调整大小时,这就是我看到的。为什么油漆不在黑色区域绘制?我检查了我的代码,并且对油漆没有硬编码限制。是否发生了一些隐藏的剪辑?

我找不到任何与这个问题相关的问题,所以我似乎遗漏了一些东西。这个类似的问题说在重绘之前使窗口无效,但那是针对 C++ 的: Graphics.DrawImage Doesn't Always Paint The Whole Bitmap?

我需要以某种方式使小部件失效吗?我找不到 PyQt 方法来做到这一点。

import sys
from PyQt5 import QtCore, QtGui, QtWidgets, uic
import PyQt5 as qt

import numpy as np

class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()

self.label = QtWidgets.QLabel()
self.max_x = 600
self.max_y = 400
canvas = QtGui.QPixmap(self.max_x, self.max_y)
self.label.setPixmap(canvas)
self.setCentralWidget(self.label)

np.random.seed(777)
self.x_time = np.linspace(0, 12.56, 3000)
rand_data = np.random.uniform(0.0, 1.0, 3000)
self.data = np.sin(self.x_time) + rand_data

pal = self.palette()
pal.setColor(self.backgroundRole(), QtGui.QColor('black'))
self.setPalette(pal)
self.setAutoFillBackground(True)

def resizeEvent(self, a0: QtGui.QResizeEvent):
print("resizeEvent")
max_x = self.size().width()
max_y = self.size().height()
self.draw(max_x, max_y)

def mousePressEvent(self, a0: QtGui.QMouseEvent):
print("mousePressEvent")

def paintEvent(self, a0: QtGui.QPaintEvent):
print("New window size = ", self.size())
print("canvas size = ", self.label.size())
max_x = self.label.size().width()
max_y = self.label.size().height()
self.draw(max_x, max_y)

def draw(self, max_x, max_y):
x_final = self.x_time[-1]

data = self.data/np.max(np.abs(self.data))
data = [abs(int(k*max_y)) for k in self.data]
x_pos_all = [int(self.x_time[i]*max_x / x_final) for i in range(len(data))]

# Find and use only the max y value for each x pixel location
y_pos = []
x_pos = list(range(max_x))
cnt = 0
for x_pixel in range(max_x):
mx = 0.0
v = x_pos_all[cnt]
while cnt < len(x_pos_all) and x_pos_all[cnt] == x_pixel:
if data[cnt] > mx:
mx = data[cnt]
cnt += 1
y_pos.append(mx)

print("data = ")
dat = np.array(data)
print(dat[dat > 0].shape[0])

painter = QtGui.QPainter(self.label.pixmap()) # takes care of painter.begin(self)

pen = QtGui.QPen()

rect = self.label.rect()
print("rect = {}".format(rect))
painter.fillRect(rect, QtGui.QColor('lightblue'))
pen.setWidth(2)
pen.setColor(QtGui.QColor('green'))

for i in range(len(x_pos)):
painter.setPen(pen)
painter.drawLine(x_pos[i], max_y, x_pos[i], max_y - y_pos[i])

pen.setWidth(5)
pen.setColor(QtGui.QColor('red'))
painter.setPen(pen)
painter.drawRect(rect)

painter.end()

app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

我希望当小部件调整大小时,绘制事件将重新绘制小部件的整个新尺寸,而不仅仅是原始尺寸。奇怪的是,图表部分(绿线)看起来像是在调整大小时缩放的,但所有内容都以原始小部件大小被切断。

如何解决这个问题?

最佳答案

如果您使用的是 QLabel,则无需覆盖 PaintEvent,因为创建一个新的 QPixmap 并将其设置在 QLabel 中就足够了。

import sys
import numpy as np

from PyQt5 import QtCore, QtGui, QtWidgets


class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()

self.label = QtWidgets.QLabel()
self.setCentralWidget(self.label)

np.random.seed(777)
self.x_time = np.linspace(0, 12.56, 3000)
rand_data = np.random.uniform(0.0, 1.0, 3000)
self.data = np.sin(self.x_time) + rand_data

pal = self.palette()
pal.setColor(self.backgroundRole(), QtGui.QColor("black"))
self.setPalette(pal)
self.setAutoFillBackground(True)

def resizeEvent(self, a0: QtGui.QResizeEvent):
self.draw()
super().resizeEvent(a0)

def draw(self):
max_x, max_y = self.label.width(), self.label.height()
x_final = self.x_time[-1]
data = self.data / np.max(np.abs(self.data))
data = [abs(int(k * max_y)) for k in self.data]
x_pos_all = [int(self.x_time[i] * max_x / x_final) for i in range(len(data))]

y_pos = []
x_pos = list(range(max_x))
cnt = 0
for x_pixel in range(max_x):
mx = 0.0
v = x_pos_all[cnt]
while cnt < len(x_pos_all) and x_pos_all[cnt] == x_pixel:
if data[cnt] > mx:
mx = data[cnt]
cnt += 1
y_pos.append(mx)

print("data = ")
dat = np.array(data)
print(dat[dat > 0].shape[0])

pixmap = QtGui.QPixmap(self.size())
painter = QtGui.QPainter(pixmap)

pen = QtGui.QPen()
rect = self.label.rect()
print("rect = {}".format(rect))
painter.fillRect(rect, QtGui.QColor("lightblue"))
pen.setWidth(2)
pen.setColor(QtGui.QColor("green"))

painter.setPen(pen)
for x, y in zip(x_pos, y_pos):
painter.drawLine(x, max_y, x, max_y - y)

pen.setWidth(5)
pen.setColor(QtGui.QColor("red"))
painter.setPen(pen)
painter.drawRect(rect)
painter.end()
self.label.setPixmap(pixmap)


app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

更新:

  1. 为什么窗口放大后无法缩小? QMainWindow 的布局将 QMainWindow 的最小尺寸作为centralWidget 的minimumSizeHint 的引用,在您的情况下,QLabel 将QPixmap 的尺寸作为minimumSizeHint 。如果您希望能够减小大小,则必须重写该方法:
<b>class Label(QtWidgets.QLabel):
def minimumSizeHint(self):
return QtCore.QSize(1, 1)</b>

class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()

self.label = <b>Label()</b>
self.setCentralWidget(self.label)
# ...
  • 为什么之前没有对整个区域进行粉刷?因为您正在绘制 QPixmap 的副本:painter = QtGui.QPainter(self.label.pixmap()),而不是 QLabel 存储的 QPixmap,所以没有任何修改。
  • 关于python - 调整大小时,paint 方法不会绘制整个小部件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57964433/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com