How to connect Orange-Widgets in a Python script - python

I would like to use Orange widgets not in the Orange canvas but in my own program. In the main functions of some widgets it is shown how to put data into a widget. For example:
ow = OWScatterPlot()
ow.set_data(Orange.data.Table('iris'))
But unfortunately I can't find out how to connect Inputs and Outputs of two widgets. I had expected something like this:
ow1 = OWSelectRows()
ow1.set_data(Table("iris"))
ow2 = OWScatterPlot()
ow2.Inputs.data=ow1.Outputs.matching_data
But no data reaches ow2.
In the canvas it is done just by dragging the link from one widget to another. Does anybody know how it is done in a Python script?

Orange have a SignalManager runing in the background, which handle widgets inputs and outputs. So if you would like to transfer your data from one widget to another without canvas, you should do something like this:
from orangecanvas.application.canvasmain import *
from Orange.data import Table
from PyQt5.QtWidgets import QApplication
from orangewidget.tests.base import DummySignalManager
from Orange.widgets.data.owtable import OWDataTable
from WindowForWidgets import WindowForWidgets
def App():
app = QApplication(sys.argv)
signal_manager = DummySignalManager()
window_for_widgets = WindowForWidgets
data = Table('iris')
ow1 = OWDataTable()
ow1.signalManager = signal_manager
getattr(ow1, ow1.Inputs.data.handler)(data) # you may replace this with: ow1.set_data(data)
ow1.handleNewSignals()
window_for_widgets = WindowForWidgets(ow1, data, signal_manager)
sys.exit(app.exec_())
App()
I used WindowForWidgets to show first widget and detect when the widget is closed (closeEvent method). Then we transfer the data from the first widget to second with signal manager. Here is the code for WindowForWidgets:
from Orange.widgets.visualize.owscatterplot import OWScatterPlot
from orangecanvas.application.canvasmain import *
class WindowForWidgets(QMainWindow):
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 250
def __init__(self, widget, data, signal_manager):
super(WindowForWidgets, self).__init__()
self.widget = widget
self.data = data
self.signal_manager = signal_manager
self.initUI()
def initUI(self):
self.setCentralWidget(self.widget)
self.show()
def closeEvent(self, event):
ow2 = OWScatterPlot()
getattr(ow2, ow2.Inputs.data.handler)(self.signal_manager.get_output(self.widget, "Selected Data"))
ow2.show()
This code will transfer selected data from the first widget to second. If we want to transfer all data we need to change the line in closeEvent method from:
getattr(ow2, ow2.Inputs.data.handler)(self.signal_manager.get_output(self.widget, "Selected Data"))
to:
getattr(ow2, ow2.Inputs.data.handler)(self.signal_manager.get_output(self.widget, "Data"))

Related

Open popup notification on the same monitor where the mainwindow is in python an pyqt5

