2016-11-01 2 views
1

Я получаю окно сообщения: «Python перестает работать», когда я загружаю изображение в QLabel в уже видимом окне. Выбор отладочных показов: в Python.exe произошло необработанное исключение Win32.Python3 + Pillow + QT5: сбой при изменении размера метки, содержащей изображение

Если я загружаю изображение на этикетку перед отображением окна, оно отображается правильно.

Вот урезанная код:

#!/usr/bin/etc python 
import sys 
import os 
import stat 
from PyQt5.QtCore import * 
from PyQt5.QtGui import * 
from PyQt5.QtWidgets import * 
from PIL import * 
from PIL.ImageQt import * 

def update(label): 
    filename = r"C:\Users\me\Pictures\images\00000229.jpg" 
    im1 = Image.open(filename) 
    print ("Read ({},{})".format(im1.width, im1.height)) 
    im2 = im1.rotate(90, expand=True) 
    print("Rotate ({},{})".format(im2.width, im2.height)) 

    im2.thumbnail((1200,1200)) 
    print("Thumbnail({},{})".format(im2.width, im2.height)) 

    qimage = ImageQt(im2) 
    pixmap = QPixmap.fromImage(qimage) 
    label.setPixmap(pixmap) 


app = QApplication(sys.argv) 

desktop = QDesktopWidget() 
deskGeometry = desktop.availableGeometry() 
print("desktop ({},{})".format(deskGeometry.width(), deskGeometry.height())) 

window = QFrame() 
# If you let QT pick the sizes itself, it picks dumb ones, then complains 
# 'cause they are dumb 
window.setMinimumSize(300, 200) 
window.setMaximumSize(deskGeometry.width(), deskGeometry.height()) 

label = QLabel() 
#call update here: no crash 

caption = QLabel() 
caption.setText("Hello world") 

box = QVBoxLayout() 
box.addWidget(label) 
box.addWidget(caption) 
#call update here, no crash 
window.setLayout(box) 
#call update here, no crash 

window.show() 
#this call to update results in a crash 
update(label) 

#window.updateGeometry() 
print("App: exec") 
app.exec_() 

Выход:

desktop (3623,2160) 
Read (1515,1051) 
Rotate (1051,1515) 
Thumbnail(832,1200) 
App: exec 

мне нужно сделать что-нибудь особенное, чтобы сказать, что QT размер окна будет меняться ли? Любые предложения по диагностике проблемы здесь ...


Update:

Если я копирую тело функции обновления и вставить его на место вызова обновления, она не долго аварий - он работает так, как ожидалось.

Из этого я заключаю, что существует проблема с объектами. Где-то за кулисами QT и/или Pillow удерживают указатель на внутренний буфер, а не делают копию или «крадут» буфер. Когда объект, содержащий буфер удаляется указатель становится недействительным и «плохие вещи случаются [TM]»

Теперь, чтобы определить, кто ленив ...

+0

Я собирался предлагая, чтобы вам нужно было ссылаться на основные данные изображения, - но тогда я не мог фактически воспроизвести проблему самостоятельно. Но в любом случае эти проблемы с сборкой мусора хорошо известны, поэтому я не думаю, что есть что-то необычный здесь. – ekhumoro

+0

'' Если бы мне нужны были проблемы с жизненным циклом объекта, я бы программа в C++, а не Python - sheesh. ' 'Спасибо, что посмотрели на проблему. –

ответ

0

Я нашел решение, основанное на наблюдении, упомянутых в обновлении что это стало проблемой жизни объекта.

Изменение строки в функции update от

pixmap = QPixmap.fromImage(qimage) 

в

pixmap = QPixmap.fromImage(qimage).copy() 

заставляет копию пиксельной. Эта копия, по-видимому, имеет свой собственный буфер данных, а не заимствование буфера из изображения.

Метка затем сохраняет ссылку на pixmap - обеспечивая время жизни буфера. «Ошибка», похоже, заключается в том, что QPixmap.fromImage захватывает указатель на данные в изображении, но не сохраняет ссылку на изображение, поэтому, если изображение получает сбор мусора (что, вероятно, является причиной того, что это большой объект, ярлык (и пиксельная) есть указатель на нераспределенную память.

[Это «указатель на буфер» вещи сущая спекуляция с моей стороны, но нижняя линия является программа больше не падает.]

Смежные вопросы