Hi Konstantin,
Interesting observation about the shift to self.close() in the subsequent
tutorials... I think I will switch over to the self.close() method as my
standard way to quit the application, but I'm also going to keep the main()
layout recommended by sourceforge because it seems to help keep the order
of garbage collection in proper sequence. And given my experience with
interactions between Qt functionality (described below), I want to keep
things as orderly as possible.
I went back to the View StatusBar tutorial to review my understanding and
do some further checks. Here's my observations:
1. I'm not sure I agree with you about the intended functionality of the
"View" checkmenu, but as the tutorial isn't exactly super clear about what
is supposed to happen, I will assume you are correct. That is to say, as
soon as the mouse hovers over the "View" menubar text, the statusbar
"ready" text disappears. From then on, the statusbar text is only visible
when the View menu is clicked open and a) the "view statusbar" box is
positively checked and b) the mouse hovers over the "view statusbar"
submenu. If the "view statusbar" box is unchecked in the submenu, nothing
will ever show up in the statusbar.
2. When I go back and run *just* the checkMenu code by itself, as shown in
the tutorial (but also with my "if app is None" logic added to avoid
multiple app instances causing Spyder grief...), I get correct "View"
behavior (as defined by you) both in Spyder and from the command line
(yay!). Here is that code:
*************************************************
import sys
from PyQt5.QtWidgets import QMainWindow, QAction, QApplication
from PyQt5.QtCore import QCoreApplication
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.statusbar = self.statusBar()
self.statusbar.showMessage('Ready')
menubar = self.menuBar()
viewMenu = menubar.addMenu('View')
viewStatAct = QAction('View statusbar', self, checkable=True)
viewStatAct.setStatusTip('View statusbar')
viewStatAct.setChecked(True)
viewStatAct.triggered.connect(self.toggleMenu)
viewMenu.addAction(viewStatAct)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Check menu')
self.show()
def toggleMenu(self, state):
if state:
self.statusbar.show()
else:
self.statusbar.hide()
if __name__ == '__main__':
app = QCoreApplication.instance()
if app is None:
app = QApplication(sys.argv)
ex = Example()
app.exec_()
*************************************************
But what I didn't explain to you initially was that as I did each tutorial,
I added each lesson's new functionality to the existing GUI design. So by
the time I was at the checkmenu tutorial, I had incorporated the statusBar,
menuBar (with both "File" and it's sub-menus & the "View" function in
question), pushButtons (including "Quit"), and toolTips. It is this code
where "View" runs fine from Spyder (as defined by you) but exits when I
choose "View" when run from the command line. So there is some weird
interaction that I don't understand. Here is the code that misbehaves, do
you see anything obviously wrong?
Jim
*************************************************
import sys
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtWidgets import QApplication, QMessageBox
from PyQt5.QtWidgets import QToolTip, QPushButton, QDesktopWidget
from PyQt5.QtWidgets import QMainWindow, QAction, QMenu
from PyQt5.QtGui import QFont, QIcon
class Example(QMainWindow):
"""
QMainWindow is a subclass of QWidget and inherits all of its methods,
but
also has some of its own, like the status bar. The QWidget is the base
class for all user interface objects in PyQt5. The default constructor
has
no parent; a widget with no parent is called a window.
"""
def __init__(self): # Constructor method for "Example" class.
super().__init__() # Inherited QWidget constructor.
self.title = 'PyQt5 EXAMPLE MAIN WINDOW; STATUS & MENU BARS; TITLE
w/'\
' ICON; QUIT PUSHBUTTON, & TOOLTIPS'
self.width = 800
self.height = 400
self.initUI()
def initUI(self): # Creating the GUI.
# QMainWindow ATTRIBUTES:
QToolTip.setFont(QFont('SansSerif', 10)) # Static method.
self.setToolTip('This is a <b>QWidget</b> widget') # Rich text
(bold).
self.resize(self.width, self.height)
# Code that will center the window is placed in the custom
"center()"
# method below.
self.center()
# Methods below inherited from QWidget class:
self.setWindowTitle(self.title)
self.setWindowIcon(QIcon('icons8_List_48px.png')) # QIcon object.
# Method below inherited (uniquely) from QMainWindow class. First
call
# creates status bar, subsequent calls return the statusBar object.
self.statusBar().showMessage('Ready')
# MENUBAR:
menubar = self.menuBar()
fileMenu = menubar.addMenu('File')
viewMenu = menubar.addMenu('View') # Doesn't work properly.
newAct = QAction('New', self)
impMenu = QMenu('Import', self)
impAct = QAction('Import mail', self)
impMenu.addAction(impAct)
exitAct = QAction(QIcon('exit.png'), 'Exit', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.setStatusTip('Exit application')
exitAct.triggered.connect(self.close)
fileMenu.addAction(newAct)
fileMenu.addMenu(impMenu)
fileMenu.addAction(exitAct)
viewStatAct = QAction('View statusbar', self, checkable=True)
viewStatAct.setStatusTip('View statusbar')
viewStatAct.setChecked(True)
viewStatAct.triggered.connect(self.toggleMenu)
viewMenu.addAction(viewStatAct)
# BUTTONS:
btn = QPushButton('Button', self)
btn.setToolTip('This is a <b>QPushButton</b> widget')
btn.resize(btn.sizeHint())
btn.move(150, 50)
qbtn = QPushButton('Quit', self)
qbtn.setToolTip('<b>QPushButton</b> widget to quit the application')
# qbtn.clicked.connect(QCoreApplication.instance().quit)
qbtn.clicked.connect(self.close)
qbtn.resize(qbtn.sizeHint())
qbtn.move(150, 80)
def toggleMenu(self, state):
if state:
self.statusBar.showMessage()
else:
self.statusBar.clearMessage()
def center(self):
# QDesktopWidget class provides information about the user's
desktop,
# including screen size. This allows Qt to center the window on the
# user's desktop.
# Rectangle specifying geometry of main window, including any window
# frame:
qr = self.frameGeometry()
# Figure out screen resolution for monitor and get center point:
cp = QDesktopWidget().availableGeometry().center()
# Given the width & height of the rectangle, set center of rectangle
# to center of the screen:
qr.moveCenter(cp)
# Move top-left point of application window to the top-left point of
# the qr rectangle, thus centering the window on the screen:
self.move(qr.topLeft())
def closeEvent(self, event):
"""
If a QWidget is closed via the "X" button in the upper-right corner,
the QCloseEvent is generated. To modify the widget behavior, the
closeEvent() event handler needs to be reimplemented.
"""
reply = QMessageBox.question(self, 'Message',
"Are you sure you want to quit?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
def main():
"""
SOURCE:
http://pyqt.sourceforge.net/Docs/PyQt5/gotchas.html#crashes-on-exit
Creating the "main" function to contain the event loop and call the GUI
Example class changes the garbage collection order (module destructors
vs.
the actual Qapplication destruction). This keeps the GUI from hanging
and killing the kernel. But the VIEW menubar fucntionality still does
not
work properly...
"""
global app
# The "if app is None" logic below keeps kernal from dying every other
time.
#
https://stackoverflow.com/questions/40094086/python-kernel-dies-for-second-run-of-pyqt5-gui
# Qt does not like more than one QApplication object in the same
process.
# The "instance()" code gets the application instance if it was already
# created.
app = QCoreApplication.instance()
if app is None:
app = QApplication(sys.argv) # QApp requires the sys arg list.
ex = Example()
ex.show() # Widget first created in memory; "show()" required for
display.
app.exec_()
if __name__ == "__main__":
main()
*****************************************************
On Saturday, August 26, 2017 at 2:48:49 PM UTC-7, Konstantin Krayn wrote:
>
> Jim,
>
> Thank you for the garbage collection info link and the restructured code
> sample that works in Spyder. It looks quite relevant and helpful if even a
> bit too complicated for me to understand from the first glance.
>
> As to the zetcode tutorials, I am at "Dialogs in PyQt5", and so far I have
> not encountered any further issues while running the tutorial code samples
> in Spyder. I keep using self.close handler to exit apps, and btw at some
> point in the tutorial they too stopped using app.quit and switched to
> self.close (without explaining why).
>
> I had no problem with the "View StatusBar" tutorial code, which worked
> properly both in Spyder and from the command line on my system. I do not
> know why the app unexpectedly terminates when run from the command line on
> your system, but the behavior when run in Spyder that you described as
> symptoms sounds like the intended functionality to me. My understanding is
> that, apart from the initial "ready" message that legitimately disappears
> for good after you rollover the menu bar, the only thing to see in the
> status bar of this Qt application is the status bar tip for the toggle
> action menu item itself. So, when it is checked and you hover the mouse
> pointer over it, you see the status bar tip, and you do not see the tip
> when the action item is unchecked. This is how it works on my system, and,
> judging by you description, it appears to work the same way on yours, which
> I think is the intended behavior.
>
> Konstantin
>
> On Sat, Aug 26, 2017 at 9:58 PM, jimmott via spyder <
> [email protected] <javascript:>> wrote:
> [...]
> > Incidentally, how far along in the zetcode tutorials are you? Were you
> able to get the "View StatusBar" checkMenu's QAction to work properly? I
> was thinking about posting this as another, separate
> Windows+Python3+PyQt5+Spyder issue...
> >
> > Here are my symptoms: Running the checkMenu code in Spyder, the toggle
> doesn't permanently change the statusBar view on/off as I believe is
> intended. The statusBar message turns off permanently just by hovering the
> mouse cursor over the View menu label. Then, the only way to get the
> statusBar message to be visible again is to click the checkMenu "View"
> button and hover the mouse over the text in the QAction sub-menu.
> Alternatively, when I run this same code from the command line, the
> checkMenu QAction to toggle whether the StatusBar is visible or not
> actually terminates the application instead.
> >
> > Let me know when you get to this point in the tutorial or what you
> experienced if you've already tried it out...
> >
> > Jim
>
--
You received this message because you are subscribed to the Google Groups
"spyder" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/spyderlib.
For more options, visit https://groups.google.com/d/optout.