PyQT: how to open new window - python

First of all, similar questions have been answered before, yet I need some help with this one.
I have a window which contains one button (Class First) and I want on pressed, a second blank window to be appeared (Class Second).
I fiddled with the code copied from this question: PyQT on click open new window, and I wrote this code:
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
import sys
import design1, design2
class Second(QtGui.QMainWindow, design2.Ui_MainWindow):
def __init__(self, parent=None):
super(Second, self).__init__(parent)
self.setupUi(self)
class First(QtGui.QMainWindow, design1.Ui_MainWindow):
def __init__(self, parent=None):
super(First, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.on_pushButton_clicked)
self.dialog = Second(self)
def on_pushButton_clicked(self):
self.dialog.exec_()
def main():
app = QtGui.QApplication(sys.argv)
main = First()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
but on_pressed, this error message appears:
AttributeError: 'Second' object has no attribute 'exec_'
(design1 and design2 have been derived from the Qt designer.)
Any thought would be appreciated.

Here I'm using the show method.
Here is a working example (derived from yours):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
import sys
class Second(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Second, self).__init__(parent)
class First(QtGui.QMainWindow):
def __init__(self, parent=None):
super(First, self).__init__(parent)
self.pushButton = QtGui.QPushButton("click me")
self.setCentralWidget(self.pushButton)
self.pushButton.clicked.connect(self.on_pushButton_clicked)
self.dialog = Second(self)
def on_pushButton_clicked(self):
self.dialog.show()
def main():
app = QtGui.QApplication(sys.argv)
main = First()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
If you need a new window every time you click the button, you can change the code that the dialog is created inside the on_pushButton_clicked method, like so:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt4 import QtGui, QtCore
import sys
class Second(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Second, self).__init__(parent)
class First(QtGui.QMainWindow):
def __init__(self, parent=None):
super(First, self).__init__(parent)
self.pushButton = QtGui.QPushButton("click me")
self.setCentralWidget(self.pushButton)
self.pushButton.clicked.connect(self.on_pushButton_clicked)
self.dialogs = list()
def on_pushButton_clicked(self):
dialog = Second(self)
self.dialogs.append(dialog)
dialog.show()
def main():
app = QtGui.QApplication(sys.argv)
main = First()
main.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Related

PyQT QListWidget drag and drop does not work

I am trying to implement in my project a QListWidget with the possibility of moving elements by drag and drop
I try to integrate it into the project in the simplest way without success, while outside I have no problem executing it.
EDIT:The problem seems to come from the realsense library, without its, DAD works
Here is its implementation:
priorityContainer.py:
class priorityContainer(QListWidget):
def __init__(self):
super().__init__()
self.setIconSize(QSize(124, 124))
self.setDragDropMode(QAbstractItemView.InternalMove)
self.setDefaultDropAction(Qt.MoveAction)
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.setAcceptDrops(True)
self.setDragEnabled(True)
for i in range(5):
QListWidgetItem( 'Item '+str(i), self)
main_interface.py:
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
import traceback, sys, os
import pyrealsense2 as rs
from ressource.interface import priorityContainer
class UI_main(QMainWindow):
def __init__(self):
super(UI_main, self).__init__()
self.setupUi()
self.show()
def setupUi(self):
self.centralwidget = QWidget(self)
self.mainVcontainer = QVBoxLayout(self.centralwidget)
self.listWidget = priorityContainer.priorityContainer()
self.mainVcontainer.addWidget(self.listWidget)
self.setCentralWidget(self.centralwidget)
def root_path(self):
return os.path.abspath(os.sep)
if __name__ == "__main__":
app = QApplication(sys.argv)
ui = UI_main()
sys.exit(app.exec_())
I have solved my problem by adding these lines before any other imports where I import my pyrealsense2 librairies:
import sys
sys.coinit_flags = 2
import pythoncom
Reference to the fix: https://github.com/IntelRealSense/librealsense/issues/6174

Passing methods from secondary GUI to main GUI in python

