I am trying to close a window using PyQt and open another, but this is not happening. Someone could help me?
Here is what I am doing basically:
class App(QtGui.QMainWindow, MainWindow.Ui_MainWindow):
def __init__(self, privilegio, db):
super(self.__class__, self).__init__()
self.setupUi(self)
self.get_thread = None
self.db = db
self.privilegio = privilegio
class Login(QtGui.QMainWindow, LoginWindow.Ui_McDonalds):
def __init__(self):
super(self.__class__, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.verify)
self.db = None
self.db_connection = False
self.connect_db()
def login():
app = QtGui.QApplication(sys.argv)
form_login = Login()
form_login.show()
sys.exit(app.exec_())
if __name__ == '__main__':
login()
if password == result[0][0]:
main(result[0][1], self.db)
you can connect the close event (button.clicked or some else) of the first window to window2.show
by putting before sys.exit(app.exec_())
window1.rejected.connect(window2.show)
or in your first window __init__
self.rejected.connect(window2.show)
or
self.my_button.clicked.connect(window2.show)
Related
I have a function that is ran using the Worker method. Inside this function, there can be a condition that then requires the user to input a string and that string will be used in the function. I am able to get the QInputDialog to show up, but it freezes once I start typing something and the program crashes. I have an example of what I am doing right now below:
from PySide2.QtWidgets import QApplication, QInputDialog, QMainWindow, QPushButton
from PySide2.QtCore import *
import sys, os
class Worker_Class:
class WorkerSignals():
finished = Signal()
newRecord = Signal(str)
class Worker(QRunnable):
def __init__(self, fn, *args, **kwargs):
super(Worker_Class.Worker, self).__init__()
self.fn = fn
self.args = args
self.kwargs = kwargs
self.signals = Worker_Class.WorkerSignals()
#Slot()
def run(self):
try:
self.fn(*self.args, **self.kwargs)
except:
pass
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press Me!")
self.setFixedSize(QSize(400, 300))
self.setCentralWidget(button)
self.threadpool = QThreadPool()
def start_worker(self):
worker = Worker_Class.Worker(get_dialog_value)
self.threadpool.start(worker)
def get_dialog_value():
text, ok = QInputDialog().getText(window, "Missing Module Partnumber", "Input Module Partnumber: ")
if ok and text:
return text
return ''
QCoreApplication.setLibraryPaths([os.getcwd() + "\\virtualenv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins"])
app = QApplication(sys.argv)
window = MainWindow()
window.show()
window.start_worker()
app.exec_()
This is likely not the best solution, but here is an example of how you could open a QDialog and use it's return value in the same function from a thread. There is likely a better alternative to solving your problem, however given the limited context you have provided, it is difficult to know what to suggest.
The key is to use Signals trigger the launching of the dialog, so that it is opened from the main thread. Then the issue of getting the return value back to the same thread function can be accomplished by simply stalling the function until the thread can see and access the value.
class Worker_Class(QThread):
opendialog = Signal()
def __init__(self, window):
super().__init__()
self.window = window
self.value = None
def setvalue(self, value):
self.value = value
def run(self):
self.opendialog.emit()
while self.value is None:
pass
print(self.value)
# do something with value
# ...
# ...
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("My App")
button = QPushButton("Press Me!")
self.setFixedSize(QSize(400, 300))
self.setCentralWidget(button)
def start_worker(self):
self.thread = Worker_Class(self)
self.thread.finished.connect(self.thread.deleteLater)
self.thread.opendialog.connect(self.get_dialog_value)
self.thread.start()
def get_dialog_value(self):
text, _ = QInputDialog().getText(window, "Missing Module Partnumber", "Input Module Partnumber: ")
self.thread.setvalue(text)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
window.start_worker()
app.exec_()
If you run the above code you will see that the dialog return value is successfully printed in the threads run function once the dialog closes.
I am trying to create a custum animated cursor that replaces the regular cursor for when lengthy processes are taking place similar to here and here, however, I woud like mine to be animated, for example using a gif, just as it is the case with the standard Qt.WaitCursor. How can I do this? I found this solution regarding animated system tray icons, however, I didn't manage to adapt it for it to work with the cursor icon.
As a side note: When I try to execute pm.setAlphaChannel(bm) as stated in the first link it does not work for me and I get the following error:
'AttributeError: QPixmap' object has no attribute 'setAlphaChannel'
Which is odd because according to the documentation, QPixmap does have a setAlphaChannel method.
One possible solution is to create a class that handles the update of the cursor of a given widget. In the following example the cursor is set when the start button is pressed and the cursor is restored when the stop button is pressed:
from PyQt5 import QtCore, QtGui, QtWidgets
class ManagerCursor(QtCore.QObject):
def __init__(self, parent=None):
super(ManagerCursor, self).__init__(parent)
self._movie = None
self._widget = None
self._last_cursor = None
def setMovie(self, movie):
if isinstance(self._movie, QtGui.QMovie):
if not self._movie != QtGui.QMovie.NotRunning:
self._movie.stop()
del self._movie
self._movie = movie
self._movie.frameChanged.connect(self.on_frameChanged)
self._movie.started.connect(self.on_started)
self._movie.finished.connect(self.restore_cursor)
def setWidget(self, widget):
self._widget = widget
#QtCore.pyqtSlot()
def on_started(self):
if self._widget is not None:
self._last_cursor = self._widget.cursor()
#QtCore.pyqtSlot()
def restore_cursor(self):
if self._widget is not None:
if self._last_cursor is not None:
self._widget.setCursor(self._last_cursor)
self._last_cursor = None
#QtCore.pyqtSlot()
def start(self):
if self._movie is not None:
self._movie.start()
#QtCore.pyqtSlot()
def stop(self):
if self._movie is not None:
self._movie.stop()
self.restore_cursor()
#QtCore.pyqtSlot()
def on_frameChanged(self):
pixmap = self._movie.currentPixmap()
cursor = QtGui.QCursor(pixmap)
if self._widget is not None:
if self._last_cursor is None:
self._last_cursor = self._widget.cursor()
self._widget.setCursor(cursor)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
start_btn = QtWidgets.QPushButton("start", clicked=self.on_start)
stop_btn = QtWidgets.QPushButton("stop", clicked=self.on_stop)
self._manager = ManagerCursor(self)
movie = QtGui.QMovie("loading-icon.gif")
self._manager.setMovie(movie)
self._manager.setWidget(self)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(start_btn)
lay.addWidget(stop_btn)
lay.addStretch()
#QtCore.pyqtSlot()
def on_start(self):
self._manager.start()
#QtCore.pyqtSlot()
def on_stop(self):
self._manager.stop()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
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()
My program has a MainWindow which contains my inventory system. I have added a Dialog window which pop-ups when I clicked "Add Item". I am able to successfully open the Dialog window but I can't seem to close it.
When the user tries to close the Dialog Window, it will display a messagebox asking if the user really wants to close the window. Currently, I'm using self.close(). It just closes the MessageBox I've made to prevent accidental exit and doesn't close the Dialog window unless you end it using the IDE or task manager.
Here's my code snippets:
Main.py
class Main(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.db = Database()
self.model = Model(self)
self.ui = MainWindow_ui()
self.ui.setupUi(self)
self.window = Ui_Dialog()
self.ui.addItem.clicked.connect(lambda : self.start_Form())
def start_Form(self):
window = QtGui.QDialog()
self.window.setupUi(window)
self.window.show()
def main():
app = QtGui.QApplication(sys.argv)
window = Main()
window.showMaximized()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
AddItem.py (contains the Dialog Window code)
def getNumber():
conn = sqlite3.connect('inventory.db')
c = conn.cursor()
c.execute('SELECT seq FROM sqlite_sequence')
itemNumber = c.fetchone()[0]
return int(itemNumber) + 1
class Ui_Dialog(QtGui.QDialog):
def __init__(self):
QtGui.QDialog.__init__(self)
self.setupUi(self)
def setupUi(self, Dialog):
Dialog.setObjectName(_fromUtf8("Dialog"))
Dialog.resize(413, 382)
self.buttonBox = QtGui.QDialogButtonBox(Dialog)
self.buttonBox.setStandardButtons(
QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Reset)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
def retranslateUi(self, Dialog):
self.itemCode.setText(str(getNumber()))
def accept(self):
row = self.mapper.currentIndex()
self.mapper.submit()
self.main.model.insertRow(row)
self.mapper.setCurrentIndex(row)
self.close()
def reject(self):
ret = QtGui.QMessageBox.question(None, 'Close request', 'Are you sure you want to quit?',
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
if ret == QtGui.QMessageBox.Yes:
self.close()
else:
pass
Your accept() and reject() methods effectively create an infinite loop, because calling close() will, in turn, just call those methods again. When overriding virtual methods, you should call the base-class implementation using super:
class Ui_Dialog(QtGui.QDialog):
...
def accept(self):
...
super(Ui_Dialog, self).accept()
def reject(self):
...
if ret == QtGui.QMessageBox.Yes:
super(Ui_Dialog, self).reject()
I have some trouble with creating window application using PyQt. For example: we have the following class for GUI:
class SampleMainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
...
def hideEvent(self, event):
...
def showEvent(self, event):
...
def activate(self):
...
def closeEvent(self, event):
...
What if we want to use it just for showing results and acept user inputs, and for all control logic we have another class, which use the instance of SampleMainWindow as a field:
class Programm:
def __init__(self):
self.window = SampleMainWindow()
....
app = QtGui.QApplication(sys.argv)
prog = Programm()
prog.window.show()
app.exec_()
So, if we create the instance of Programm, the application will run well, but on close we'll get an error that python.exe process could not be completed normally. But if the instance of SampleMainWindow is not a field of class:
class Programm:
def __init__(self):
win = SampleMainWindow()
....
application close well. What's the reason?
Here are the full version of Gui class:
class SampleMainWindow(QtGui.QMainWindow):
def initTray(self):
self.icon = QtGui.QSystemTrayIcon()
self.icon.setIcon(QtGui.QIcon('Tray.png'))
self.icon.show()
self.icon.activated.connect(self.activate)
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self)
moduleglobalconstants.APP_RUNNING = True
self.initTray()
self.newSession = True
self.setGeometry(300, 300, 600, 400)
self.setWindowTitle('Eye: Recently Added Lines')
self.statusBar().showMessage('Ready')
exitAction = QtGui.QAction(QtGui.QIcon('Exit.png')
,'Exit'
,self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
self.connect(exitAction
,QtCore.SIGNAL('triggered()')
,QtCore.SLOT('close()'))
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAction)
self.toolbar = self.addToolBar('Exit')
self.toolbar.addAction(exitAction)
self.textEdit = QtGui.QTextEdit()
self.scrollPosition = self.textEdit.textCursor()
self.textEdit.setReadOnly(True)
self.setCentralWidget(self.textEdit)
def hideEvent(self, event):
self.hidden = True
self.setWindowFlags(QtCore.Qt.ToolTip)
self.setVisible(False)
def showEvent(self, event):
self.hidden = False
self.setVisible(True)
def activate(self):
self.setWindowFlags(QtCore.Qt.Window)
self.show()
self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
self.activateWindow()
def questionDialog(self, caption = 'Message',text = "Are you sure?"):
self.activate()
msgBox = QtGui.QMessageBox(self)
msgBox.setWindowTitle("Eye")
msgBox.setText(caption);
msgBox.setInformativeText(text);
msgBox.setStandardButtons(QtGui.QMessageBox.Yes| QtGui.QMessageBox.No);
msgBox.setDefaultButton(QtGui.QMessageBox.Yes);
return msgBox.exec_()
def criticalDialog(self,app, caption = 'Eye: Critical Error',text = "Impossible to continue working!"):
self.activate()
msgBox = QtGui.QMessageBox.critical(self,caption,text)
moduleglobalconstants.APP_RUNNING = False
def closeEvent(self, event):
reply = self.questionDialog()
if reply == QtGui.QMessageBox.Yes:
moduleglobalconstants.APP_RUNNING = False
event.accept()
else:
event.ignore()
def showNewLines(self, singleLine = None, lines = None, mode='insert'):
if (mode == 'rewrite'):
self.textEdit.clear()
if lines:
for line in lines:
self.textEdit.insertPlainText(line.strip() + "\n")
elif singleLine:
self.textEdit.insertPlainText(singleLine.strip()+"\n")
This has to do with python's garbage collecting - as (almost) soon an object isn't referenced anymore it destroys it, so I guess the process doesn't terminate as long as the window wasn't garbage-collected.
You can try to add at the end del Programm.window or something like that (there's probably a better way of doing this, but I never programmed QT myself so I can't help you here)
see this:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
class MyWindow(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.label = QLabel("Hi, I'm a window", self)
self.button = QPushButton("&Quit", self)
self.connect(self.button, SIGNAL("clicked()"), QCoreApplication.instance(), SLOT("quit()"))
lay = QVBoxLayout()
lay.addWidget(self.label)
lay.addWidget(self.button)
self.setLayout(lay)
def closeEvent(self, event):
print "Closing the app"
self.deleteLater()
if __name__ == '__main__':
app = QApplication(sys.argv)
mw = MyWindow()
mw.show()
sys.exit(app.exec_())
the solution is to implement closeEvent method