When two widget animation commands run at start only one gets animated - python

I am trying hide two list widgets upon start by animating the maximum width to zero, then two buttons to toggle each widget to appear and disappear, this works fine, but not at start, only one of the two widget gets animated, the other just stays on, but the same command works fine when signaled by the push buttons.
Please suggest if there is any better approach to achieve the same effect or the reason behind it.
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtCore import QPropertyAnimation
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(640, 480)
self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
self.horizontalLayout.setObjectName("horizontalLayout")
self.frame = QtWidgets.QFrame(Form)
self.frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
self.frame.setObjectName("frame")
self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
self.verticalLayout.setObjectName("verticalLayout")
self.pushButton = QtWidgets.QPushButton(self.frame)
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton)
self.pushButton_2 = QtWidgets.QPushButton(self.frame)
self.pushButton_2.setObjectName("pushButton_2")
self.verticalLayout.addWidget(self.pushButton_2)
self.pushButton_3 = QtWidgets.QPushButton(self.frame)
self.pushButton_3.setObjectName("pushButton_3")
self.verticalLayout.addWidget(self.pushButton_3)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.horizontalLayout.addWidget(self.frame)
self.listWidget = QtWidgets.QListWidget(Form)
self.listWidget.setObjectName("listWidget")
self.horizontalLayout.addWidget(self.listWidget)
self.listWidget_2 = QtWidgets.QListWidget(Form)
self.listWidget_2.setObjectName("listWidget_2")
self.horizontalLayout.addWidget(self.listWidget_2)
self.listWidget_3 = QtWidgets.QListWidget(Form)
self.listWidget_3.setObjectName("listWidget_3")
self.horizontalLayout.addWidget(self.listWidget_3)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
# Trying to Hide both widgets upon start, but one gets hidden
self.animate_listwidget2()
self.animate_listwidget3()
self.pushButton_2.clicked.connect(self.animate_listwidget2)
self.pushButton_3.clicked.connect(self.animate_listwidget3)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "PushButton"))
self.pushButton_2.setText(_translate("Form", "toggle lw2"))
self.pushButton_3.setText(_translate("Form", "toggle lw3"))
def animate_listwidget2(self):
width = self.listWidget_2.width()
if width != 0:
width1 = 0
else:
width1 = 350
self.animation = QPropertyAnimation(self.listWidget_2, b'maximumWidth')
self.animation.setDuration(800)
self.animation.setStartValue(width)
self.animation.setEndValue(width1)
self.animation.setEasingCurve(QtCore.QEasingCurve.Type.Linear)
self.animation.start()
def animate_listwidget3(self):
width = self.listWidget_3.width()
if width != 0:
width1 = 0
else:
width1 = 350
self.animation = QPropertyAnimation(self.listWidget_3, b'maximumWidth')
self.animation.setDuration(800)
self.animation.setStartValue(width)
self.animation.setEndValue(width1)
self.animation.setEasingCurve(QtCore.QEasingCurve.Type.Linear)
self.animation.start()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec())

