I have this code:
import sys, random, pprint
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5 import QtGui
from PyQt5.QtCore import Qt
class Window(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(QtCore.QRect(200, 200, 700, 700))
self.widget = QtWidgets.QWidget(self)
self.widget.setGeometry(QtCore.QRect(10, 10, 400, 200))
self.widget.setObjectName("widget")
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self.widget)
self.drawPoints(painter)
painter.end()
def drawPoints(self, painter):
#drawing code
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = Window()
ex.show()
sys.exit(app.exec_())
What do i expect: area (400x200) which would be painted by drawPoints(). QWidget inherits QPaintDevice. So this code should work. But console says:
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::end: Painter not active, aborted
Could you help me, please.
It looks like you are attempting to replicate this example, correct?
The major difference appears to be that you are defining paintEvent() for the main window, rather than the widget you are actually trying to paint. It would work if you created a custom subclass of QWidget, defined paintEvent() there, and then inserted that into a standard QMainWindow instance, like this:
class MyWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent=parent)
self.initUI()
def initUI(self):
self.setGeometry(QtCore.QRect(10, 10, 400, 200))
self.setObjectName("widget")
def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
self.drawPoints(painter)
painter.end()
def drawPoints(self, painter):
pass
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
my_window = QtWidgets.QMainWindow()
my_window.setGeometry(QtCore.QRect(200, 200, 700, 700))
my_window.setCentralWidget(MyWidget(my_window))
my_window.show()
sys.exit(app.exec_())
At the very least, it isn't printing that error message anymore.
Related
Im trying to overlay an image with transparency on QCameraViewfinder. The following code works fine on windows, but ignores the transparency on raspberry pi.
Im using pyside2 version 5.11.2 on RPI4 and tried tranparent PNG and SVG files.
As an alternative, if Im using paintEvent to draw shapes, the viewfinder doesnt show video. My QPainter code is attached too.
from PySide2.QtMultimedia import QCamera, QCameraInfo
from PySide2.QtMultimediaWidgets import QCameraViewfinder
from PySide2 import QtCore, QtGui
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *
import sys
class ExampleWindow(QMainWindow):
def __init__(self, windowsize):
super().__init__()
self.windowsize = windowsize
self.initUI()
def initUI(self):
self.setFixedSize(self.windowsize)
widget = QWidget()
self.setCentralWidget(widget)
self.view_finder = QCameraViewfinder()
camerainfo = QCameraInfo.availableCameras()[0]
self.camera = QCamera(camerainfo)
self.camera.setViewfinder(self.view_finder)
self.camera.start()
layout_box = QHBoxLayout(widget)
layout_box.setContentsMargins(0, 0, 0, 0)
layout_box.addWidget(self.view_finder)
pixmap = QPixmap('crosshair3.png')
self.image = QLabel(widget)
self.image.setPixmap(pixmap)
self.image.setFixedSize(pixmap.size())
hw = pixmap.size().width()/2
hh = pixmap.size().height()/2
self.image.move(self.rect().center().x()-hw, self.rect().center().y()-hh)
if __name__ == '__main__':
app = QApplication(sys.argv)
screensize = app.desktop().availableGeometry().size()
ex = ExampleWindow(screensize)
ex.show()
sys.exit(app.exec_())
When using QPainter there is no video on the viewfinder:
class MyQCameraViewfinder(QCameraViewfinder):
def __init__(self, parent=None):
super().__init__(parent)
def paintEvent(self, event):
paint = QtGui.QPainter()
paint.begin(self)
paint.setRenderHint(QtGui.QPainter.Antialiasing)
paint.setPen(QtCore.Qt.black)
paint.setBrush(QtCore.Qt.white)
paint.drawEllipse(QtCore.QRect(17, 22, 50, 50))
paint.end()
on windows 11:
on rpi 4:
AttributeError: type object 'QThread' has no attribute 'create'
Here is my code.
from PyQt5.QtCore import QThread
def fun(num):
print(num)
thread1 = QThread.create(fun)
thread1.start()
But Qt documentation says there is a function called create since Qt 5.10. I am using PyQt5 5.11.3. Someone please help me with this.
You can use worker objects by moving them to the thread using QObject::moveToThread().
from PyQt5.QtCore import QObject, pyqtSignal, QThread, QTimer
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QProgressBar, QPushButton
class Worker(QObject):
valueChanged = pyqtSignal(int) # Value change signal
def run(self):
print('thread id ->', int(QThread.currentThreadId()))
for i in range(1, 101):
print('value =', i)
self.valueChanged.emit(i)
QThread.msleep(100)
class Window(QWidget):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
layout = QVBoxLayout(self)
self.progressBar = QProgressBar(self)
self.progressBar.setRange(0, 100)
layout.addWidget(self.progressBar)
layout.addWidget(QPushButton('Open thread', self, clicked=self.onStart))
# Current thread id
print('main id = ', int(QThread.currentThreadId()))
# Start thread update progress bar value
self._thread = QThread(self)
self._worker = Worker()
self._worker.moveToThread(self._thread) # Move to thread to execute
self._thread.finished.connect(self._worker.deleteLater)
self._worker.valueChanged.connect(self.progressBar.setValue)
def onStart(self):
print('main id -> ', int(QThread.currentThreadId()))
self._thread.start() # Start thread
QTimer.singleShot(1, self._worker.run)
def closeEvent(self, event):
if self._thread.isRunning():
self._thread.quit()
del self._thread
del self._worker
super(Window, self).closeEvent(event)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Window()
w.show()
w.setWindowTitle('Demo moveToThread')
sys.exit(app.exec_())
I'm trying to display files and folders like column view in Mac finder.
I was able get the basic structure with the help of ListViews and QFileSystemModel. Then I set the splitter handle as a corner widget for the scroll area. I have two issues here
When I resize the listview, the splitter handle disappears.
Even after setting the splitter handle width to 0, I see spacing between
listviews.
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
import os
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class PopulateList(QtGui.QDialog):
def __init__(self,parent=None):
super().__init__(parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.setModel()
self.show()
self.ui.splitter.setHandleWidth(0)#not working
self.ui.listView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.ui.listView.setCornerWidget(self.getCornerWidget(self.ui.splitter))
self.ui.closePushButton.clicked.connect(self.close)
self.ui.listView.clicked.connect(self.showSubFiles)
def getCornerWidget(self, splitter):
self.handle=splitter.handle(1)
layout=QtGui.QHBoxLayout(self.handle)
layout.setSpacing(0)
layout.setMargin(0)
for i in range(0,2):
line = QtGui.QFrame(self.handle)
line.setFrameShape(QtGui.QFrame.VLine)
layout.addWidget(line)
return self.handle
def showSubFiles(self, index):
root_path = self.model.fileInfo(index).absoluteFilePath()
self.model1=QtGui.QFileSystemModel()
self.model1.setRootPath(root_path)
self.ui.listView_1.setModel(self.model1)
self.ui.listView_1.setRootIndex(self.model1.index(root_path))
def setModel(self):
root_path=os.path.expanduser("~")
self.model=QtGui.QFileSystemModel()
self.model.setRootPath(root_path)
self.model.setFilter(QtCore.QDir.NoDotAndDotDot | QtCore.QDir.Dirs)
self.ui.listView.setModel(self.model)
self.ui.listView.setRootIndex(self.model.index(root_path))
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(602, 365)
self.verticalLayout = QtGui.QVBoxLayout(Form)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.splitter = QtGui.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Horizontal)
self.splitter.setObjectName(_fromUtf8("splitter"))
self.listView = QtGui.QListView(self.splitter)
self.listView.setObjectName(_fromUtf8("listView"))
self.listView_1 = QtGui.QListView(self.splitter)
self.listView_1.setObjectName(_fromUtf8("listView_1"))
self.verticalLayout.addWidget(self.splitter)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.closePushButton = QtGui.QPushButton(Form)
self.closePushButton.setObjectName(_fromUtf8("closePushButton"))
self.horizontalLayout.addWidget(self.closePushButton)
self.verticalLayout.addLayout(self.horizontalLayout)
self.verticalLayout.setStretch(0, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(_translate("Form", "Form", None))
self.closePushButton.setText(_translate("Form", "Close", None))
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
listView=PopulateList()
sys.exit(app.exec_())
Are you able to use QColumnView? It is exactly this.
http://doc.qt.io/qt-5/qcolumnview.html
import sys
from PyQt5 import QtWidgets, QtCore
app = QtWidgets.QApplication(sys.argv)
model = QtWidgets.QFileSystemModel()
view = QtWidgets.QColumnView()
view.setModel(model)
model.setRootPath("/")
view.show()
sys.exit(app.exec())
I am trying to animate the window in startup but it doesn't seem to work, I have written the code below.
from PyQt4 import QtCore,QtGui
import sys
class AnimatedWindow(QtGui.QMainWindow):
"""docstring for AnimatedWindow"""
def __init__(self):
super(AnimatedWindow, self).__init__()
animation = QtCore.QPropertyAnimation(self, "geometry")
animation.setDuration(10000);
animation.setStartValue(QtCore.QRect(0, 0, 100, 30));
animation.setEndValue(QtCore.QRect(250, 250, 100, 30));
animation.start();
if __name__ == "__main__":
application = QtGui.QApplication(sys.argv)
main = AnimatedWindow()
main.show()
sys.exit(application.exec_())
The problem with this code is, when you create an object of QPropertyAnimation it is destroyed by the python garbage collector after animation.start() statement as animation variable is a local variable, hence the animation does not take place. To overcome this problem you need to make the animation as member variable (self.animation)
Here is the updated code which works fine:
from PyQt4 import QtCore,QtGui
import sys
class AnimatedWindow(QtGui.QMainWindow):
"""docstring for AnimatedWindow"""
def __init__(self):
super(AnimatedWindow, self).__init__()
self.animation = QtCore.QPropertyAnimation(self, "geometry")
self.animation.setDuration(1000);
self.animation.setStartValue(QtCore.QRect(50, 50, 100, 30));
self.animation.setEndValue(QtCore.QRect(250, 250, 500, 530));
self.animation.start();
if __name__ == "__main__":
application = QtGui.QApplication(sys.argv)
main = AnimatedWindow()
main.show()
sys.exit(application.exec_())
I created a widget in qt designer and transformed the ui file using pyuic to a python class called Ui_wid_canvas. This is supposed to be used as special canvas:
# file mgcanvas.py
from PyQt4 import QtCore, QtGui
class Ui_wid_canvas(object):
def setupUi(self, wid_canvas):
wid_canvas.setObjectName("wid_canvas")
wid_canvas.resize(400, 300)
self.horizontalLayout = QtGui.QHBoxLayout(wid_canvas)
self.horizontalLayout.setObjectName("horizontalLayout")
self.pushButton = QtGui.QPushButton(wid_canvas)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout.addWidget(self.pushButton)
self.retranslateUi(wid_canvas)
QtCore.QMetaObject.connectSlotsByName(wid_canvas)
def retranslateUi(self, wid_canvas):
wid_canvas.setWindowTitle(QtGui.QApplication.translate("wid_canvas", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton.setText(QtGui.QApplication.translate("wid_canvas", "PushButton", None, QtGui.QApplication.UnicodeUTF8))
From Ui_wid_canvas I derive a class MyCanvas to implement the paintEvent function and some utility functions such as moo(). Within the paintevent all it shall do is draw two rects. If I use the following class as my application everything works like a charm.
# file mycanvas.py
from PyQt4 import QtCore, QtGui
import mgcanvas
class MyCanvas(mgcanvas.Ui_wid_canvas, QtGui.QWidget):
def __init__(self):
super(mgcanvas.Ui_wid_canvas, self).__init__()
self.setupUi(self)
def paintEvent(self, qpaintevent):
print "PaintEvent canvas"
painter = QtGui.QPainter(self)
painter.setBrush(QtGui.QColor(255,0,0,80))
painter.setPen(QtGui.QColor(00,00,00,255))
painter.drawRect(10,10,100,100)
r = QtCore.QRectF(110,110,100,100)
painter.drawRect(r)
painter.drawText(r,"Hello", QtGui.QTextOption(QtCore.Qt.AlignCenter))
def moo(self):
print "This is canvas mooing"
Now, when I create an application Test instantiating MyCanvas (see below), the paintEvent for Test is called, but the paintevent for MyCanvcas is never called, the rects are not drawn and no output "Paintevent Canvas" on the console. If I call self.widget.update() or self.widget.redraw() in Test.paintevent() the paintevent is not caught. If I call self.widget.paintevent() manually, the function is called, but the painter not activated. The pushbutton, on the other hand, is shown from which I figure that the widget is included correctly, but just not the paint event is called by the child widget.
# file test.py; executed with `python test.py`
from PyQt4 import QtCore, QtGui
import mycanvas
class Test(object):
def setupUi(self, Gui):
self.counter = 0
Gui.setObjectName("TestObject")
Gui.resize(500,500)
self.layout = QtGui.QVBoxLayout()
self.widget = mycanvas.MyCanvas()
self.widget.setupUi(self)
self.widget.setObjectName("wid_canvas")
self.layout.addWidget(self.widget)
self.retranslateUi(Gui)
QtCore.QMetaObject.connectSlotsByName(Gui)
def retranslateUi(self, Gui):
Gui.setWindowTitle(QtGui.QApplication.translate("TestObject", "Title", None, QtGui.QApplication.UnicodeUTF8))
def paintEvent(self, qpaintevent):
print "---> Enter"
self.counter += 1
print "counter", self.counter
self.widget.repaint()
self.widget.moo()
print "<-- Leave"
class MyTest(Test, QtGui.QWidget):
def __init__(self):
super(Test, self).__init__()
self.setupUi(self)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
ui = MyTest()
ui.show()
sys.exit(app.exec_())
Setting the Qt.WA_PaintOutsidePaintEvent is not an option, because it does not work on Mac and Windows but I'd like to stay platform independent.
Please excuse me posting so much code, but I guess it will make things easier. I tried to keep it to a minimum. Can someone tell me how I can have the Widget MyCanvas paint on itself and include this painting widget in another widget MyTest, which will work as the application?
In you class Test, you didn't attach the layout to the parameter Gui, by passing it as parameter to QVBoxLayout, and you called the self.widget.setupUi for MyCanvas although it was already called by MyCanvas constructor.
class Test(object):
def setupUi(self, Gui):
self.counter = 0
Gui.setObjectName("TestObject")
Gui.resize(500,500)
self.layout = QtGui.QVBoxLayout(Gui)
self.widget = mycanvas.MyCanvas()
self.widget.setObjectName("wid_canvas")
self.layout.addWidget(self.widget)
self.retranslateUi(Gui)
QtCore.QMetaObject.connectSlotsByName(Gui)