<div dir="ltr">Hi again Phil,<br><br>I just installed PyQt 6.0.2. The problems from my previous email are fixed now (thanks!) and my application is able to launch. I am having a few new issues now, though.<br><br>Here's the main one:<br><br>    from PyQt6 import QtCore, QtGui, QtWidgets<br>    app = QtWidgets.QApplication([])<br><br>    mbox = QtWidgets.QMessageBox()<br>    mbox.setStandardButtons(QtWidgets.QMessageBox.StandardButtons.Yes | <a href="http://QtWidgets.QMessageBox.StandardButtons.No">QtWidgets.QMessageBox.StandardButtons.No</a>)<br>    ret = mbox.exec()<br><br>    # The return value is an integer, but QtWidgets.QMessageBox.StandardButtons<br>    # can't be converted or compared to integers.<br><br>    # This prints False no matter which button you clicked:<br>    print(ret == QtWidgets.QMessageBox.StandardButtons.Yes)<br><br>    # TypeError: int() argument must be a string, a bytes-like object or a number, not 'StandardButtons'<br>    int(QtWidgets.QMessageBox.StandardButtons.Yes)<br><br>    # TypeError: unsupported operand type(s) for &: 'int' and 'StandardButtons'<br>    print(ret & QtWidgets.QMessageBox.StandardButtons.Yes)<br><br>As far as I can tell, there's no way to check the return value of `QtWidgets.QMessageBox.exec()` without hardcoding integer values (yuck). One way to fix it would be to change `.exec()`'s return type to `QtWidgets.QMessageBox.StandardButtons`, but since the integer values of the enum are officially publicly documented (<a href="https://doc.qt.io/qt-6/qmessagebox.html#StandardButton-enum">https://doc.qt.io/qt-6/qmessagebox.html#StandardButton-enum</a>), my guess is that adding support for int comparisons to the `StandardButtons` class would be a better solution. Or maybe there already is a way to do this comparison and I just don't see it?<br><br>A second issue:<br><br>    from PyQt6 import QtCore, QtGui, QtWidgets<br>    app = QtWidgets.QApplication([])<br>    folder = QtWidgets.QFileDialog.getExistingDirectory(None, 'Select a folder')<br>    print(folder)<br><br>For whatever reason, this actually creates a *file*-selection dialog, which doesn't let me choose a folder. (Platform is KDE Neon (Ubuntu 20.04), if it helps.)<br><br>One more issue I found on 6.0.1 after my previous email -- though unfortunately without a way to trigger it consistently -- is that sometimes `QMainWindow.restoreState()` or `QMainWindow.restoreGeometry()` (not sure which) crashes if the pre-existing state (or geometry) was saved by PyQt5.<br><br>The best workaround I can think of is to append the PyQt version name ("PyQt5"/"PyQt6") to the application name passed to the QSettings constructor, thus preventing PyQt6 from ever trying to read PyQt5's settings and vice versa. Luckily, my application has very few settings and I don't expect anyone to switch back and forth between PyQt versions, so this won't be a big problem. It's still not really ideal, though.<br><br>Is this crash considered a bug? If not, is there a better way for me to handle this situation?<br><br>Thanks again!<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Feb 10, 2021 at 12:11 PM RoadrunnerWMC <<a href="mailto:roadrunnerwmc@gmail.com">roadrunnerwmc@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Thank you! I'll look forward to the next release.<br>
<br>
<br>
On Tue, Feb 9, 2021 at 7:45 AM Phil Thompson<br>
<<a href="mailto:phil@riverbankcomputing.com" target="_blank">phil@riverbankcomputing.com</a>> wrote:<br>
><br>
> On 07/02/2021 20:33, RoadrunnerWMC wrote:<br>
> > Hello. I'm trying to port a PyQt5 application to PyQt6, but am running<br>
> > into a few issues, which I think are bugs in PyQt6 itself. I've<br>
> > distilled them down to minimum reproducible examples, all of which<br>
> > work fine on PyQt5. My environment is Ubuntu 20.04 (KDE Neon), using<br>
> > the system-provided Python 3.8.5.<br>
> ><br>
> > Here's an issue with signals/slots signature matching:<br>
> ><br>
> >     from PyQt6 import QtCore, QtGui, QtWidgets<br>
> ><br>
> >     class MainWindow(QtWidgets.QMainWindow):<br>
> >         def __init__(self):<br>
> >             super().__init__()<br>
> >             self.myList = QtWidgets.QListWidget()<br>
> ><br>
> > self.myList.itemActivated.connect(self.itemActivatedHandler)<br>
> ><br>
> >         @QtCore.pyqtSlot(QtWidgets.QListWidgetItem)<br>
> >         def itemActivatedHandler(self, item):<br>
> >             print('Item activated')<br>
> ><br>
> >     app = QtWidgets.QApplication([])<br>
> >     mw = MainWindow()<br>
> >     mw.show()<br>
> >     app.exec()<br>
> ><br>
> > On PyQt 6.0.1, this results in the following traceback:<br>
> ><br>
> >     Traceback (most recent call last):<br>
> >       File "/path/to/pyqt6_test.py", line 14, in <module><br>
> >         mw = MainWindow()<br>
> >       File "/path/to/pyqt6_test.py", line 7, in __init__<br>
> >         self.myList.itemActivated.connect(self.itemActivatedHandler)<br>
> >     TypeError: decorated slot has no signature compatible with<br>
> > itemActivated(QListWidgetItem*)<br>
><br>
> That's fixed in the current PyQt6 snapshot.<br>
><br>
> > This seems to affect every slot that takes one or more pointers to Qt<br>
> > objects. If there's a way to denote pointers in the decorator,<br>
> > something like<br>
> > `@QtCore.pyqtSlot(pointerTo(QtWidgets.QListWidgetItem))`,<br>
> > it doesn't seem to be explained in the documentation<br>
> > (<a href="https://www.riverbankcomputing.com/static/Docs/PyQt6/signals_slots.html" rel="noreferrer" target="_blank">https://www.riverbankcomputing.com/static/Docs/PyQt6/signals_slots.html</a>).<br>
> ><br>
> > Here's a different issue, related to<br>
> > `QtWidgets.QGraphicsItem.itemChange()`:<br>
> ><br>
> >     from PyQt6 import QtCore, QtGui, QtWidgets<br>
> ><br>
> >     class CustomGraphicsItem(QtWidgets.QGraphicsItem):<br>
> >         def boundingRect(self):<br>
> >             return QtCore.QRectF(0, 0, 10, 10)<br>
> ><br>
> >         def itemChange(self, change, value):<br>
> >             return QtWidgets.QGraphicsItem.itemChange(self, change,<br>
> > value)<br>
> ><br>
> >     class MainWindow(QtWidgets.QMainWindow):<br>
> >         def __init__(self):<br>
> >             super().__init__()<br>
> >             self.scene = QtWidgets.QGraphicsScene(0, 0, 100, 100, self)<br>
> >             self.view = QtWidgets.QGraphicsView(self.scene, self)<br>
> ><br>
> >             self.scene.addItem(CustomGraphicsItem())<br>
> ><br>
> >     app = QtWidgets.QApplication([])<br>
> >     mw = MainWindow()<br>
> >     mw.show()<br>
> >     app.exec()<br>
> ><br>
> > On PyQt 6.0.1, this results variously in one of the following three<br>
> > outcomes (most often the second):<br>
> ><br>
> >     Traceback (most recent call last):<br>
> >       File "/path/to/pyqt6_test_2.py", line 8, in itemChange<br>
> >         return QtWidgets.QGraphicsItem.itemChange(self, change, value)<br>
> >     TypeError: itemChange(self, QGraphicsItem.GraphicsItemChange,<br>
> > Any): argument 2 has unexpected type 'GraphicsItemChange'<br>
> ><br>
> >     Traceback (most recent call last):<br>
> >       File "/usr/lib/python3.8/enum.py", line 309, in __call__<br>
> >         return cls.__new__(cls, value)<br>
> >     RecursionError: maximum recursion depth exceeded while calling a<br>
> > Python object<br>
> ><br>
> >     Segmentation fault<br>
> ><br>
> > I notice this example *does* work fine if I replace<br>
> > `QtWidgets.QGraphicsItem` in `itemChange()`'s body with `super()` or<br>
> > `super(CustomGraphicsItem, self)`. Maybe that syntax is required now?<br>
> > But even if so, it shouldn't really be segfaulting if you do it the<br>
> > wrong way.<br>
><br>
> That's a SIP code generator bug that is fixed in the next snapshot.<br>
><br>
> > Here's a third issue:<br>
> ><br>
> >     from PyQt6 import QtCore, QtGui, QtWidgets<br>
> ><br>
> >     class CustomGraphicsView(QtWidgets.QGraphicsView):<br>
> >         def mouseMoveEvent(self, event):<br>
> >             print(event.x())<br>
> ><br>
> >     class MainWindow(QtWidgets.QMainWindow):<br>
> >         def __init__(self):<br>
> >             super().__init__()<br>
> >             self.scene = QtWidgets.QGraphicsScene(0, 0, 100, 100, self)<br>
> >             self.view = CustomGraphicsView(self.scene, self)<br>
> >             self.view.setMouseTracking(True)<br>
> ><br>
> >             self.setCentralWidget(self.view)<br>
> ><br>
> >     app = QtWidgets.QApplication([])<br>
> >     mw = MainWindow()<br>
> >     mw.show()<br>
> >     app.exec()<br>
> ><br>
> > On PyQt 6.0.1, running this and then moving your cursor over the<br>
> > graphics view results in the following traceback:<br>
> ><br>
> >     Traceback (most recent call last):<br>
> >       File "/path/to/pyqt6_test_3.py", line 6, in mouseMoveEvent<br>
> >         print(event.x())<br>
> >     AttributeError: 'QMouseEvent' object has no attribute 'x'<br>
> ><br>
> > I don't really have any idea about this one. The same thing happens if<br>
> > you try to access `.pos()`, so that's not a workaround.<br>
><br>
> PyQt6 does not support API elements that are deprecated (ie. x(), y(),<br>
> pos() etc.). However the Qt docs are wrong in that these methods aren't<br>
> marked as such.<br>
><br>
> The exact equivalent of event.x() is event.position().toPoint().x()<br>
><br>
> > PyQt is by far my favorite GUI framework in any language, so I'm<br>
> > really looking forward to being able to use PyQt6. Thanks in advance<br>
> > for any help you can provide!<br>
><br>
> The SIP bug is quite serious so I may make new releases sooner rather<br>
> than later.<br>
><br>
> Thanks,<br>
> Phil<br>
</blockquote></div>