PyQt5 call a function on Dialog resized - pyqt5

I have a MainWindow with a button, when I click the button, a dialog will pop up following the code below
self.window = QtWidgets.QDialog(None, QtCore.Qt.WindowSystemMenuHint|QtCore.Qt.WindowCloseButtonHint)
list_to_print = [1,2,3,4]
self.ui = Ui_Dialog()
self.ui.setupUi(self.window, list_to_print)
self.window.show()
My dialog is created from QtDesigner and PyUIC
Class Ui_Dialog(QtCore.QObject):
def setupUi(self, Dialog, the_list):
self.my_list = the_list
....
# the UI is set here
....
def retranslateUi(self, Dialog):
....
def functionOnResize(self)
print(self.my_list)
How can I call the functionOnResize when the dialog is resized?

You can try to attach the event to your method by doing this:
Class Ui_Dialog(QtCore.QObject):
def setupUi(self, Dialog, the_list):
self.my_list = the_list
Dialog.resizeEvent = self.functionOnResize
def retranslateUi(self, Dialog):
....
def functionOnResize(self, event)
print(self.my_list)

Related

How to set a hover event handler on a QPushButton in PyQt5

I'm trying to set a hover event on a button to open an options menu implemented as a QDialog. Everything works so far except the hovering: the menu opens when the button is pressed and disappears if any of the options is selected or the mouse is moved away from the dialog.
Now I want to open the window without clicking the button but rather by hovering over it.
I've seen PyQt5 mouse hover functions and How to detect mouse hover event in PySide6 widget but i wasn't able to make it work this way.
My code looks like this:
class ElementWidget(QWidget):
def __init__ (self, p, element):
super().__init__(p)
layout = QHBoxLayout()
label = QLabel(element)
label.setFixedSize(200,39)
self.btn = QPushButton("btn")
self.btn.clicked.connect(self._openOptionsMenu)
self.btn.setFixedSize(50,39)
layout.addWidget(label)
layout.addWidget(self.btn)
self.setLayout(layout)
self.setFixedSize(250,60)
def _openOptionsMenu(self):
self.dlg = selfClosingDialog(self.closeOptionsMenu, parent = self)
self.dlg.setLayout(ElementOptionsLayout(self.closeOptionsMenu))
self.dlg.setWindowFlag(Qt.FramelessWindowHint)
self.dlg.setGeometry(QCursor.pos().x(), QCursor.pos().y() ,100,100)
self.dlg.show()
def closeOptionsMenu(self):
self.dlg.close()
if __name__ == "__main__":
app = QApplication([])
window = QMainWindow()
window.resize(500,400)
wid = ElementWidget(window,"Parabola_0")
window.show()
app.exec_()
with the custom dialog:
class selfClosingDialog(QDialog):
def __init__(self, closeFunc, parent=None):
super().__init__(parent)
self.closeFunc = closeFunc
def leaveEvent(self, event):
self.closeFunc()
The perfect solution would be to replace the clicked-event by some kind of an onHover
I found the answer.
It is not a signal but an event enterEvent that needs to be reimplemented by a subclass of QWidget
class HoverOpenBtn(QPushButton):
def __init__(self, text, openOtionsFunc, parent=None):
super().__init__(text, parent)
self.openFunc = openOtionsFunc
def enterEvent(self, event):
self.openFunc()

PyQt5) When I try to open Second window, it is closed without any error messages

I'm trying to open second window on main window.
I made 2 classes for each windows, and run the code. when I click the button on main window, the main window is closed and second windows show. but after 1 seconds the second window is closed and the process ends.
Really I don't know why it does...
from PyQt5 import QtWidgets
import sys
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
# Button
self.button = QtWidgets.QPushButton(self)
self.button.setGeometry(0, 0, 400, 300)
self.button.setText('Open Sub Window')
self.button.setStyleSheet('font-size:40px')
self.button.clicked.connect(self.sub_show)
def sub_show(self):
self.hide()
self.sub_window = SubWindow()
self.sub_window.exec()
self.show()
class SubWindow(QtWidgets.QWidget):
def __init__(self):
super(SubWindow, self).__init__()
self.resize(400, 300)
self.button2 = QtWidgets.QPushButton(self)
self.button2.setGeometry(0, 0, 400, 300)
self.button2.setText('Back to Main window')
self.button2.setStyleSheet('font-size:40px')
self.button2.clicked.connect(self.home)
self.show()
def home(self):
self.close()
if __name__ == "__main__" :
app = QtWidgets.QApplication([])
mw = MainWindow()
mw.show()
sys.exit(app.exec())
You are calling show a few to many times. Also QWidget doesn't have an exec method. You will also want the first window to reappear when you close the second I assume.
I made some changes in the example below. Give it a try:
from PyQt5 import QtWidgets
import sys
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.resize(400, 300)
self.button = QtWidgets.QPushButton(self)
self.button.setGeometry(0, 0, 400, 300)
self.button.setText('Open Sub Window')
self.button.setStyleSheet('font-size:40px')
self.button.clicked.connect(self.sub_show)
def sub_show(self):
self.hide()
self.sub_window = SubWindow()
# connect signal to show again when button2 is pressed
self.sub_window.button2.clicked.connect(self.show)
self.sub_window.show()
class SubWindow(QtWidgets.QWidget):
def __init__(self):
super(SubWindow, self).__init__()
self.resize(400, 300)
self.button2 = QtWidgets.QPushButton(self)
self.button2.setGeometry(0, 0, 400, 300)
self.button2.setText('Back to Main window')
self.button2.setStyleSheet('font-size:40px')
self.button2.clicked.connect(self.close)
if __name__ == "__main__" :
app = QtWidgets.QApplication([])
mw = MainWindow()
mw.show()
sys.exit(app.exec())