In my QMainWindow i have a button which opens a new QDialog in the bottom right monitorcorner with a successmessage when i click it.
Now, if i move the QMainWindow to another monitor (i have 3 monitor) and click the button the successmessage popup appears in the monitor where the QMainWindow was opened. What i want is that the popup message appears in the monitor where my QMainWindow actually is. So if i move the QMainWindow to Monitor 1 and click the button, the successpopup should opens in monitor 1. If the QMainWindow is in monitor 2, the successpopup should open in monitor 2 an same for monitor 3.
with
screenNumber = QDesktopWidget().screenNumber(self)
i can read the screennumber where the mainwindow is. and this works fine. Evertime i click the button i read out the screennumber. But i don't found a way, to set the screennumber to my notification.
Any ideas?
Edit:
maybe it helps if i show my notify class
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication, QDesktopWidget
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
## Some helping stuff
############################################################
parent_sSize = QDesktopWidget().screenGeometry(parent)
parent_screenNumber = QDesktopWidget().screenNumber(parent)
sSize = QDesktopWidget().screenGeometry()
screenNumber = QDesktopWidget().screenNumber()
print("notification ScreenNumber = " + str(screenNumber))
print(sSize.width())
print(sSize.height())
print("Parents ScreenNumber = " + str(parent_screenNumber))
print(parent_sSize.width())
print(parent_sSize.height())
self.Note_Exit.clicked.connect(self.close)
## ScreenSize from parent
############################################################
self.hidedPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()+200,
self.frameGeometry().width(),
self.frameGeometry().height())
self.showPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()-50,
self.frameGeometry().width(),
self.frameGeometry().height())
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.setGeometry(self.hidedPos)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(self.showPos)
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(self.hidedPos)
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())
You cannot use the size of the widget during its construction, as at that moment it has a default size (640x480 for top level widgets, 100x30 for widgets created with a parent, including dialogs): the only reliable option is to use the sizeHint() or ensure that the layout has been properly activated with adjustSize().
Then, you don't need the screen to get the target position, as the parent geometry will suffice, but you do need it for the start position, otherwise the dialog will "pop up" at an arbitrary point below the window. Note that QDesktopWidget is considered obsolete, and you should use QScreen instead.
Finally, since you might want to reuse the notification, the start position should be set when the popup is actually being shown, not before. The same goes for the position when hiding (in case the notification could be moved).
class Notify(QDialog, Ui_Notification):
def __init__(self, parent):
super().__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.showAnim = QPropertyAnimation(self, b'geometry')
self.showAnim.setDuration(700)
self.showAnim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.hideAnim = QPropertyAnimation(self, b'geometry')
self.hideAnim.setDuration(700)
self.hideAnim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.hideTimer = QTimer(self, singleShot=True)
self.hideTimer.setInterval(4000)
self.hideTimer.timeout.connect(self.hideNote)
self.showAnim.finished.connect(self.hideTimer.start)
self.hideAnim.finished.connect(self.close)
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.adjustSize() # important!
endRect = self.rect()
center = self.parent().geometry().center()
endRect.moveCenter(center)
screen = QApplication.screenAt(center)
startRect = QRect(endRect)
startRect.moveTop(screen.geometry().bottom())
self.setGeometry(startRect)
self.showAnim.setStartValue(startRect)
self.showAnim.setEndValue(endRect)
self.showAnim.start()
self.show()
def hideNote(self):
rect = self.geometry()
self.hideAnim.setStartValue(rect)
screen = QApplication.screenAt(rect.center())
rect.moveTop(screen.geometry().bottom())
self.hideAnim.setEndValue(rect)
self.hideAnim.start()
if __name__ == "__main__":
notes = QApplication(sys.argv)
notes.setStyle('fusion')
w = QMainWindow()
b = QPushButton('click!')
w.setCentralWidget(b)
w.show()
notify = Notify(w)
b.clicked.connect(lambda: notify.setNote())
sys.exit(notes.exec())
Be aware that if you're going to create the popup every time, you should also set the WA_DeleteOnClose attribute in order to destroy it when closed, otherwise it will be kept in memory.
Note: QTimer.singleShot() is a static function, creating an instance of QTimer to use it is pointless, as that instance won't be used and a new QTimer would be created anyway.
Thank you.
In the meantime i found a solution which works for me.
Look a little dirty but works.
could you tell me, whats the difference between my code an yours?
Why should i use your code, except the fact that you are a better programmer ;-)
I set the WA_DeleteOnClose Attribute.
Good to know that. Thanks
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
clock = "clock"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
self.setWindowModality(QtCore.Qt.NonModal)
self.Note_Exit.clicked.connect(self.close)
self.parent_h = self.parent().geometry().height()
self.parent_w = self.parent().geometry().width()
self.parent_x = self.parent().geometry().x()
self.parent_y = self.parent().geometry().y()
self.dialog_w = self.width()
self.dialog_h = self.height()
self.setGeometry(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h)
## ScreenSize from parent
############################################################
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h-20, self.dialog_w, self.dialog_h))
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h))
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())

finplot candlestick chart does not render on launch when rendered as a widget

