Opening new window from python gui - python

I have a problem opening new window in my python gui app. I have 3 classes (first login is shown, and than 2 windows are opened). This works fine:
class LoginDialog(QtGui.QDialog):
def __init__(self, parent = None):
super(LoginDialog, self).__init__(parent)
.....
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
.....
class ImageViewerMainWindow(QtGui.QMainWindow):
def __init__(self, path, parent = None):
super(ImageViewerMainWindow, self).__init__(parent)
.....
if __name__ == "__main__":
qtApp = QtGui.QApplication(sys.argv)
loginDlg = LoginDialog()
if not loginDlg.exec_():
sys.exit(-1)
MyMainWindow = MainWindow()
MyMainWindow.show()
viewer = ImageViewerMainWindow("C:\image.jpg")
viewer.show()
sys.exit(qtApp.exec_())
I need viewer to be executed from MainWindow but when I put it like this it just flashes and disappear:
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
.....
def DoOpenImageViewer(self):
viewer = ImageViewerMainWindow("C:\image.jpg")
viewer.show()

You need to keep a reference to you viewer, otherwise the new window is destroyed when viewer goes out of scope and is garbage collected.
If you only need one Window at a time, you can do something like:
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
.....
def DoOpenImageViewer(self):
self.viewer = ImageViewerMainWindow("C:\image.jpg")
self.viewer.show()
Otherwise you could use a list to store the references.

Related

How to test a custom dialog window called using exec_()?

I'm trying to write a system test for my project. I have a controller class which launches the various windows. However, I can't seem to control windows launch using exec with the qtbot.
Here is an MVCE:
from PyQt5.QtWidgets import *
from PyQt5 import QtGui
class Controller:
def __init__(self):
self.name = None
self.a = WindowA(self)
def launchB(self):
self.b = WindowB(self)
if self.b.exec_():
self.name = self.b.getData()
class WindowA(QDialog):
def __init__(self, controller):
super(WindowA, self).__init__()
self.controller = controller
layout = QVBoxLayout()
self.button = QPushButton('Launch B')
self.button.clicked.connect(self.controller.launchB)
layout.addWidget(self.button)
self.setLayout(layout)
self.show()
class WindowB(QDialog):
def __init__(self, controller):
super(WindowB, self).__init__()
self.controller = controller
layout = QVBoxLayout()
self.le = QLineEdit()
self.button = QPushButton('Save')
self.button.clicked.connect(self.save)
layout.addWidget(self.le)
layout.addWidget(self.button)
self.setLayout(layout)
self.show()
def getData(self):
return self.le.text()
def save(self):
if self.le.text():
self.accept()
self.close()
else:
self.reject()
from PyQt5.QtWidgets import QApplication
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Controller()
sys.exit(app.exec_())
I'd like to test that the user successfully enters data in the lineedit. In my test I'm able to successfully click the button in WindowA to launch WindowB, but am unable to use keyClicks to enter data in the lineedit.
Here is the test:
def test_1(qtbot):
control = Controller()
qtbot.mouseClick(control.a.button, QtCore.Qt.LeftButton)
qtbot.keyClicks(control.b.le, 'Test_Project')
qtbot.mouseClick(control.b.button, QtCore.Qt.LeftButton)
assert control.name == 'Test_Project'
The problem is that using exec_() blocks all synchronous tasks until the window is closed, the solution is to use a QTimer to launch the remaining tasks asynchronously:
def test_1(qtbot):
control = Controller()
def on_timeout():
qtbot.keyClicks(control.b.le, "Test_Project")
qtbot.mouseClick(control.b.button, QtCore.Qt.LeftButton)
QtCore.QTimer.singleShot(0, on_timeout)
qtbot.mouseClick(control.a.button, QtCore.Qt.LeftButton)
assert control.name == "Test_Project"

Trouble with PyQt4 List Widget

