PyQt: How to send parameters by reference with QAxWidget

4k Views Asked by At

I'm attempting to use PyQt to talk to an ActiveX COM object in Python. This method works in Python:

myobj.dynamicCall('SetAbsMovePos(int, double)', [0, 10])

However, I can't send arguments by reference. From the docs, the method I wish to call is:

int GetNumHWUnits (int lHWType, int& plNumUnits)

and the basic example code is:

QVariantList params = ...
int result = object->dynamicCall("GetNumHWUnits(int, int&)", params).toInt();

I presume the equivalent code in Python, using ctypes, should be:

num = ctypes.c_int()
myobj.dynamicCall('GetNumHWUnits(int, int&)', [6, ctypes.byref(num)])

but num is never updated.

What's the equivalent code or workaround in Python, and how can I send and later read an argument of type int& using Python?

3

There are 3 best solutions below

1
101 On BEST ANSWER

Got the solution from the PyQt mailing list. A reference to the list of arguments is needed, as only that list is updated; the original QVariant objects never are. Seems fairly obvious in retrospect!

typ = QVariant(6)
num = QVariant(0)
args_list = [typ, num]

self.dynamicCall('GetNumHWUnits(int, int&)', args_list)

print 'Num of HW units =', args_list[1].toInt()[0]

A full code example is shown in this post.

1
jonie83 On

You could try to pass a list with just one element:

def funct(a):
    a[0] = 4

b = [3]
funct(b)
print b[0]

Output: 4

1
Aaron Digulla On

QVariant is involved:

    QVariant dynamicCall(const char *, QList<QVariant> & /GetWrapper/);
%MethodCode
        Py_BEGIN_ALLOW_THREADS
        sipRes = new QVariant(sipCpp->dynamicCall(a0, *a1));
        Py_END_ALLOW_THREADS

        // Update the input list with the (possibly) new values.
        for (SIP_SSIZE_T i = 0; i < PyList_GET_SIZE(a1Wrapper); ++i)
        {
            QVariant *v = new QVariant(a1->at(i));
            PyObject *v_obj = sipConvertFromNewType(v, sipType_QVariant, NULL);

In a nutshell, QVariant is a wrapper to pass a value by reference.

Which means by passing c_int, you have wrapped the value twice. Try to pass a real QVariant instead of c_int as second argument. Without this, the automatic type coercion in PyQt would take your c_int, wrap its value in a QVariant, call dynamicCall. During the call, the new QVariant is updated but there is no connection to the original c_int so your instance won't change.

This should work:

num = QVariant(0)
myobj.dynamicCall('GetNumHWUnits(int, int&)', [6, num])
print repr(num.value())