So I have 2 GUIs. One is the main gui which has one push button to activate the second gui. The second gui is a simple calculator which sums two numbers when I push the button with external function.The second gui (the calculator) runs fine standalone However when I try to activate the second gui from the main one the program crashes so I probably doing something wrong.
Also if I change the code in main to this:
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.SumCalcBtn.clicked.connect(self.OpenSecondWindow)
def OpenSecondWindow(self):
self.ex = SumCalculator(self)
self.ex.show()
It runs but doesn't do anything in second gui when I push the button to sum the numbers.(it seems the methods didn't pass to the instance)
I attach the code for better understanding:
Main.py
import sys
from calculators import summary
from PyQt5 import QtCore, QtGui, QtWidgets
from SummaryUI import Ui_SummaryUI
from SummaryMain import SumCalc
from MainWindow import Ui_MainWindow
class SumCalculator(SumCalc):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.SumCalcBtn.clicked.connect(self.OpenSecondWindow)
def OpenSecondWindow(self):
self.ex = SumCalc(self)
self.ex.show()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
SummaryMain.py
import sys
from calculators import summary
from PyQt5 import QtCore, QtGui, QtWidgets
from SummaryUI import Ui_SummaryUI
class SumCalc(QtWidgets.QMainWindow, Ui_SummaryUI):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
Ui_SummaryUI.__init__(self)
self.setupUi(self)
self.CalculateSumBtn.clicked.connect(self.sum_function)
def sum_function(self):
number_a = int(self.FirstNumberInput.text())
number_b = int(self.SecondNumberInput.text())
sum = summary(number_a, number_b)
self.SumResultsValue.setText(str(sum))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = SumCalc()
window.show()
sys.exit(app.exec_())
replace self.ex = SumCalc(self) with self.ex = SumCalc() because the constructor(__init__) function of SumCalc does not take any argument (def __init__(self))
or juts add parameter parent to SumCalc's constructor so it becomes def __init__(self, parent=none)

children widget's closeEvent is not getting called on close

Either I don't understand completely how Qt's event propagation works or something, but I cannot understand why exactly closeEvent is not being called both for QPushButton-derived class and for QWidget-derived one itself.
Shouldn't wid.closeEvent() trigger closeEvents of all children widgets?
#!/bin/env python
# -*- coding: utf-8 -*-
import sys, os
from Qt.QtCore import *
from Qt.QtWidgets import *
from Qt.QtGui import *
class butt(QPushButton):
def __init__(self, parent, name='Button'):
super(self.__class__, self).__init__(parent)
self.name = name
def closeEvent(self, e):
print('butt closeevent')
e.accept()
class wid(QWidget):
def __init__(self, parent=None):
super(self.__class__, self).__init__(parent)
self.initUI()
def initUI(self):
#self.setAttribute(Qt.WA_DeleteOnClose)
self.vl = QVBoxLayout(self)
self.button = butt(self)
self.button.setText('test1')
self.vl.addWidget(self.button)
self.button.clicked.connect(QCoreApplication.quit)
def closeEvent(self, e):
print('wid closeevent')
e.accept()
def show():
app = QApplication(sys.argv)
win = QMainWindow()
widget = wid(win)
win.setCentralWidget(widget)
win.show()
app.exec_()
if __name__ == "__main__":
show()
I'm expecting to see 2 lines
wid closeevent
butt closeevent
as an output, but I see nothing. Why closeEvent it not being called for them?
In the following examples when you press the button visually you will observe the same behavior: the window will close, but we see the difference, in the first one it is called closeEvent(), and in the second one it is not.
Example1:
#!/bin/env python
# -*- coding: utf-8 -*-
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def closeEvent(self, event):
print("button closeEvent")
event.accept()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
button = Button(text="Press me")
button.clicked.connect(button.close)
button.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Example2:
#!/bin/env python
# -*- coding: utf-8 -*-
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def closeEvent(self, event):
print("button closeEvent")
event.accept()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
button = Button(text="Press me")
button.clicked.connect(QtCore.QCoreApplication.quit)
button.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Why do not you call closeEvent when you call QCoreApplication::quit?
Because this method is used to exit the event loop of Qt, and if there is no event loop the events(QCloseEvent) do not work.
When a widget is closed, the children widget is not closed, that is, only if a widget is closed, only its own closeEvent will be called. So if you want the closeevent of the widget to be called, call your method close.
#!/bin/env python
# -*- coding: utf-8 -*-
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def __init__(self, name="Button", parent=None):
super(Button, self).__init__(parent)
self.m_name = name
def closeEvent(self, event):
print("button closeEvent")
event.accept()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.initUI()
def initUI(self):
vl = QtWidgets.QVBoxLayout(self)
button = Button()
button.setText("test1")
vl.addWidget(button)
button.clicked.connect(self.close)
def closeEvent(self, event):
print("Widget closeevent")
event.accept()
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QMainWindow()
widget = Widget()
w.setCentralWidget(widget)
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
In the previous example depending on how you interact with the widget you will get the following behavior:
If you press the button the widget will close so it will be called closeEvent, and will not call the closeEvent of the button because even your child is not closing it.
If you press the "X" button in the window it will not be called the closeEvent of the widget but the QMainWindow, the explanation is the same as the previous one.
Conclusions:
Each type of event has its own workflow, some events are only received by the widget and not by the children, while others send the information to the children.
The close method uses the event loop to notify that the widget is to be closed, but QCoreApplication::quit() terminates the event loop.
Update:
why wid.closeEvent is not called when user pressing "X" button on Qt window? Aren't main window supposed to call closeEvent on all it's children widgets and then destroy them properly?
No, one thing is the closing of a widget and another thing is the destruction of the widget, it can be destroyed without closing and closing the window does not involve destroying the object.
As already pointed out closing a window does not imply deleting it, there may be other windows open, but if the last QApplication window is closed by default the eventloop that implies the destruction of the widget will be terminated which does not necessarily imply calling the close method.
To be understood, let's use the following code:
from Qt import QtCore, QtGui, QtWidgets
class Button(QtWidgets.QPushButton):
def closeEvent(self, event):
print("closeEvent Button")
super(Button, self).closeEvent(event)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
button_quit = Button(
text="quit",
clicked=QtCore.QCoreApplication.quit
)
button_close = Button(
text="close",
clicked=self.close
)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button_quit)
lay.addWidget(button_close)
def closeEvent(self, event):
print("closeEvent Widget")
super(Widget, self).closeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
There are 2 buttons, in the case of the first button that calls QCoreApplication::quit() that will end the eventloop so all the widgets will be destroyed, and in that case no closeEvent will be called, in the case of the second button it will be call near the window so it will call its closeEvent but not the closeEvents of its children.
my actual problem is that I have saveUI() func in closeEvent, and it's not being called upon widgets hierarchical destruction on window close
If you want the closeEvent method to be called hierarchically then you must call the close method manually since Qt does not design it that way. In the next part there is an example:
from PyQt5 import QtCore, QtGui, QtWidgets
class PushButton(QtWidgets.QPushButton):
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent PushButton")
super(PushButton, self).closeEvent(event)
class LineEdit(QtWidgets.QLineEdit):
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent LineEdit")
super(LineEdit, self).closeEvent(event)
class ComboBox(QtWidgets.QComboBox):
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent ComboBox")
super(ComboBox, self).closeEvent(event)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
button_close = PushButton(text="close", clicked=self.close)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button_close)
lay.addWidget(LineEdit())
lay.addWidget(ComboBox())
def closeEvent(self, event):
for children in self.findChildren(
QtWidgets.QWidget, options=QtCore.Qt.FindDirectChildrenOnly
):
children.close()
print("closeEvent Widget")
super(Widget, self).closeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