How can I add Icons to a QListWidget

I have a program that has you drag and drop files into a QListWidget box and then you click a button to upload those files to a bucket. I would like to say which files have been uploaded and which one is currently being uploaded with an icon. Is there a way to add Icons inside/next to the QListWidget box?
Here is some of the code for the QListWidget and the drag and drop feature. I am just hoping there is a way to add icons
import sys, os
from PyQt5.QtWidgets import QApplication, QMainWindow, QListWidget, QListWidgetItem, QPushButton
from PyQt5.QtCore import Qt, QUrl
class ListBoxWidget(QListWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
self.resize(600, 600)
def dragEnterEvent(self, event):
if event.mimeData().hasUrls:
event.accept()
else:
event.ignore()
def dragMoveEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(Qt.CopyAction)
event.accept()
else:
event.ignore()
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(Qt.CopyAction)
event.accept()
links = []
for url in event.mimeData().urls():
# https://doc.qt.io/qt-5/qurl.html
if url.isLocalFile():
links.append(str(url.toLocalFile()))
else:
links.append(str(url.toString()))
self.addItems(links)
else:
event.ignore()
class AppDemo(QMainWindow):
def __init__(self):
super().__init__()
self.resize(1200, 600)
self.listbox_view = ListBoxWidget(self)
self.btn = QPushButton('Get Value', self)
self.btn.setGeometry(850, 400, 200, 50)
self.btn.clicked.connect(lambda: print(self.getSelectedItem()))
def getSelectedItem(self):
item = QListWidgetItem(self.listbox_view.currentItem())
return item.text()
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = AppDemo()
demo.show()
sys.exit(app.exec_())
I have tried adding QIcon to the self.addItems(links) line but it continues to give me an error about arguments.
Instead of adding items using addItems, create indivual QListWidgetItems and add them one by one using addItem(QListWidgetItem).
def dropEvent(self, event):
if event.mimeData().hasUrls():
event.setDropAction(Qt.CopyAction)
event.accept()
for url in event.mimeData().urls():
# https://doc.qt.io/qt-5/qurl.html
if url.isLocalFile():
address = str(url.toLocalFile())
icon = QIcon('localIcon.png')
else:
address = str(url.toString())
icon = QIcon('remoteIcon.png')
self.addItem(QListWidgetItem(icon, address))
If you want to change the icon of an existing item, access it using item() and use setIcon():
def setIconForItem(self, row, icon):
self.listbox_view.item(row).setIcon(icon)

PyQt5: drawing multiple rectangles using mouseEvents by implementing QGraphicsScene, QGraphicsView and QGraphicsItem [duplicate]

I have a scene like this
class Scene(QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super(Scene, self).__init__(parent)
def mousePressEvent(self, event):
print('scene pressed')
self.wid = MyRect(event.pos(), event.pos())
self.addItem(self.wid)
self.wid.show()
I would like class MyRect(QtWidgets.QGraphicsRectItem) with painter, mouse event and so on to be a draggable rectangle.
all stuff in MyRect
So then I could have many Rectangle to the scene and even after draw line between them and so on (kind of diagram app), but keeping objects related editable options in MyRect, MyLine , ....
I thought :
class MyRect(QtWidgets.QGraphicsRectItem):
def __init__(self, begin, end, parent=None):
super().__init__(parent)
self.begin = begin
self.end = end
def paintEvent(self, event):
print('painting')
qp = QtGui.QPainter(self)
qp.drawRect(QtCore.QRect(self.begin, self.end))
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
But I does not work (paint event not initiated whereas mousepressed event in scene is intiated)
I did not find what I wanted through the web so started totry do it by myself. I'm pretty sure it is a must known starting point but I cannot find it
First of all a QGraphicsItem is not a QWidget, so it has those events and does not handle them directly, that's what QGraphicsView and QGraphicsScene do. For example you say that you want to have a moveable rectangle because that task is simple is QGraphicsView, it is not necessary to overwrite:
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(view)
rect_item = QtWidgets.QGraphicsRectItem(QtCore.QRectF(0, 0, 100, 100))
rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
scene.addItem(rect_item)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
If you want to change the way you paint the rectangle you must overwrite the paint() method as shown below:
from PyQt5 import QtCore, QtGui, QtWidgets
class RectItem(QtWidgets.QGraphicsRectItem):
def paint(self, painter, option, widget=None):
super(RectItem, self).paint(painter, option, widget)
painter.save()
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setBrush(QtCore.Qt.red)
painter.drawEllipse(option.rect)
painter.restore()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(view)
rect_item = RectItem(QtCore.QRectF(0, 0, 100, 100))
rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
scene.addItem(rect_item)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
Update:
from PyQt5 import QtCore, QtGui, QtWidgets
class GraphicsScene(QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super(GraphicsScene, self).__init__(QtCore.QRectF(-500, -500, 1000, 1000), parent)
self._start = QtCore.QPointF()
self._current_rect_item = None
def mousePressEvent(self, event):
if self.itemAt(event.scenePos(), QtGui.QTransform()) is None:
self._current_rect_item = QtWidgets.QGraphicsRectItem()
self._current_rect_item.setBrush(QtCore.Qt.red)
self._current_rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
self.addItem(self._current_rect_item)
self._start = event.scenePos()
r = QtCore.QRectF(self._start, self._start)
self._current_rect_item.setRect(r)
super(GraphicsScene, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self._current_rect_item is not None:
r = QtCore.QRectF(self._start, event.scenePos()).normalized()
self._current_rect_item.setRect(r)
super(GraphicsScene, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self._current_rect_item = None
super(GraphicsScene, self).mouseReleaseEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene =GraphicsScene(self)
view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(view)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())

How can I open and close a new window from main window in PyQt?

I searched in Google usually many posts are talking about how to open a new window and not indicating how to close the window. I found several posts in this website but most of them are using dialog window which is not considered in my software.
I make a UI, which contains a spin box and a button, to demonstrate my problem. I can type in a number equal or less than 5 in spin box. When I click the button, a number of new windows will show up and how many windows will show up is depending on the number in the spin box. If I change to the number in spin box then click the button, the original windows will be closed and new windows will be shown.
Fox example, first I type in "2" in spin box then click the button. Then 2 new windows will show up. If I change the number in spin box to 3 then click the button, the original 2 windows will be closed and 3 new windows will show up.
Here is my main program code:
from PyQt5.QtWidgets import QApplication, QMainWindow
from uitest_review import Ui_MainWindow # import the UI module
# set up a class for main window
class window(QMainWindow):
def __init__(self, parent=None):
super(window, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.Open.clicked.connect(self.openwindow)
def openwindow(self):
windownum = self.ui.windownum.value()
print("open window num:", windownum)
opennewwindow = newwindow(self)
opennewwindow.show()
class newwindow(QMainWindow):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
if __name__ == "__main__":
app = QApplication([])
gui = window()
gui.show()
app.exec_()
Here is my UI code:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(816, 577)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 796, 537))
self.scrollAreaWidgetContents.setObjectName(\
"scrollAreaWidgetContents")
self.verticalLayout = QtWidgets.QVBoxLayout(self.scrollAreaWidgetContents)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
spacerItem = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
self.verticalLayout.addItem(spacerItem)
self.windownum = QtWidgets.QSpinBox(self.scrollAreaWidgetContents)
self.windownum.setMaximum(5)
self.windownum.setObjectName("windownum")
self.verticalLayout.addWidget(self.windownum)
self.groupBox = QtWidgets.QGroupBox(self.scrollAreaWidgetContents)
self.groupBox.setTitle("")
self.groupBox.setObjectName("groupBox")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.groupBox)
self.horizontalLayout.setObjectName("horizontalLayout")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1)
self.Open = QtWidgets.QPushButton(self.groupBox)
font = QtGui.QFont()
font.setPointSize(14)
font.setBold(True)
font.setWeight(75)
self.Open.setFont(font)
self.Open.setObjectName("Open")
self.horizontalLayout.addWidget(self.Open)
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem2)
self.verticalLayout.addWidget(self.groupBox)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.gridLayout.addWidget(self.scrollArea, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Open.setText(_translate("MainWindow", "Open"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
I create a new class (newwindow) in my main program and I can call this class to show a new window. But I cannot figure out how to detect how many windows is opened and how to close them. Does anyone can help me? Thank you so much.
I figured out by myself.
class window(QMainWindow):
def __init__(self, parent=None):
super(window, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.Open.clicked.connect(self.openwindow)
self.openedwin = []
def openwindow(self):
windownum = self.ui.windownum.value()
if windownum != 0:
if self.openedwin != []:
for window in self.openedwin:
window.close()
for repeat in range(windownum):
opennewwindow = newwindow(self)
# print("opennewwindow:", opennewwindow)
self.openedwin.append(opennewwindow)
opennewwindow.show()
# print("self.openedwin:", self.openedwin)
class newwindow(QMainWindow):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
if __name__ == "__main__":
app = QApplication([])
gui = window()
gui.show()
app.exec_()
I add a list self.openedwin = [] to save all window objects. I can use "window object".close() command to close the window before opening new one.