I have placed finplot candlestick chart as a widget. When launched, it comes up black on first render of app. If I zoom out, it starts to show up in the maximum zoomed state. How can I launch it in a state so that all candles that are inside the chart is displayed. Following is my entire code.
import sys
import finplot as fplt
import pandas as pd
import pyqtgraph as pg
import requests
from PyQt5.QtWidgets import *
# Creating the main window
class App(QMainWindow):
def __init__(self):
super().__init__()
self.title = 'PyQt5 - QTabWidget'
self.left = 0
self.top = 0
self.width = 1200
self.height = 800
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.tab_widget = MyTabWidget(self)
self.setCentralWidget(self.tab_widget)
self.show()
# Creating tab widgets
class MyTabWidget(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
self.layout = QVBoxLayout(self)
# Initialize tab screen
self.tabs = QTabWidget()
self.tabs.setTabPosition(QTabWidget.East)
self.tabs.setMovable(True)
self.tab1 = QWidget()
self.tabs.resize(600, 400)
# Add tabs
self.tabs.addTab(self.tab1, "tab1")
self.tab1.layout = QVBoxLayout(self)
self.tab1.label = QLabel("USDT-BTC")
self.tab1.fplt_widget = pg.PlotWidget(plotItem=fplt.create_plot_widget(self.window()))
self.tab1.btn = QPushButton("Press me")
# pull some data
symbol = 'USDT-BTC'
url = 'https://bittrex.com/Api/v2.0/pub/market/GetTicks?marketName=%s&tickInterval=fiveMin' % symbol
data = requests.get(url).json()
# format it in pandas
df = pd.DataFrame(data['result'])
df = df.rename(columns={'T':'time', 'O':'open', 'C':'close', 'H':'high', 'L':'low', 'V':'volume'})
df = df.astype({'time':'datetime64[ns]'})
candles = df[['time','open','close','high','low']]
fplt.candlestick_ochl(candles)
self.tab1.layout.addWidget(self.tab1.label)
self.tab1.layout.addWidget(self.tab1.fplt_widget)
self.tab1.layout.addWidget(self.tab1.btn)
self.tab1.setLayout(self.tab1.layout)
# Add tabs to widget
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Here is my app when launched:
Here it is when one scroll zoomed out
I want to see it as follows as soon as it launches
Thank you for posting full details of your problem.
Everything is almost there. You just need to add two things:
In your App.__init add one of the following lines just before calling self.show():
fplt.show(qt_exec=False)
or just
fplt.refresh()
Either choice will work because fplt.refresh() is called in either case. This autozooms your data plot, among other good things.
For the refresh call to work in either of the above choices, the window instance that you passed to fplt.create_plot_widget needs an axs attribute containing a list of your fplt widgets that you created. In your case, you wrap your fplt widget in a pg.PlotWidget, so the required widget reference becomes self.tab1.fplt_widget.plotItem (note the .plotItem there). Long story short: in MyTabWidget.__init__ insert this line before adding your widget to self.tab1.layout:
self.window().axs = [self.tab1.fplt_widget.plotItem]
Running your posted code with the above changes gives me the initial plot view that you desire.

Complex context-menu submenu

I have a Qt5 application mainly driven by context menu.
Right now I have the standard structure with menu(s), submenu(s) and actions.
I would like to add, in place of a submenu, a small dialog with a few input widgets, something like this:
Is there any (possibly simple) way to get this?
I know I can open a normal dialog from popup, but that is not what I mean.
I would like to have normal submenu behavior, with chance to go back to parent menu... if possible.
Note: I'm actually using PyQt5, but I think this is a more general Qt question.
Following #G.M. advice I was able to partially solve my problem.
My code current code looks like:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class ActionFont(QWidgetAction):
def __init__(self, parent: QWidget, target: QPlainTextEdit):
super(ActionFont, self).__init__(parent)
self.setIcon(QIcon("font-face.svg"))
self.setText("Face")
w = QFontComboBox()
w.currentFontChanged.connect(self.doit)
self.setDefaultWidget(w)
self.cursor = target.textCursor()
self.char_format = self.cursor.charFormat()
font = self.char_format.font()
w.setCurrentFont(font)
# self.triggered.connect(self.doit)
def doit(self, font):
self.char_format.setFont(font)
self.cursor.setCharFormat(self.char_format)
class ActionSize(QWidgetAction):
def __init__(self, parent: QWidget, target: QPlainTextEdit):
super(ActionSize, self).__init__(parent)
self.setIcon(QIcon("font-size.svg"))
self.setText("Size")
self.has_changed = False
w = QSpinBox()
self.setDefaultWidget(w)
self.cursor = target.textCursor()
self.char_format = self.cursor.charFormat()
font = self.char_format.font()
size = font.pointSize()
w.setRange(6, 100)
w.setValue(size)
w.valueChanged.connect(self.doit)
w.editingFinished.connect(self.quit)
def doit(self, size):
print(f'ActionSize.doit({size})')
self.char_format.setFontPointSize(size)
self.cursor.setCharFormat(self.char_format)
self.has_changed = True
def quit(self):
print(f'ActionSize.quit()')
if self.has_changed:
print(f'ActionSize.quit(quitting)')
class Window(QMainWindow):
def __init__(self, parent=None):
from lorem import text
super().__init__(parent)
self.text = QPlainTextEdit(self)
self.setCentralWidget(self.text)
self.text.setContextMenuPolicy(Qt.CustomContextMenu)
self.text.customContextMenuRequested.connect(self.context)
self.text.appendPlainText(text())
self.setGeometry(100, 100, 1030, 800)
self.setWindowTitle("Writer")
def context(self, pos):
m = QMenu(self)
w = QComboBox()
w.addItems(list('ABCDE'))
wa = QWidgetAction(self)
wa.setDefaultWidget(w)
m.addAction('Some action')
m.addAction(wa)
m.addAction('Some other action')
sub = QMenu(m)
sub.setTitle('Font')
sub.addAction(ActionFont(self, self.text))
sub.addAction(ActionSize(self, self.text))
m.addMenu(sub)
pos = self.mapToGlobal(pos)
m.move(pos)
m.show()
app = QApplication([])
w = Window()
w.show()
app.exec()
This works with a few limitations:
I have been able to add just a single widget using setDefaultWidget(), if I try to
add a fill QWidget or a container (e.g.: QFrame) nothing appears in menu.
I have therefore not been able to prepend an icon (or a QLabel) to the widget.
Widget does not behave like a menu item (it does not close when activated); I tried to overcome that as implemented in ActionSize, but looks rather kludgy and I'm unsure if it's the right way to go.
I will therefore not accept my own answer in hope someone can refine it enough to be generally useful.

How can I add a submit, output and input box using PyQt4?

I never tried creating a GUI with a language other than Java(kinda left it aside not long ago)
and started using Python.
made a simple program that calculates Pi to a certain digit as the user wishes.
Now, I created a window with PyQt4, made a button and got everything in place.
How can I add a input box so that the user could enter a number into it, make the button "Enter" the information and at the end of all that output it to the window instead of the terminal?
That's what I've got for now:
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from decimal import *
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 800, 600)
self.setWindowTitle("Pi's Nth Digit")
self.setWindowIcon(QtGui.QIcon('icon.jpg'))
self.buttons()
def buttons(self):
btn = QtGui.QPushButton("Quit",self)
btn1 = QtGui.QPushButton("Get Pi",self)
btn.clicked.connect(QtCore.QCoreApplication.instance().quit)
btn1.clicked.connect(self.getpi())
btn1.resize(btn1.sizeHint())
btn.resize(btn.sizeHint())
btn1.move(350,500)
btn.move(450,500)
self.show()
def start():
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
start()
don't mind the getpi function.
Thanks! :)
You would want to use a QLineEdit or a QSpinBox for a number. If you want multiple things in a widget you would use a layout. A QMainWindow typically has one central widget and toolbars and dock widgets.
class Window(QtGui.QMainWindow):
def __init__(self):
super().__init__()
self.container = QtGui.QWidget()
self.setCentralWidget(self.container)
self.container_lay = QtGui.QVBoxLayout()
self.container.setLayout(self.container_lay)
# Input
self.le = QtGui.QLineEdit()
self.container_lay.addWidget(self.le)
# enter button
self.enter_btn = QtGui.QPushButton("Enter")
self.container_lay.addWidget(self.enter_btn)
self.enter_btn.clicked.connect(self.run) # No '()' on run you want to reference the method.
# display
self.container_lay.addWidget(QtGui.QLabel("Answer:"))
self.ans = QtGui.QLabel()
self.container_lay.addWidget(self.ans)
def run(self):
precision = self.le.text()
pi = str(round(math.pi, precision)) # probably different formatting
self.ans.setText(pi)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
You have almost everything, just add a QLineEdit to get the input and a QLabel where to show the result (with QLabel.setText).