So my problem is the following:
I have a program that I created in QT Designer and added some code in Python.
There is an main window and two windows wich appear when you click an button in the window before.
The List Widget is in the second window:
Hope with this picture you can understand what I mean
So now I want to add some Items to my list widget.
def add_number_to_list(self):
self.ui.list_of_numbers.addItem('test')
So I call this function on another place but it didn't happen anything.
If I add an print command, to test if the function works: The print is showed. But nothing appears in the list widget...
What is wrong?
import sys
from PyQt4 import QtGui
import p_design, p_edit_numbers, p_add_number
number_to_add = ''
class Example(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = p_design.Ui_MainWindow()
self.ui.setupUi(self)
self.ui.manually_alarm.clicked.connect(self.alarm)
self.ui.edit_numbers.clicked.connect(self.open_edit_numbers)
def alarm(t1,t2):
#send sms to numbers
print('ALARM!')
def open_edit_numbers(self):
self.test = EditNumbers(self)
self.test.show()
class EditNumbers(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = p_edit_numbers.Ui_MainWindow()
self.ui.setupUi(self)
self.ui.add_number.clicked.connect(self.open_add_number)
### Problem! ###
def add_number_to_list(self):
self.ui.list_of_numbers.addItems('test')
################
def open_add_number(self):
self.t3 = AddNumber(self)
self.t3.show()
class AddNumber(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = p_add_number.Ui_MainWindow()
self.ui.setupUi(self)
self.ui.add.clicked.connect(self.add_number)
def add_number(self):
global number_to_add
editnumbers=EditNumbers()
editnumbers.add_number_to_list()
def main():
app = QtGui.QApplication(sys.argv)
form = Example()
form.show()
sys.exit(app.exec_())
main()

How to find out if second window is closed

I have an application that uses another application from someone else halfway through (both applications use .ui files). Therefore I create the second application in SecondWindow and hide MainWindow. Now I would like to show MainWindow again after SecondWindow is closed. I found the solution in the answer works, but now the background of SecondWindow is wrong because it uses the background of MainWindow. Is there a way to find out if SecondWindow is closed in the class from MainWindow without making MainWindow a parent of SecondWindow or to prevent the background changes caused by the parenthood?
My current code looks somewhat like this:
## Define main window class from template
path = os.path.dirname(os.path.abspath(__file__))
uiFile = os.path.join(path, 'test.ui')
Ui_MainWindow, QtBaseClass = uic.loadUiType(uiFile)
uiFile2 = os.path.join(path, 'monitor.ui')
WindowTemplate, SecondWindowClass = pg.Qt.loadUiType(uiFile2)
class SecondWindow(SecondWindowClass):
def closeThis(self):
self.close()
self.parent().show()
def __init__(self, parent):
super(SecondWindow, self).__init__(parent)
# ensure this window gets garbage-collected when closed
self.setWindowTitle('pyqtgraph example: Qt Designer')
self.ui = WindowTemplate()
self.ui.setupUi(self)
self.show()
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def showSecond(self):
self.second.show()
self.hide()
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.ui=uic.loadUi(uiFile, self)
self.setupUi(self)
self.show()
self.second = SecondWindow(self)
self.second.hide()
self.ui.end_button.clicked.connect(lambda x:self.showSecond())
win = MainWindow()
if __name__ == '__main__':
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
It's not actually necessary for the second window to be a child of the first.
So you should be able to do something like this:
class SecondWindow(SecondWindowClass):
def closeThis(self):
self.close()
self.first.show()
def __init__(self, first):
super(SecondWindow, self).__init__()
self.first = first
...
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def showSecond(self):
self.second.show()
self.hide()
def __init__(self):
...
self.second = SecondWindow(self)
self.second.hide()

Main form and child form

I am quite new in pyqt design
and I have a question.
I have a Main form. and a child form.
I want the child form to be opened inside the parent form.
how can I do that in python?
I have written a code that just open the form.
but it didnot open it inside the form?
Thanks
##this method creates an Form Main
class FrmMainForm (QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.uiMain = FrmMain.Ui_MainWindow()
self.uiMain.setupUi(self)
action = self.uiMain.menuManual_Mode.addAction(self.tr('ManualMode'))
action.triggered.connect(self.handleNewWindow)
def handleNewWindow(self):
ex = Main(self.uiMain)
ex.show()
class Main(QtGui.QWidget):
white = "QWidget { background-color:#FFFFFF }"
red = "QWidget { background-color:#AB0000}"
green = "QWidget { background-color:#00C000}"
def __init__(self,p):
QtGui.QWidget.__init__(self)
self.p = p
self.initLogAnalyzerManuall()
def initLogAnalyzerManuall(self):
QtGui.QWidget.__init__(self)
self.ui = Ui_Form()
self.ui.setupUi(self,self.p)
The child window will be garbage-collected when the handleNewWindow method returns, and so it will never get the chance to be shown.
You need to keep a reference to the child window, but the way you go about it depends on what you are trying to achieve. Do you literally want a new window to be opened every time the button is clicked? If so, then do this:
def handleNewWindow(self):
ex = Main(self)
ex.show()
class Main(QtGui.QWidget):
...
def __init__(self, parent):
QtGui.QWidget.__init__(self, parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.ui = Ui_Form()
self.ui.setupUi(self)
On the other hand, if you want the same child window to be opened every time, then do this:
class FrmMainForm (QtGui.QWidget):
def __init__(self):
...
self._child_window = None
def handleNewWindow(self):
if self._child_window is None:
self._child_window = Main(self)
self._child_window.show()
class Main(QtGui.QWidget):
...
def __init__(self, parent):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
Note that in both cases, you can access the main window from the child window with self.parent().

how to get subclassed QWidgets from QToolBox?

I wrote a few customized widget classes by subclassing QWidget. I created a few customized widgets using them and added them to a QToolBox.
class BaseWidget(QtGui.QWidget):
def __init__(self, parent=None):
# initialize
def mymethod():
pass
class AWidget(BaseWidget):
def __init__(self, parent=None):
# initialize
def mymethod():
print "A"
class BWidget(BaseWidget):
def __init__(self, parent=None):
# initialize
def mymethod():
print "B"
Now I want to loop over all the widgets added to the QToolBox and call a method of these customized widgets:
class toolboxWidget(QtGui.QToolBox):
def __init__(self, parent=None):
super(toolboxWidget, self).__init__(parent=parent)
a = AWidget(self)
b = BWidget(self)
self.addItem(a, "A")
self.addItem(b, "B")
def printMethod(self):
for i in range(self.count()):
self.widget(i).mymethod()
However, since widget() method of QToolBox only returns objects of QWidget type, when calling printMethod() of toolboxWidget object, it gives the following error:
AttributeError: 'QWidget' object has no attribute 'mymethod'.
Is there a way I can convert the QWidget returned by widget() to BaseWidget objects? Thanks.
After fixing all the obvious errors and omissions in your example code, I was able to get it working without any problems.
If the QToolBox.widget method didn't return an instance of one of your BaseWidget subclasses, it would be a bug in PyQt (or sip).
Here is a script that works for me using sip 4.15.4 and PyQt 4.10.3:
from PyQt4 import QtCore, QtGui
class BaseWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
def mymethod(self):
pass
class AWidget(BaseWidget):
def __init__(self, parent=None):
BaseWidget.__init__(self, parent)
def mymethod(self):
print "A"
class BWidget(BaseWidget):
def __init__(self, parent=None):
BaseWidget.__init__(self, parent)
def mymethod(self):
print "B"
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.toolbox = QtGui.QToolBox(self)
a = AWidget(self.toolbox)
b = BWidget(self.toolbox)
self.toolbox.addItem(a, "A")
self.toolbox.addItem(b, "B")
self.button = QtGui.QPushButton('Test', self)
self.button.clicked.connect(self.printMethod)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.toolbox)
layout.addWidget(self.button)
def printMethod(self):
for i in range(self.toolbox.count()):
self.toolbox.widget(i).mymethod()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 300, 300)
window.show()
sys.exit(app.exec_())

Categories