Python Qt - Use button via function from outside a class

I am quite new to python. For my problem I cannot seem to find an answer. And sadly I didn't find anything that could held me. I try to call a function from another file in the same folder but it won't work. If I call the same function from the same file, it works just fine. The same goes for external classes.
This code works:
import sys
from PyQt5 import QtWidgets
from ui.mainwindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.show()
self.ui.pushButton.clicked.connect(test_function)
def test_function():
window.ui.stackedWidget.setCurrentIndex(1)
if __name__=='__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
The following code won't work:
import sys
from PyQt5 import QtWidgets
from ui.mainwindow import Ui_MainWindow
from other_file import test_function
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.show()
self.ui.pushButton.clicked.connect(test_function)
if __name__=='__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
other_file.py
def test_function():
window.ui.stackedWidget.setCurrentIndex(1)
Error: cannot import name 'test_function'

create main script to use PyQt4 windows with other objects

I am trying to learn how to use python and pyQt.
I have done a window with Qtcreator then I used pyuic4, I have also created a class called Ruban I would like to use it with my window interface. In my window I have a button called nouveauRuban. I would like to create an object from my class Ruban when this button is clicked.
I know my code is wrong, the problem may be at the initial part of mainTN, on the __init__ ?
# -*- coding: utf-8 -*-
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from mainwindow import Ui_MainWindow
from Ruban import Ruban
class mainTM(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None): #, parent=None ??
super (mainTM, self).__init__(self, parent) #(parent) ??
self.createWidgets()
self.nouveauRuban.connect(nouveauRuban, QtCore.SIGNAL(_fromUtf8("clicked()")), self.nvRuban)
def nvRuban(self):
self.ruban=Ruban()
self.ruban.info_ruban()
def createWidgets(self):
self.ui=Ui_MainWindow()
self.ui.setupUi(self)
if __name__== "__main__":
app=QApplication(sys.argv)
myapp=mainTM()
myapp.show()
sys.exit(app.exec_())
Here is a re-write of your script which should fix all the problems:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from mainwindow import Ui_MainWindow
from Ruban import Ruban
class mainTM(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(mainTM, self).__init__(parent)
self.setupUi(self)
self.nouveauRuban.clicked.connect(self.nvRuban)
def nvRuban(self):
self.ruban = Ruban()
self.ruban.info_ruban()
if __name__== '__main__':
app = QApplication(sys.argv)
myapp = mainTM()
myapp.show()
sys.exit(app.exec_())
If you're connecting a signal to a slot, you need to define that slot using a decorator:
#QtCore.pyqtSlot()
def nvRuban(self):
self.ruban=Ruban()
self.ruban.info_ruban()
Then connect it:
self.nouveauRuban.clicked.connect(nvRuban)

Categories

Resources