To show PyQt main window inside a function - python

I am trying to write a python script to an application like matplotlib.
I need a function call to show the Qt main window. How do I do this?
class MainWindow(QtGui.QMainWindow):
def __init__(self,parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.numbers = 4
...
app = QtGui.QApplication(sys.argv)
dmw = DesignerMainWindow()
dmw.show()
sys.exit(app.exec_()) #this works, but pops the window right away
I want to be able to call the window when I wish instead. (Something like this)
def newWin():
app = QtGui.QApplication(sys.argv)
dwm = MainWindow()
sys.exit(app.exec_())
return dwn
a = newWin() # application is created now
a.numbers = 10 # do something
a.show() # should pop me the window now
EDIT : Pasting solution thanks to jadkik94
class App(QtGui.QApplication):
def __init__(self, args):
QtGui.QApplication.__init__(self,args)
self.window = MainWindow()
def doSomething(self, ii):
self.window.numbers = ii
def show(self):
self.window.show()
sys.exit(self.exec_())
a = App(sys.argv)
a.doSomething(12) #updates numbers alternately a.window.numbers = 12
a.show() #pops the window!

When used inside a function, the window does not show. The problem is simple: the window is garbage collected because it is defined inside the scope of the function, and then not used anymore, so Python sees it as "garbage" and deletes the object.
The best way I found of avoiding that is having an application class that will hold references to all the windows you want to show. So you can either have a regular class do that for you, or subclass the QtGui.QApplication if you can make use of it otherwise too. I would go for the second option.
Another option, if you really don't want to be using a class, is to set it to a global variable, and that will usually prevent it from being garbage-collected by Python.

Is this what you want:
import sys
from PyQt4 import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Icon')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
a = main()
a.show()

Related

PyQt5 Custom Widget Opens in Another Window

I started out with PyQt5 recently. I wanted to create a custom widget and then insert it into the main window of an application.
The custom Widget:
class ScoreCard(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ScoreCard, self).__init__(parent=parent)
self.setWindowFlags(QtCore.Qt.CustomizeWindowHint)
self.pressing = False
self.init_ui()
self.show()
def init_ui(self):
# Layout in here
And this is the main Application:
from PyQt5.QtWidgets import *
from scorecard import ScoreCard
import sys
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.initUi()
self.show()
def initUi(self):
self.setGeometry(300,300,800,700)
window_layout = QVBoxLayout()
recent_playcard = ScoreCard()
window_layout.addWidget(recent_playcard)
self.setLayout(window_layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
execute = MainWindow()
sys.exit(app.exec_())
Why is it that whenever I run the main Application, the custom widget appears in another window? I even tried removing the frame and setting the parent to none, but none of that changed this behavior. How do I fix this?
Looks like I mixed up QMainWindow and QDialog I should be using a central widget for the main application instead of setting a layout..

(PyQt5) How can i show a new window in my main window?

I'm trying to show a new dialog window in my main window when i click on a pushbutton. I'm facing some issues here:
1: when i create a new dialog object inside my mainWindow class, i'll have to use lambda as a slot or else it wont work. the code below works as expected:
class main(QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
new = QDialog()
self.ui.pushButton.clicked.connect(lambda: new.show())
self.show()
app = QApplication(sys.argv)
ex = main()
sys.exit(app.exec_())
while going like self.ui.pushButton.clicked.connect(new.show) does not work.
But if the object is created outside the main class it will run without Lambda:
class main(QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.show()
app = QApplication(sys.argv)
ex = main()
new = QDialog()
ex.ui.pushButton.clicked.connect(new.show)
sys.exit(app.exec_())
I really don't understand what is happening here. AFAIK using a slot without Lambda should work as long as no arguments are passed to it.
2:
If i wanted to connect the pushbutton to a slot (in which i create a dialog object and run the show() method on it), the dialog window would appear and then immediately disappear, in this case i'll need to do dialoginstance.exec_() instead of dialoginstance.show()
class main(QMainWindow):
def __init__(self):
super().__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(lambda: self.showdiag())
self.show()
def showdiag(self):
new = QDialog()
new.exec_() # new.show() wont work!
app = QApplication(sys.argv)
ex = main()
sys.exit(app.exec_())

How to connect to different classes in pyqt5?

Id like to ask how to connect 2 different classes. I have the following codes in 2 classes (2 classes because i have created 2 different interface. 1 is the QMainwindow and the other 1 is QWidget).
Here's the code:
class MainWindow(QMainWindow, Ui_MainWindow):
def open_inv_search_form(self):
self.window = QtWidgets.QWidget()
self.ui = Ui_Inv_Search()
self.ui.setupUi(self.window)
self.window.show()
MainWindow.setEnabled(False)
class Inv_Search(QWidget, Ui_Inv_Search):
def __init__(self,):
super(Inv_Search, self).__init__()
self.btn_close_search.clicked.connect(self.close_inv_search_form)
def close_inv_search_form(self):
Inv_Search.hide()
MainWindow.setEnabled(True)
The idea is when SEARCH button is clicked in MainWindow, Inv_Search will pop up while MainWindow will be disabled. I have done this part correctly. When CLOSE button is clicked, Inv_Search will be hide and MainWindow will be enabled. However, when CLOSE button is clicked, nothing happened. And there is no error at all.
UPDATE
I was able to successfully do what I wanted. Here's the changes I did. Let me know if this is fine or can be better. Nevertheless, this code works.
class MainWindow(QMainWindow, Ui_MainWindow):
Inv_Search.show() #called to connect to the new window. This is the key since what i previously did only call the ui, but not connect it to the class itself.
MainWindow.setEnabled(False)
class Inv_Search(QWidget, Ui_Inv_Search):
def __init__(self,):
super(Inv_Search, self).__init__()
self.setupUi(self)
self.btn_close_search.clicked.connect(self.close_inv_search_form)
def close_inv_search_form(self):
Inv_Search.close() # I cant figure out how can I use the self but this works fine
MainWindow.setEnabled(True)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
MainWindow = MainWindow()
Inv_Search = Inv_Search() #added this one
#ui = Ui_MainWindow()
#ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
When you call Inv_Search.hide() and MainWindow.setEnabled(True) in close_inv_search_form, you call the methods on the class itself not on the instance, which is what you actually have to.
from PyQt5.QtCore import qApp
class MainWindow(QMainWindow, Ui_MainWindow):
def open_inv_search_form(self):
self.window = QtWidgets.QWidget()
self.window.ui = Ui_Inv_Search() # You have to set the attributes of the
self.window.ui.setupUi(self.window) # "window" not the instance of MainWindow
self.window.show()
self.setEnabled(False)
class Inv_Search(QWidget, Ui_Inv_Search):
def __init__(self,):
super(Inv_Search, self).__init__()
self.btn_close_search.clicked.connect(self.close_inv_search_form)
def close_inv_search_form(self):
self.hide() # Use the method "hide" on the instance
qApp.setEnabled(True) # Use the method "setEnabled" on the instance
if __name__ == "__main__" :
app = QApplication()
main = MainWindow() # This is the instance that can be referred to by qApp
main.exec_()
I am assuming that there is more code and a .ui file somewhere. It looks like this line
Inv_Search.hide()
should be changed to
self.hide()
Also, I think that because you need to call the method on the instance, not the class.
self.ui = Ui_Inv_Search()
should probably be
self.ui = Inv_Search()
You are doing a similar thing with MainWindow. It's a little more difficult here, because you will need to have an instance of MainWindow stored somewhere accessible. Although you may be able to access the MainWindow instance through QtWidget.parentWidget, in Python I prefer to just pass the instance to the constructor. So
def __init__(self, mainWindow):
self.mainWindow = mainWindow
# ... all the other stuff too
as your Inv_Search constructor, and
self.ui = Inv_Search(self)
# notice the new ^ argument
in your MainWindow constructor. And then
self.mainWindow.setEnabled(True)
in your class method. Also, your argument signature is wrong for the clicked signal. Use
def close_inv_search_form(self, checked=None):
# Need this ^ argument, even if you don't use it.
In reality, it seems like the functionality you are trying to accomplish is best suited for a modal dialog, such as that provided by QDialog, which will natively handle many of the effect I think you are looking for.

Create another window of same class in PySide

I am creating a small GUI program using PySide. I am having difficulty creating another object of same class. What exactly I am trying to do is that when clicked on a button on MainWindow it should create another independent window of same class.
import sys
from PySide import QtCore, QtGui
class Sticky(QtGui.QMainWindow):
def __init__(self,parent = None):
QtGui.QMainWindow.__init__(self,parent)
self.initUI()
def initUI(self):
....
self.addToolBarElements()
....
self.show()
def addToolBarElements(self):
....
self.newwindow = QtGui.QAction(QtGui.QIcon(os.path.join(os.path.dirname(__file__),'icons/new.png')),"New Note",self)
self.newwindow.setStatusTip("New")
self.newwindow.triggered.connect(newwindow)
self.toolBar.addAction(self.newwindow)
def newwindow(self):
#how to create new object of same class
def run():
app = QtGui.QApplication(sys.argv)
notes = Sticky()
sys.exit(app.exec_())
Here is what I have tried:
I have tried multiprocessing but I didn't understand much. I tried calling run() method again but it gives error.
Do not call with the same name 2 different elements, in your case self.newwindow refers to the QAction as the method of the class, avoid it, that is a type of error easy to commit but difficult to find.
going to the point, you just have to create a new object of the class, but the problem is that the garbage collector will eliminate it, to avoid it there are 2 possible options, the first is to make the new window member of the class, or second store it in a list, that's the one I choose because I think you want to have several windows.
import sys
import os
from PySide import QtCore, QtGui
class Sticky(QtGui.QMainWindow):
def __init__(self,parent = None):
QtGui.QMainWindow.__init__(self,parent)
self.others_windows = []
self.initUI()
def initUI(self):
self.addToolBarElements()
self.show()
def addToolBarElements(self):
self.toolBar = self.addToolBar("toolBar")
self.newwindow = QtGui.QAction(QtGui.QIcon(os.path.join(os.path.dirname(__file__),'icons/new.png')), "New Note",self)
self.newwindow.setStatusTip("New")
self.newwindow.triggered.connect(self.on_newwindow)
self.toolBar.addAction(self.newwindow)
def on_newwindow(self):
w = Sticky()
w.show()
self.others_windows.append(w)
def run():
app = QtGui.QApplication(sys.argv)
notes = Sticky()
sys.exit(app.exec_())
run()

How to accept close event of MainWindow when loading it with QUiLoader()?

How to receive close event in following code?
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.view = QUiLoader().load("sample.ui", self)
self.view.show()
def closeEvent(self, e):
print "close event recieved"
def main():
app = QApplication(sys.argv)
a=Main()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
If I convert sample.ui to sample.py using pyside-uic and importing this into main.py then I was able to receive close event.
from sample import Ui_MainWindow
class Main(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
def closeEvent(self, e):
print "close event recieved"
app = QApplication(sys.argv)
a=Main()
a.show()
sys.exit(app.exec_())
The second example works because it effectively becomes a subclass of the top-level class from Qt Designer. By contrast, the first example uses composition rather than subclassing, which puts all the gui elements inside an internal namespace. The Main class is just a container that acts as the parent of the view widget, and is never actually shown (which in turn means it doesn't receive any close events).
In PyQt, the uic module has several funtions which allow you to work around these issues, but there is currently nothing like that in PySide. Instead, you have to roll your own function. See this answer for an explanation of how to do that.
Alternatively, you could change the top-level class in Qt Designer to a QWidget, and then make view the central widget of your Main class. This is a lot less flexible than the above method, though.

Categories

Resources