Search code examples
pythonc++pyqt5signals-slotssigned

PyQt5: Wrong conversion of int object when using custom signal


I am trying to create a custom pyqtSignal in order to pass some integers around, but I am having some issues. Let me first present the smallest example that demonstrates the problem:

#!/usr/local/bin/python3
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class Form(QDialog):

    post_request = pyqtSignal(int)

    def __init__(self, parent=None):
        super(Form, self).__init__(parent)

        self.button = QPushButton('Click Me')
        self.textbox = QLineEdit(self)

        layout = QHBoxLayout()
        layout.addWidget(self.button)
        layout.addWidget(self.textbox)
        self.setLayout(layout)

        self.button.clicked.connect(self.on_button_click)
        self.post_request.connect(self.test)

        self.setWindowTitle('Test')


    def on_button_click(self):
        try:
            integer = int(self.textbox.text(), 16)
            self.post_request.emit(integer)
        except ValueError:
            print('wrong input')


    def test(self, integer):
        print('I received {0:x}'.format(integer))

def run_app():
    app = QApplication(sys.argv)
    form = Form()
    form.show()
    app.exec_()

if __name__ == '__main__':
    run_app()

This is a simple window that prints out whatever you entered into the text box (unless it's non-hex characters). Now, this works fine most of the time. However, it exhibits some weird behavior when I type into the text box a number whose most significant bit is set. For example, if I type in 0x4afecafe to the text box and then click the button, it will print:

I received 4afecafe

but typing in 0xcafecafe will result in the following output:

I received -35013502

Which is not wrong if that was C/C++, but in Python this breaks my program, since -35013502 == 0xcafecafe returns False.

So my questions are:

  1. Why is this happening? I guess it has something to do with the underlying implementation of the Python wrappers, but I couldn't quite understand it.
  2. How can I work around this problem? I want the slot to receive a Python int object holding 0xcafecafe.

Solution

  • When sending signals, PyQt will always try to convert to the corresponding C++ type where it can. But where it can't, it will simply send a pointer to the Python object instead. So the simplest way to work around your problem is to not declare the specific type of the signal parameter, like this:

    class Form(QDialog):
        post_request = pyqtSignal(object)
    

    Now PyQt will not make any attempt to convert between Python and C++ types. This is leveraging the default behaviour for Python types like tuple which have no equivalent in C++.