I have menu_utama.py which has UI in menu_utama_ui.py (converting result from qt designer) and rekam_mhs.py which has UI in rekam_mhs_ui.py.
The source code of menu_utama.py
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from menu_utama_ui import Ui_Form
from rekam_mhs import rekam_mhs_form
class Main_Program(Ui_Form):
def __init__(self,dialog):
rekam_mhs_form.__init__(self)
self.setupUi(dialog)
#Connect "add" button with a custom function
self.btnMhs.clicked.connect(self.fungsiMahasiswa)
def fungsiMahasiswa(self):
dialog = QtWidgets.QDialog()
dialog.ui = rekam_mhs_form() #call rekam_mhs.py
dialog.ui.setupUi(dialog)
dialog.exec_()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
dialog = QtWidgets.QDialog()
prog = Main_Program(dialog)
dialog.show()
sys.exit(app.exec_())
Here some source code in rekam_mhs.py
import sys
import database as db
from PyQt5 import QtCore, QtGui, QtWidgets, uic
from rekam_mhs_ui import rekam_mhs_form
from model import mahasiswa
class rekam_mhs_main(rekam_mhs_form):
def __init__(self,dialog):
rekam_mhs_form.__init__(self)
self.setupUi(dialog)
self.btnGetData.clicked.connect(self.fungsiPushButton) #problem
#Connect "add" button with a custom function
def fungsiGetData(self):
#To call some data from database
txt = self.lineEdit.text()
res = db.Database().select_NIM(txt)
self.lineEdit_2.setText(""+res.nama)
self.lineEdit_4.setText(""+res.kelas)
self.lineEdit_3.setText(""+res.prodi)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
dialog = QtWidgets.QDialog()
prog = rekam_mhs_main(dialog)
dialog.show()
sys.exit(app.exec_())
When I run "python3 rekam_mhs.py" and click the button (btnGetData), the method is called (fungsiGetData) and executed.
When I run "python3 menu_utama.py" and click the button (btnMhs) to call rekam_mhs.py, the GUI is shown up but when I click btnGetData, the method (fungsiGetData) is not executed. This condition kinda like there is no method when that button is clicked.
What did I miss? Do I do wrong to call another GUI by that way? I've searched some tutorial but using qt4 instead of qt5.
With the code you provided, I'm pretty sure the problem is in the fungsimahasiswa() function. You are calling the setupUi() function twice( inside the rekam_mhs_main constructor and then inside fungsimahasiswa() too).
You are defining the Signal-slot self.btnGetData.clicked.connect(self.fungsiPushButton) within the constructor, but immediately you call setupUi() in fungsimahasiswa(). That causes a new self.btnGetData to be created. Then that new button will not have a Signal-Slot.
That's why I think the fungsimahasiswa() should be:
def fungsiMahasiswa(self):
dialog = QtWidgets.QDialog()
dialog.ui = rekam_mhs_form(dialog)
dialog.exec_()
Related
I have multiple windows in a Python GUI application using PyQt5.
I need to hide current window when a button is clicked and show the next window.
This works fine from WindowA to WindowB but I get an error while going from WindowB to WindowC.
I know there is some problem in initialization as the initialization code in WindowB is unreachable, but being a beginner with PyQt, i can't figure out the solution.
WindowA code:
from PyQt5 import QtCore, QtGui, QtWidgets
from WindowB import Ui_forWindowB
class Ui_forWindowA(object):
def setupUi(self, WindowA):
# GUI specifications statements here
self.someButton = QtWidgets.QPushButton(self.centralwidget)
self.someButton.clicked.connect(self.OpenWindowB)
# More GUI specifications statements here
def retranslateUi(self, WindowA):
# More statements here
def OpenWindowB(self):
self.window = QtWidgets.QMainWindow()
self.ui = Ui_forWindowB()
self.ui.setupUi(self.window)
WindowA.hide()
self.window.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
WindowA = QtWidgets.QMainWindow()
ui = Ui_forWindowA()
ui.setupUi(WindowA)
MainWindow.show()
sys.exit(app.exec_())
WindowB code:
from PyQt5 import QtCore, QtGui, QtWidgets
from WindowB import Ui_forWindowB
class Ui_forWindowB(object):
def setupUi(self, WindowB):
# GUI specifications statements here
self.someButton = QtWidgets.QPushButton(self.centralwidget)
self.someButton.clicked.connect(self.OpenWindowC)
# More GUI specifications statements here
def retranslateUi(self, WindowB):
# More statements here
def OpenWindowB(self):
self.window = QtWidgets.QMainWindow()
self.ui = Ui_forWindowC()
self.ui.setupUi(self.window)
WindowB.hide() # Error here
self.window.show()
# The below code doesn't get executed when Ui_forWindowB is called from A
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
WindowB = QtWidgets.QMainWindow()
ui = Ui_forWindowB()
ui.setupUi(WindowB)
MainWindow.show()
sys.exit(app.exec_())
It works fine from A to B where
WindowA.hide() # Works Properly
While calling WindowC from WindowB
WindowB.hide() # Shows error: name 'WindowB' is not defined
I understand that the initialization isn't done as the "if" statement doesn't get executed.
How to get this working?
I have many more windows to connect in this flow
When you run a Python script, the first file executed will be assigned the name __main__, therefore, if you first execute WindowA the code inside the block if __name__ == "__main__" gets executed and the application is started using WindowA as the main window, similarly if you execute your WindowB script first, the application will be started usingWindowB as the main window.
You cannot start two applications within the same process so you have to choose which one you want to be the main window, all the others will be secondary windows (even if they inherit from QMainWindow).
Nevertheless, you should be able to instantiate new windows from a method in your main window.
As a good practice, you could create a main script to handle the initialization of your application and start an empty main window that will then handle your workflow, also, you may want to wrap your UI classes, specially if they are generated using Qt creator, here is an example:
main.py
import PyQt5
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication
from views.main_window import MainWindow
class App(QApplication):
"""Main application wrapper, loads and shows the main window"""
def __init__(self, sys_argv):
super().__init__(sys_argv)
# Show main window
self.main_window = MainWindow()
self.main_window.show()
if __name__ == '__main__':
app = App(sys.argv)
sys.exit(app.exec_())
main_window.py
This is the main window, it doesn't do anything, just control the workflow of the application, i.e. load WindowA, then WindowB etc., notice that I inherit from Ui_MainWindow, by doing so, you can separate the look and feel from the logic and use Qt Creator to generate your UI:
from PyQt5.QtWidgets import QWidget, QMainWindow
from views.window_a import WindowA
from views.window_b import WindowB
from widgets.main_window import Ui_MainWindow
class MainWindow(Ui_MainWindow, QMainWindow):
"""Main application window, handles the workflow of secondary windows"""
def __init__(self):
Ui_MainWindow.__init__(self)
QMainWindow.__init__(self)
self.setupUi(self)
# start hidden
self.hide()
# show window A
self.window_a = WindowA()
self.window_a.actionExit.triggered.connect(self.window_a_closed)
self.window_a.show()
def window_a_closed(self):
# Show window B
self.window_b = WindowB()
self.window_b.actionExit.triggered.connect(self.window_b_closed)
self.window_b.show()
def window_b_closed(self):
#Close the application if window B is closed
self.close()
window_a.py
from PyQt5.QtWidgets import QWidget, QMainWindow
from widgets.main_window import Ui_forWindowA
class WindowA(Ui_forWindowA, QMainWindow):
"""Window A"""
def __init__(self):
Ui_forWindowA.__init__(self)
QMainWindow.__init__(self)
self.setupUi(self)
# Do some stuff
window_b.py
from PyQt5.QtWidgets import QWidget, QMainWindow
from widgets.main_window import Ui_forWindowB
class WindowA(Ui_forWindowB, QMainWindow):
"""Window B"""
def __init__(self):
Ui_forWindowB.__init__(self)
QMainWindow.__init__(self)
self.setupUi(self)
# Do some stuff
Hopefully should give you an idea to get you going.
This is my code for running PyQt, however the selectFile method is not called by the button. The UI code is converted from QtCreator. I've checked my objectName for the button is browseCSV
import sys
from readCSV import *
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QFileDialog
import form
from function2 import *
from function4 import *
from Function6 import *
class App(QtWidgets.QMainWindow, form.Ui_MainWindow):
def __init__(self):
super(self.__class__, self).__init__()
self.setupUi(self) # This is defined in design.py file automatically
self.browseCSV.clicked.connect(self.selectFile)
def selectFile(self):
print ("Hello")
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = form.Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
You're not actually using your App class. So you need to do this:
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = App()
window.show()
sys.exit(app.exec_()
PS: don't ever use self.__class__ in a super call. In some scenarios, it can cause an infinite regress. If you're using Python 3, you can just use super().__init__() to avoid repeating the class name.
I have a GUI that was generated using Qt Designer, I used pyuic5 to generate a .py file. In a separate py (program.py) file I import my UI a do all my work there.
program.py
import sys, os, time
from subprocess import call
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyCred_GUI import Ui_Dialog
class MyGUI(Ui_Dialog):
def __init__(self, dialog):
Ui_Dialog.__init__(self)
self.setupUi(dialog)
self.pushButton_2.clicked.connect(self.cancelbutton)
def cancelbutton(self):
exit()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
dialog = QtWidgets.QDialog()
dialog.setWindowFlags(QtCore.Qt.WindowSystemMenuHint)
prog = MyGUI(dialog)
dialog.show()
sys.exit(app.exec_())
I pulled a lot out just to focus on the issue here. When I click my Cancel button, I want the window to hide, set a timer, and then reappear after so many seconds. I have tried every combination of self.close() self.hide() self.destroy() and none of them hide my window. I get an error that says
"AttributeError: 'MyGUI' object has no attribute 'hide'"
Which makes sense because MyGUI doesn't have a hide() function. I am at a complete loss on how to hide this window.
EDIT (Solved)
For future people, as suggested by Hi Im Frogatto dialog.hide() worked.
In your code snippet, dialog is of type QDialog and thereby having hide method. However instances of MyGUI class seem to not have such a method. So, if you write dialog.hide() in that __init__() function, you can hide it.
This example creates a single QListWidget with its items right-click enabled.
Right-click brings up QMenu. Choosing a menu opens a OS File Browser in a current user's home directory.
After a File Browser is closed QMenu re-appears which is very annoying.
How to avoid this undesirable behavior?
import sys, subprocess
from os.path import expanduser
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
layout = QtGui.QVBoxLayout(self)
self.listWidget = QtGui.QListWidget()
self.listWidget.addItems(('One','Two','Three','Four','Five'))
self.listWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.listWidget.connect(self.listWidget,QtCore.SIGNAL('customContextMenuRequested(QPoint)'),self.showMenu)
self.menu=QtGui.QMenu()
menuItem=self.menu.addAction('Open Folder')
self.connect(menuItem,QtCore.SIGNAL('triggered()'),self.openFolder)
layout.addWidget(self.listWidget)
def showMenu(self, QPos):
parentPosition=self.listWidget.mapToGlobal(QtCore.QPoint(0, 0))
menuPosition=parentPosition+QPos
self.menu.move(menuPosition)
self.menu.show()
def openFolder(self):
if sys.platform.startswith('darwin'):
subprocess.call(['open', '-R',expanduser('~')])
if sys.platform.startswith('win'):
subprocess.call(['explorer','"%s"'%expanduser('~')])
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Two ideas come to my mind:
Try adding self as a constructor parameter when defining QMenu(), passing your QWidget as a parent.
Call self.menu.hide() in the openFolder() method.
Tip: instead of using subprocess to open up explorer, there's an arguably better, cross platform solution in Qt called QDesktopServices - see http://pyqt.sourceforge.net/Docs/PyQt4/qdesktopservices.html
I have a PyQt wizard that includes a dialog box that asks the user a question. This dialog box is optional and only for use if the user wants it. A button sends a signal that the app receives and opens the window. The problem I have is that when the dialog is closed, it closes the whole app with it. How do I make sure that when the dialog is closed, the main app stays open and running? Here the code that handles the dialog box:
def new_item(self):
app = QtGui.QApplication(sys.argv)
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.exec_()
I tried adding a 'Cancel' button to close it manually but the result was the same, the whole app closed.
QtCore.QObject.connect(self.cancel, QtCore.SIGNAL(_fromUtf8("clicked()")), Dialog.close)
You shouldn't create new QApplication objects in your code, and I am not surprised that destroying that object closes the application.
Your code should look something like this:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtGui, QtCore
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.dialog = QtGui.QMessageBox(self)
self.dialog.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
self.dialog.setIcon(QtGui.QMessageBox.Question)
self.dialog.setText("Click on a button to continue.")
self.pushButtonQuestion = QtGui.QPushButton(self)
self.pushButtonQuestion.setText("Open a Dialog!")
self.pushButtonQuestion.clicked.connect(self.on_pushButtonQuestion_clicked)
self.layoutHorizontal = QtGui.QHBoxLayout(self)
self.layoutHorizontal.addWidget(self.pushButtonQuestion)
#QtCore.pyqtSlot()
def on_pushButtonQuestion_clicked(self):
result = self.dialog.exec_()
if result == QtGui.QMessageBox.Ok:
print "Dialog was accepted."
elif result == QtGui.QMessageBox.Cancel:
print "Dialog was rejected."
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.show()
sys.exit(app.exec_())
Try to use Dialog.reject instead of Dialog.close
.close() method is being used mith QMainWindow Widget, .reject() with QDialog.
In my case, I had QSystemTrayIcon as an "entry point" to my app instead of QMainWindow or QWidget.
Calling .setQuitOnLastWindowClosed(False) on my main QApplication instance helped, thanks to this answer