First of all you should not modify the code generated by QtDesigner since that could cause other bugs so to apply my solutions you have to restore the file and call it gui.py
The problem is that using the same attribute is destroying the previous animation.
There are several solutions such as changing the name of the attribute assigned to one of them (for example, changing the name of the second to self.animation2) but the implementation can still be improved since with the current one, animations are always being created unnecessarily since one is enough single for each QListWidget.
from PyQt6.QtCore import QEasingCurve, QPropertyAnimation
from PyQt6.QtWidgets import QApplication, QWidget
from gui import Ui_Form
class Form(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.pushButton_2.clicked.connect(self.animate_listwidget2)
self.ui.pushButton_3.clicked.connect(self.animate_listwidget3)
self.animation1 = self.build_animation(self.ui.listWidget_2)
self.animation2 = self.build_animation(self.ui.listWidget_3)
self.animate_listwidget2()
self.animate_listwidget3()
def build_animation(self, listwidget):
animation = QPropertyAnimation(listwidget, b"maximumWidth")
animation.setDuration(800)
animation.setEasingCurve(QEasingCurve.Type.Linear)
return animation
def start_animation(self, animation):
width = animation.targetObject().width()
animation.stop()
animation.setStartValue(width)
animation.setEndValue(0 if width != 0 else 350)
animation.start()
def animate_listwidget2(self):
self.start_animation(self.animation1)
def animate_listwidget3(self):
self.start_animation(self.animation2)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = Form()
w.show()
sys.exit(app.exec())

Related

Keep aspect ratio of image in a QLabel whilst resizing window

Say i have a layout like this:
I want the ratio of the left object and the right object to always be like this:
So that i can add a small image in the top left corner that wont be gigantic or too small, but always in nice relation to the size of the window. How can i do this, either in the designer, or in the code?
I already found that you seem to be able to do this via selecting the layout and changing the LayoutStretch to something like 1,3 - this worked in the designer, however, when i inserted my image in the code, it did not respect it and blew the layout out of proption again.
I added a stretcher and used a QLabel to display the image, and then added the file via self.LogoLabel.setPixmap(QtGui.QPixmap('res/image.png')) , so i do not understand what i need to change in order to get the image to always be nice and small in the top left corner.
A test example, in case the question wasnt clear enough - the image i need is 1000x710px large.
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
class Ui_ZEBRA(object):
def setupUi(self, ZEBRA):
ZEBRA.setObjectName("ZEBRA")
ZEBRA.resize(315, 134)
self.centralwidget = QtWidgets.QWidget(ZEBRA)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setContentsMargins(-1, -1, -1, 0)
self.horizontalLayout.setSpacing(0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout_3 = QtWidgets.QVBoxLayout()
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.LogoLabel = QtWidgets.QLabel(self.centralwidget)
self.LogoLabel.setText("")
self.LogoLabel.setScaledContents(True)
self.LogoLabel.setObjectName("LogoLabel")
self.verticalLayout_3.addWidget(self.LogoLabel)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout_3.addItem(spacerItem)
self.ComboBox_InputType = QtWidgets.QComboBox(self.centralwidget)
self.ComboBox_InputType.setObjectName("ComboBox_InputType")
self.ComboBox_InputType.addItem("")
self.ComboBox_InputType.addItem("")
self.ComboBox_InputType.addItem("")
self.ComboBox_InputType.addItem("")
self.verticalLayout_3.addWidget(self.ComboBox_InputType)
self.horizontalLayout.addLayout(self.verticalLayout_3)
self.TextInput_Devices = QtWidgets.QPlainTextEdit(self.centralwidget)
self.TextInput_Devices.setObjectName("TextInput_Devices")
self.horizontalLayout.addWidget(self.TextInput_Devices)
self.horizontalLayout.setStretch(0, 1)
self.horizontalLayout.setStretch(1, 3)
self.verticalLayout_4.addLayout(self.horizontalLayout)
ZEBRA.setCentralWidget(self.centralwidget)
self.menuBar_EnterToken = QtWidgets.QAction(ZEBRA)
self.menuBar_EnterToken.setObjectName("menuBar_EnterToken")
self.menuBar_TestToken = QtWidgets.QAction(ZEBRA)
self.menuBar_TestToken.setObjectName("menuBar_TestToken")
self.menuBar_About = QtWidgets.QAction(ZEBRA)
self.menuBar_About.setObjectName("menuBar_About")
self.retranslateUi(ZEBRA)
QtCore.QMetaObject.connectSlotsByName(ZEBRA)
def retranslateUi(self, ZEBRA):
_translate = QtCore.QCoreApplication.translate
ZEBRA.setWindowTitle(_translate("ZEBRA", "ZEBRA"))
self.ComboBox_InputType.setItemText(0, _translate("ZEBRA", "ip"))
self.ComboBox_InputType.setItemText(1, _translate("ZEBRA", "Use all devices"))
self.ComboBox_InputType.setItemText(2, _translate("ZEBRA", "displayName"))
self.ComboBox_InputType.setItemText(3, _translate("ZEBRA", "id"))
self.menuBar_EnterToken.setText(_translate("ZEBRA", "Enter Accesstoken"))
self.menuBar_TestToken.setText(_translate("ZEBRA", "Test Accesstoken"))
self.menuBar_About.setText(_translate("ZEBRA", "About..."))
class Test(QtWidgets.QMainWindow, Ui_ZEBRA):
def __init__(self, parent=None):
super(Test, self).__init__(parent)
self.setupUi(self)
self.LogoLabel.setPixmap(QtGui.QPixmap('res/image.png'))
def main():
app = QtWidgets.QApplication(sys.argv)
form = Test()
form.show()
app.exec_()
if __name__ == '__main__':
main()
EDIT: Weirdly enough, i could not find a single working example on how to use an image in a QLabel and scale its size while changing the window size, while also keeping the aspect ratio. Such a basic thing that is nowhere to be found?
You firstly need to change the layout so that it uses alignment rather than expanding spacers to keep the label at the top left corner. Also, some properties of the label need adjustment so that it can resize itself freely. This can all be done in Qt Designer, but your example code can also be fixed manually like this:
self.LogoLabel = QtWidgets.QLabel(self.centralwidget)
self.LogoLabel.setText("")
self.LogoLabel.setObjectName("LogoLabel")
# new stuff
self.LogoLabel.setScaledContents(False)
self.LogoLabel.setMinimumSize(1, 1)
self.LogoLabel.setSizePolicy(
QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
self.LogoLabel.setAlignment(QtCore.Qt.AlignTop)
self.verticalLayout_3.setAlignment(QtCore.Qt.AlignTop)
self.verticalLayout_3.addWidget(self.LogoLabel)
The dynamic resizing can then be handled using an event-filter, like this:
class Test(QtWidgets.QMainWindow, Ui_ZEBRA):
def __init__(self, parent=None):
super(Test, self).__init__(parent)
self.setupUi(self)
self._logo = QtGui.QPixmap('res/image.png')
self.LogoLabel.setPixmap(self._logo)
self.LogoLabel.installEventFilter(self)
def eventFilter(self, widget, event):
if event.type() == QtCore.QEvent.Resize and widget is self.LogoLabel:
self.LogoLabel.setPixmap(self._logo.scaled(
self.LogoLabel.width(), self.LogoLabel.height(),
QtCore.Qt.KeepAspectRatio))
return True
return super(Test, self).eventFilter(widget, event)
To scale the image down as you wanted and keep the ratio between the two elements, you need to set setScaledContents(True) like this:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(559, 289)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.label = QtWidgets.QLabel(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Ignored)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
self.label.setSizePolicy(sizePolicy)
self.label.setScaledContents(True)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setObjectName("comboBox")
self.verticalLayout.addWidget(self.comboBox)
self.horizontalLayout.addLayout(self.verticalLayout)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
self.textBrowser.setObjectName("textBrowser")
self.horizontalLayout.addWidget(self.textBrowser)
self.horizontalLayout.setStretch(0, 1)
self.horizontalLayout.setStretch(2, 3)
self.verticalLayout_2.addLayout(self.horizontalLayout)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "TextLabel"))
import sys
class Test(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Test, self).__init__(parent)
self.setupUi(self)
pixmap = QtGui.QPixmap('res/image.png')
pixmap = pixmap.scaled(256, 128, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
self.label.setPixmap(pixmap)
self.label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
def main():
app = QtWidgets.QApplication(sys.argv)
form = Test()
form.show()
app.exec_()
if __name__ == '__main__':
main()
In order to keep the aspect ratio - i think you have to use a resizeEvent of the Widget containing the Label which changes the size to the correct aspect ratio whenever the event is triggered.

How to make a loop and AutoClosed messagebox in PyQt5?

How to make a loop and AutoClosed messagebox in PyQt5?
Here is a kind of messagebox that can auto close after 3sec.
I want to show the message by using it in a loop.
How can i do it?
PS:the code is not writen by me
import sys
from PyQt5 import QtCore, QtGui, QtWidgets, Qt
import time
class Ui_Message(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(538, 91)
self.frame = QtWidgets.QFrame(Form)
self.frame.setGeometry(QtCore.QRect(0, 0, 541, 111))
# self.frame.setStyleSheet("background-image: url(:/img/messageback.png);")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.label = QtWidgets.QLabel(self.frame)
self.label.setGeometry(QtCore.QRect(0, 0, 531, 91))
font = QtGui.QFont()
font.setPointSize(31)
font.setBold(False)
font.setWeight(50)
self.label.setFont(font)
self.label.setStyleSheet("background-color: transparent;\n"
"fontsize: 30px;")
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "显示信息"))
# import img_rc
# Define a removable borderless 3S prompt message interface
class MessageWindow(Qt.QMainWindow):
def __init__(self, parent=None):
Qt.QWidget.__init__(self, parent)
self.ui = Ui_Message()
self.ui.setupUi(self)
self.setWindowFlags(Qt.Qt.FramelessWindowHint)
QtCore.QTimer().singleShot(3000, self.close)
self.show()
def mousePressEvent(self, event):
# Define mouse click events
if event.button() == QtCore.Qt.LeftButton:
self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
event.accept()
def mouseMoveEvent(self, event):
# Define mouse movement events
if event.buttons() == QtCore.Qt.LeftButton:
self.move(event.globalPos() - self.dragPosition)
event.accept()
def setMessage(self, message):
self.ui.label.setText(message)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
login = MessageWindow()
#----how can i maike a loop messagebox?------
for i in range(0,5):
login.setMessage("Number"+str(i))
time.sleep(3)
sys.exit(app.exec())
I know maybe i can't use time.sleep in PyQt5,however i had search for anything but not get the answer.
In Qt if you want to do a periodic task then you must use a QTimer, and forget about synchronous logic since you must work through events.
In this case a possible solution is to use a queue that stores the information and in each shot of the timer an element is obtained.
from collections import deque
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
login = MessageWindow()
values = range(0, 5)
q = deque(values)
def on_timeout():
print(q)
if q:
i = q.popleft()
Qt.QTimer.singleShot(3000, on_timeout)
login.setMessage("Number" + str(i))
on_timeout()
sys.exit(app.exec())
Notes:
Your class must not inherit from QMainWindow but from QWidget.
You must eliminate the timer that closes the window, otherwise you will not see the text change since the time is very short.

QGraphicsScene. How do I draw an ellipse over a loaded image in pyqt5?

I have a QGraphicsView with a QGraphicsScene. On QGraphicsScene, I output the image using QGraphicsPixmapItem. And I would like to draw an ellipse over the image with my mouse.
I have that code now. And the ellipse is drawn on MainWindow.
What do I need to do to have the ellipse drawn on an image in QGraphicsView?
Code OFT_MainWindow
# OFT_MainWindow
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(862, 710)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView.setGeometry(QtCore.QRect(10, 90, 841, 571))
self.graphicsView.setMouseTracking(True)
self.graphicsView.setObjectName("graphicsView")
self.buttonBox = QtWidgets.QDialogButtonBox(self.centralwidget)
self.buttonBox.setGeometry(QtCore.QRect(360, 670, 81, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.buttonBox.setFont(font)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(760, 10, 91, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.pushButton.setFont(font)
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(10, 10, 731, 31))
self.lineEdit.setObjectName("lineEdit")
self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_2.setGeometry(QtCore.QRect(10, 670, 331, 31))
self.lineEdit_2.setObjectName("lineEdit_2")
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(10, 50, 841, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.pushButton_2.setFont(font)
self.pushButton_2.setObjectName("pushButton_2")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Browse"))
self.pushButton_2.setText(_translate("MainWindow", "Highlight field area"))
Main code
import OFT_MainWindow
import sys
import os
import numpy as np
import cv2
from PIL import Image, ImageQt, ImageEnhance
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.Qt import Qt
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
class MainWindow(QtWidgets.QMainWindow, OFT_MainWindow.Ui_MainWindow, QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.browse_file)
self.pushButton_2.clicked.connect(self.imageFrame)
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.show()
###################################################################################
def browse_file(self):
self.lineEdit.clear()
file = QtWidgets.QFileDialog.getOpenFileName(self, "Choose file")
file = str(file[0])
if file:
self.lineEdit.setText(file) # добавить путь в lineEdit
# cap = cv2.VideoCapture(file)
###################################################################################
def imageFrame(self):
file = self.lineEdit.text()
self.drawing = False
self.lastPoint = QPoint()
scene = QtWidgets.QGraphicsScene(self)
self.image = QPixmap(file)
item = QtWidgets.QGraphicsPixmapItem(self.image)
scene.addItem(item)
view = self.graphicsView.setScene(scene)
# self.show()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
br = QtGui.QBrush(QtGui.QColor(0, 255, 0, 25))
qp.setBrush(br)
ellipse = qp.drawEllipse(QtCore.QRect(self.begin, self.end))
coord_a = self.begin
coord_a = str(coord_a)
coord_a = coord_a[20:][:-1]
coord_b = self.end
coord_b = str(coord_b)
coord_b = coord_b[20:][:-1]
coord = ('begin = ' + coord_a + ' end = ' + coord_b)
self.lineEdit_2.setText(coord)
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
###################################################################################
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.aboutToQuit.connect(app.deleteLater)
sys.exit(app.exec_())
If you want to paint something on a QGraphicsView, you have to add QGraphicsItem to its scene, otherwise you're making almost useless to crete a QGraphicsView to begin with.
One possible solution is to install an event filter on the scene, listen for mouse button events and draw an ellipse (using QGraphicsEllipseItem) on the scene if the first click is done within the contents of a QGraphicsPixmapItem.
Note that another possibility is to subclass from QGraphicsPixmapItem and implement its mouse events instead. It all depends on what you're going to do and what you're going to need from your program.
class MainWindow(QtWidgets.QMainWindow, OFT_MainWindow.Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
# ...
self.ellipseItem = None
def imageFrame(self):
# ...
scene.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.GraphicsSceneMousePress:
for item in self.graphicsView.scene().items(event.scenePos()):
if isinstance(item, QtWidgets.QGraphicsPixmapItem):
self.reference = item
self.ellipseItem = QtWidgets.QGraphicsEllipseItem(item)
self.ellipseItem.setBrush(QtGui.QColor(0, 255, 0, 25))
self.start = item.mapFromScene(event.scenePos())
elif event.type() == QtCore.QEvent.GraphicsSceneMouseMove and self.ellipseItem:
end = self.reference.mapFromScene(event.scenePos())
self.ellipseItem.setRect(QtCore.QRectF(self.start, end))
elif event.type() == QtCore.QEvent.GraphicsSceneMouseRelease and self.ellipseItem:
self.ellipseItem = None
return super().eventFilter(source, event)
Note that subclassing your Main window from all those classes (QtWidgets.QMainWindow, OFT_MainWindow.Ui_MainWindow, QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene) is not only unnecessary and meaningless, but absolutely WRONG: multiple-inheritance subclassing should only be done when you know what you're inheriting from and why, otherwise, just don't. For Qt widgets that load from UI files, just subclass from the base widget class and the Ui.

setPixmap crashing when trying to show image in label

I have created a minimal example with pyqt designer, that changes the text of a label when a button is pressed and is supposed to present a screenshot in the window, via the label.
Unfortunately, the example just crashes when it tries to show the screenshot in the label.
from PIL.ImageQt import ImageQt
from PyQt5 import QtCore, QtGui, QtWidgets
from pyscreenshot import grab
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(503, 382)
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(70, 30, 75, 23))
self.pushButton.setObjectName("pushButton")
self.label = QtWidgets.QLabel(Form)
self.label.setGeometry(QtCore.QRect(80, 100, 47, 14))
self.label.setObjectName("label")
self.retranslateUi(Form)
self.pushButton.clicked.connect(lambda: self.take_screenshot())
QtCore.QMetaObject.connectSlotsByName(Form)
def take_screenshot(self):
self.label.setText("1?")
screenshot = grab()
self.label.setText("2")
qim = ImageQt(screenshot)
pix = QtGui.QPixmap.fromImage(qim)
self.label.setText("3")
self.label.setPixmap(pix)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "PushButton"))
self.label.setText(_translate("Form", "TextLabel"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
"screenshot" shares the same memory with "qimg", and as screenshot it is a local variable that when eliminated the associated memory is also eliminated so the QPbelmap of the QLabel when trying to access information will generate a Segmentation fault. The solution is to make a copy so that they do not share the same memory
def take_screenshot(self):
screenshot = grab()
qim = ImageQt(screenshot).copy()
pix = QtGui.QPixmap.fromImage(qim)
self.label.setPixmap(pix)
self.label.adjustSize()

Blank PyQt5 Program

I'm trying to create a simple GUI using PyQt5, but whenever I run the program. all it displays is a blank window. How can get elements such as a pushbutton or the QLineEdit to actually appear in the window?
Any pointers would be appreciated as I am trying to create an application that can take a user input (a badge and ticket number in this case) then query a database for the tube properties and quantities before displaying the information as an output.
from PyQt5 import QtCore, QtWidgets
class Ui_MainWindow(object):
def __init__(self):
self.title = 'Tube Bender UI'
self.description = QtWidgets.QLabel('New Order Available')
self.badge = QtWidgets.QLineEdit()
self.ticket = QtWidgets.QLineEdit()
self.tubes = 0
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 641)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
MainWindow.setSizePolicy(sizePolicy)
MainWindow.setMaximumSize(QtCore.QSize(800, 641))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setMinimumSize(QtCore.QSize(800, 641))
self.centralwidget.setMaximumSize(QtCore.QSize(800, 641))
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(0, 320, 801, 641))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.horizontalLayoutWidget.sizePolicy().hasHeightForWidth())
#tubes = 0
def coil_id(self):
QtWidgets.QLineEdit(self)
return self.ticket
def page_description(self):
QtWidgets.QLineEdit(self)
return self.description
def page_title(self):
QtWidgets.QLineEdit(self)
return self.title
def badge_id(self):
QtWidgets.QLineEdit(self)
return self.badge
def tube_count(self):
QtWidgets.QLineEdit(self)
print(self.tubes)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainPage = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show())
sys.exit(app.exec_()
Just have this small look on this tiny example, tried to be the simplest I could. There are much more to learn and some much more good practices not just through everything like that, but anyways, here it is:
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QWidget
class MainWindow(QMainWindow):
layout_main = None
central_widget = None
lbl_name = None
lbl_value = None
input_name = None
input_value = None
def __init__(self):
super(MainWindow, self).__init__()
self.init_ui()
def init_ui(self):
#variables
self.layout_main = QVBoxLayout()
self.layout_labels = QHBoxLayout()
self.layout_inputs = QHBoxLayout()
self.central_widget = QWidget()
self.lbl_name = QLabel("name")
self.lbl_name.setFixedSize(100,50)
self.lbl_value = QLabel("Value")
self.lbl_value.setFixedSize(100, 50)
self.input_name = QLineEdit()
self.input_name.setFixedSize(100, 50)
self.input_value = QLineEdit()
self.input_value.setFixedSize(100, 50)
#style
self.layout_main.setContentsMargins(10, 10, 10, 10)
self.setMinimumSize(250,100)
#adding objects
self.layout_labels.addWidget(self.lbl_name)
self.layout_labels.addWidget(self.lbl_value)
self.layout_main.addLayout(self.layout_labels)
self.layout_inputs.addWidget(self.input_name)
self.layout_inputs.addWidget(self.input_value)
self.layout_main.addLayout(self.layout_inputs)
self.central_widget.setLayout(self.layout_main)
self.setCentralWidget(self.central_widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
You will see that later you will have to override many classes inheriting from qt classes and personalize one by one according to your need. just a tip ")

Categories

Resources