Why is this implementation of a QGraphicsScene causing the app to crash on exit?

I'm using Qt's Graphics View Framework to display a large number of images, and implementing it using PyQt4 and Python 2.7. I instantiate a number of QPixmapItem objects and add them to my QGraphicsScene. It all works as I'd expect it to until I exit the application, and the program crashes instead of exiting normally.
class ImgDisplay(QtGui.QWidget):
NUM_ITEMS = 5000
VIEW_WIDTH,VIEW_HEIGHT = 400, 400
def __init__(self):
super(ImgDisplay, self).__init__()
self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT))
self.view = QtGui.QGraphicsView(self.scene)
self.view.setParent(self)
#Load the texture
self.texture = QtGui.QPixmap('image.png')
self.populateScene()
def populateScene(self):
for i in range(0, ImgDisplay.NUM_ITEMS-1):
item = QtGui.QGraphicsPixmapItem(self.texture)
self.scene.addItem(item)
I'm thinking that all those PixMapItems I'm creating aren't being cleaned up properly, or maybe I need to free the texture that I load (there doesn't seem to be a method to free it, so I assumed it happened in the background).
I've tried calling self.scene.clear in a destructor to delete the PixmapItems, but it didn't help.
Any suggestions on how I can fix this problem?
*I'm aware that the posted code just puts the images all on top of each other, my actual program assigns them random positions and rotations, but I wanted to reduce this to the minimal problem.
OK, understood. Problem is QtGui.QGraphicsPixmapItem can't clear itself your have to manual just like you says, but not destructor. I recommend doing after have signal close program by using closeEvent, like this;
def closeEvent (self, eventQCloseEvent):
self.scene.clear() # Clear QGraphicsPixmapItem
eventQCloseEvent.accept() # Accept to close program
and this implemented you code;
import sys
from PyQt4 import QtCore, QtGui
class ImgDisplay (QtGui.QWidget):
NUM_ITEMS = 5000
VIEW_WIDTH,VIEW_HEIGHT = 400, 400
def __init__ (self):
super(ImgDisplay, self).__init__()
self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT))
self.view = QtGui.QGraphicsView(self.scene)
self.view.setParent(self)
#Load the texture
self.texture = QtGui.QPixmap('image.png')
self.populateScene()
def populateScene (self):
for i in range(0, ImgDisplay.NUM_ITEMS-1):
item = QtGui.QGraphicsPixmapItem(self.texture)
self.scene.addItem(item)
def closeEvent (self, eventQCloseEvent):
self.scene.clear()
eventQCloseEvent.accept()
app = QtGui.QApplication([])
window = ImgDisplay()
window.show()
sys.exit(app.exec_())
I use PyQt4 (Windows 7).
And this useful to implement close event, Hope is helps;
QWidget Close Event Reference : http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html#closeEvent
LAST EDITED : 8 / 11 / 2014 01:51
If your want to control your parent & child widget to delete together, I have to implement destructor method (As your say). By use safe delete method QObject.deleteLater (self), Like this;
import sys
from PyQt4 import QtCore, QtGui
class ImgDisplay (QtGui.QWidget):
NUM_ITEMS = 5000
VIEW_WIDTH, VIEW_HEIGHT = 400, 400
def __init__ (self, parent = None):
super(ImgDisplay, self).__init__(parent)
self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT), parent = self)
self.view = QtGui.QGraphicsView(self.scene, parent = self)
#Load the texture
self.texture = QtGui.QPixmap('image.png')
self.populateScene()
def populateScene (self):
for i in range(0, ImgDisplay.NUM_ITEMS-1):
item = QtGui.QGraphicsPixmapItem(self.texture)
self.scene.addItem(item)
def __del__ (self):
self.deleteLater() # Schedules this object for deletion
app = QtGui.QApplication([])
window = ImgDisplay()
window.show()
sys.exit(app.exec_())
Warning : Don't forget set parent in your widget ! (Because some time It can't be delete itself.)
deleteLater Reference : http://pyqt.sourceforge.net/Docs/PyQt4/qobject.html#deleteLater
Regards,
I would like to highlight Josh's answer in the comments.
If you create the scene by setting the QGraphicsView as parent the crash will automatically go away.
self.view = QtGui.QGraphicsView(parent = self)
self.scene = QtGui.QGraphicsScene(QtCore.QRectF(0,0,ImgDisplay.VIEW_WIDTH,ImgDisplay.VIEW_HEIGHT), parent = self.view)
self.view.setScene(self.scene)

Categories