Why QMenu reappears after function is called - python

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

Related

How can I self hide and show QDialog() in PyQT5?

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.

Access QT Designer Objects Programmatically

Disclaimer: New to both python and qt designer
QT Designer 4.8.7
Python 3.4
PyCharm 5.0.3
Question - How do I add controls to the main form or a scroll area widget on the main form (created in QT Designer) programmatically?
I have created a MainWindow in qt designer and added my widgets. The following is the entire test program in PyCharm:
import sys
from PyQt4 import QtGui, QtCore, uic
from PyQt4.QtGui import *
from PyQt4.QtCore import *
qtCreatorFile = "programLauncher.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class MyApp(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
# Cannot resize or maximize
self.setFixedSize(1045, 770)
# Add button test
self.dateLabel = QtGui.QLabel("Test")
self.pushButton = QtGui.QPushButton('Test button')
# self.scrollArea_programs.addWidget()
grid = QtGui.QGridLayout()
# self.scrollArea_programs.addWidget(self.pushButton)
grid.addWidget(self.dateLabel,0,0)
grid.addWidget(self.pushButton,0,1)
self.setLayout(grid)
self.pushButton_exit.clicked.connect(self.closeEvent)
def closeEvent(self):
QtGui.QApplication.quit()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
As you can see I tried to add controls to a grid but nothing shows up when the program runs - I have also tried to add a control to the scroll area. Can someone help me to just add 1 control to the scroll area at run time - so then I can know the proper way to do it or "a" proper way to do this.
Thanks in advance
Without having access to your programLauncher.ui and making minimal changes to your posted code, you can add your UI elements to the window like so:
from PyQt4 import QtGui
import sys
class MyApp(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
# Cannot resize or maximize
self.setFixedSize(1045, 770)
widget = QtGui.QWidget(self)
self.setCentralWidget(widget)
# Add button test
self.dateLabel = QtGui.QLabel("Test")
self.pushButton = QtGui.QPushButton('Test button')
grid = QtGui.QGridLayout()
grid.addWidget(self.dateLabel, 0, 0)
grid.addWidget(self.pushButton, 0, 1)
widget.setLayout(grid)
self.pushButton.clicked.connect(self.closeEvent)
def closeEvent(self, event):
QtGui.QApplication.quit()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
This will get the controls on the screen, although the layout leaves a lot to be desired. You may have to make modifications to this based on what's in your .ui file. One thing that you'll want to note in this example is that the QMainWindow needs a central widget (widget in the example above). You then set the layout on that widget.
You can use the designer to create your .ui file
The you can load it in your .py using something like:
from PyQt4 import QtCore, QtGui, uic
class my_win(QtGui.QMainWindow):
def __init__(self):
self.ui = uic.loadUi('my_ui.ui',self)
then you can access all your widgets with something like
self.ui.actionQuit.triggered.connect(QtGui.qApp.quit)
or
self.ui.my_button.triggered.connect(self.do_someting)
Thanks to JCVanHamme (the programLauncher.ui hint) and also outside help I now learned most of what I need to know to access MainWindow at run time. So for anyone interested in this beginner tip:
Take a blank form in QT Designer
Add a control
Run pyuic4 batch file
Take a look at the generated .py file to learn EVERYTHING about how to add controls.
Don't let the power go to your head - cheers

Query regarding Pyside

In the below mentioned example when I click on 'Help' submenu under 'View' menu multiple times its creating multiple windows. Can anyone tell me how to resolve this issue?
import sys
from PySide import Qt Gui
from PySide.QtCore import Qt
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.menu_bar()
def menu_bar(self):
helpAction = QtGui.QAction('&Help', self)
helpAction.setShortcut('Ctrl+H')
helpAction.triggered.connect(self.add_helpWindow)
menu = self.menuBar().addMenu('View')
menu.addAction(helpAction)
def add_helpWindow(self):
window = QtGui.QMainWindow(self)
window.setWindowTitle('New Window')
window.show()
if __name__ == '__main__':
import sys
app=QtGui.QApplication.instance()
if not app:
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(300, 300)
window.show()
sys.exit(app.exec_())
You help window is just a QMainWindow, which is not modal and there are no restrictions on the number that can exist. Hence why if you select the help option multiple times, you get multiple windows.
You likely want to use a QMessageBox which has its modal property set. While there is nothing forcing only one dialog to exist at a time, being modal means that the use can only interact with that window so long as it is open. Example:
from Pyside.QtGui import QMessageBox
def add_helpWindow(self):
help_dialog = QMessageBox.information(self, 'Help', 'Some Help Text Here')
help_dialog.setModal(True)
return help_dialog.exec_()
You can also get a more generic dialog box using QDialog, which is the parent class of QMessageBox.
If that's not the behavior you want, you'll need to manually track whether the user has opened that window before, and then connect a signal that is emitted when the user closes the help window to a slot that reset the existence tracker. Here is an example using a non-modal QDialog:
from Pyside.QtGui import QDialog
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.menu_bar()
self.help_open = False # Tracks if the help dialog is already open
def help_closed(self):
self.help_open = False
...
def add_helpWindow(self):
if not self.help_open:
self.help_open = True
help_dialog = QDialog(self)
# Any other setup code here
help_dialog.setModal(False)
help_dialog.accepted.connect(self.help_closed)
help_dialog.rejected.connect(self.help_closed)
help_dialog.show()

Opening a dialog from QMainWindow

I have a problem with opening a small dialog window when I press a button from my MainWindow. I know how to make a window that I need to open (let's call it EDIT WINDOW), but calling (opening) it from Main form, and another module is a different story.
Main window is showing, and working. All the imports are fine, with sqlite connection working. Basically, program is finished, only this dialog remains... It should have QMainWindow as it parent.
#!/usr/bin/python
#encoding=utf8
import sys
from PyQt4 import QtCore, QtGui
from gui import Ui_glavni
from dialog import Ui_Dialog
import snimanje #imported modules
import clear
import pretraga
import izmena #this should represent module with custom made dialog.
class Prozor(snimanje.Snimi, clear.Brisanje, pretraga.Pretraga,QtGui.QMainWindow):
def __init__(self,parent=None):
QtGui.QWidget.__init__(self,parent)
self.ui=Ui_glavni()
self.ui.setupUi(self)
QtCore.QObject.connect(self.ui.dugmeSnimi, QtCore.SIGNAL("clicked()"), self.snimi)
QtCore.QObject.connect(self.ui.dugmeOtkazi, QtCore.SIGNAL("clicked()"), self.brisanjeUnos)
QtCore.QObject.connect(self.ui.dugmeOtkazi2, QtCore.SIGNAL("clicked()"), self.brisanjeListanje)
QtCore.QObject.connect(self.ui.dugmeTrazi, QtCore.SIGNAL("clicked()"), self.pretraga)
QtCore.QObject.connect(self.ui.checkJedinica, QtCore.SIGNAL("stateChanged(int)"), self.aktivJedinica)
QtCore.QObject.connect(self.ui.checkVrednost, QtCore.SIGNAL("stateChanged(int)"), self.aktivVrednost)
QtCore.QObject.connect(self.ui.menjaIme, QtCore.SIGNAL("clicked()"), izmena.dijalog)
QtCore.QObject.connect(self.ui.dugmeBrisi, QtCore.SIGNAL("clicked()"), self.brisanjeIzBaze)
#SREDI IZMENU. SREDI PROVERU UNETIH U BAZU PO BROJU PREDMETA
def startup():
self.brisanjeUnos()
self.brisanjeListanje()
self.provera()
startup()
def aktivJedinica(self):
self.ui.lineJedinica.setEnabled(False)
self.ui.lineJedinica.setText("")
self.ui.checkJedinica.checkStateSet()
if self.ui.checkJedinica.isChecked():
self.ui.lineJedinica.setEnabled(True)
#self.ui.checkJedinica.setEnabled(False)
def aktivVrednost(self):
self.ui.vrednost.setEnabled(False)
self.ui.vrednost.setText("")
if self.ui.checkVrednost.isChecked():
self.ui.vrednost.setEnabled(True)
def pretraga(self):
if self.ui.radioIme.isChecked():
self.pretragaIme()
elif self.ui.radioBrPr.isChecked():
self.pretragaBrPr()
else:
self.pretragaSudski()
if __name__=="__main__":
program = QtGui.QApplication(sys.argv)
mojprogram = Prozor()
mojprogram.show()
sys.exit(program.exec_())

How to create a new window button PySide/PyQt?

I'm having problems with a "New Window" function in PyQt4/PySide with Python 2.7. I connected a initNewWindow() function, to create a new window, to an action and put it in a menu bar. Once a common function in desktop software. Instead of giving me a new persistent window alongside the other one the new window pops up and closes. The code I'm working on is proprietary so I created an example that does the same thing with the same error below. Is there any way to get this to work? Runs in PySide with Python 2.7. It was written in and tested in Windows.
from PySide.QtCore import QSize
from PySide.QtGui import QAction
from PySide.QtGui import QApplication
from PySide.QtGui import QLabel
from PySide.QtGui import QMainWindow
from PySide.QtGui import QMenuBar
from PySide.QtGui import QMenu
from sys import argv
def main():
application = QApplication(argv)
window = QMainWindow()
window.setWindowTitle('New Window Test')
menu = QMenuBar(window)
view = QMenu('View')
new_window = QAction('New Window', view)
new_window.triggered.connect(initNewWindow)
view.addAction(new_window)
menu.addMenu(view)
label = QLabel()
label.setMinimumSize(QSize(300,300))
window.setMenuBar(menu)
window.setCentralWidget(label)
window.show()
application.exec_()
def initNewWindow():
window = QMainWindow()
window.setWindowTitle('New Window')
window.show()
if __name__ == '__main__':
main()
If a function creates a PyQt object that the application needs to continue using, you will have to ensure that a reference to it is kept somehow. Otherwise, it could be deleted by the Python garbage collector immediately after the function returns.
So either give the object a parent, or keep it as an attribute of some other object. (In principle, the object could also be made a global variable, but that is usually considered bad practice).
Here's a revised version of your example script that demonstrates how to fix your problem:
from PySide import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
menu = self.menuBar().addMenu(self.tr('View'))
action = menu.addAction(self.tr('New Window'))
action.triggered.connect(self.handleNewWindow)
def handleNewWindow(self):
window = QtGui.QMainWindow(self)
window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
window.setWindowTitle(self.tr('New Window'))
window.show()
# or, alternatively
# self.window = QtGui.QMainWindow()
# self.window.setWindowTitle(self.tr('New Window'))
# self.window.show()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(300, 300)
window.show()
sys.exit(app.exec_())
When initNewWindow() returns, the window variable is deleted and the window's reference count drops to zero, causing the newly created C++ object to be deleted. This is why your window closes immediately.
If you want to keep it open, make sure to keep a reference around. The easiest way to do this is to make your new window a child of the calling window, and set its WA_DeleteOnClose widget attribute (see Qt::WidgetAttribute).

Categories

Resources