【问题标题】:pyqt instance method inside ctypesctypes中的pyqt实例方法
【发布时间】:2016-01-16 22:12:33
【问题描述】:

所以我不完全确定如何提出这个问题,因为我正在与使用 ctypes 的另一个人的代码 http://pb.lericson.se/p/FpbYhX/ 的部分进行交互,并且我找不到任何其他完全可以做到的答案(这很接近: How can I get methods to work as callbacks with python ctypes?)。无论如何,就这样吧。

所以我想在 QThread 类中运行上面的代码,这样我就可以将带有相关信息的 pyqtSignal 传递回我的主程序,但我不知道如何克服以下错误:

ctypes.ArgumentError: argument 2: <type 'exceptions.TypeError'>: expected CFunctionType instance instead of instance method

我只真正了解python,之前从未接触过cTypes。下面是绘制此代码的更广泛的类(这基本上只是我将链接文件中的大部分代码复制到 QThread 类中)。问题从底部向上 17 行出现。据我所知,python 对我在“self.MTRegisterContactFrameCallback”中使用“self.my_callback”不满意,因为 my_callback 是一个实例方法。这一切都很好,但是我如何将这个实例方法变成一个 CFunctionType 同时仍然保留在我的类中?

class Handler(QThread):
  trackPadTouched = pyqtSignal(str)
  def __init__(self, parent=None):
    super(Handler, self).__init__(parent)
    self.parent = parent
    print self.parent
    global MTFunctions
    MTFunctions = MTFunctions(parent=self)
    self.parent = parent
    CFArrayRef = ctypes.c_void_p
    CFMutableArrayRef = ctypes.c_void_p
    CFIndex = ctypes.c_long

    self.MultitouchSupport =     ctypes.CDLL("/System/Library/PrivateFrameworks/MultitouchSupport.framework/MultitouchSupport")

    self.CFArrayGetCount = self.MultitouchSupport.CFArrayGetCount
    self.CFArrayGetCount.argtypes = [CFArrayRef]
    self.CFArrayGetCount.restype = CFIndex

    self.CFArrayGetValueAtIndex = self.MultitouchSupport.CFArrayGetValueAtIndex
    self.CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex]
    self.CFArrayGetValueAtIndex.restype = ctypes.c_void_p

    MTDeviceCreateList = self.MultitouchSupport.MTDeviceCreateList
    MTDeviceCreateList.argtypes = []
    MTDeviceCreateList.restype = CFMutableArrayRef
    MTDataRef = ctypes.POINTER(MTData)



    MTDeviceRef = ctypes.c_void_p

    self.MTRegisterContactFrameCallback = self.MultitouchSupport.MTRegisterContactFrameCallback
    self.MTRegisterContactFrameCallback.argtypes = [MTDeviceRef, ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, MTDataRef, ctypes.c_int, ctypes.c_double, ctypes.c_int)]
    self.MTRegisterContactFrameCallback.restype = None

    MTDeviceStart = self.MultitouchSupport.MTDeviceStart
    MTDeviceStart.argtypes = [MTDeviceRef, ctypes.c_int]
    MTDeviceStart.restype = None


    devices = self.MultitouchSupport.MTDeviceCreateList()
    num_devices = self.CFArrayGetCount(devices)
    print "num_devices =", num_devices
    for i in xrange(num_devices):
        device = self.CFArrayGetValueAtIndex(devices, i)
        print "device #%d: %016x" % (i, device)
        self.MTRegisterContactFrameCallback(device, self.my_callback)
        self.MTDeviceStart(device, 0)

  def my_callback(self, device, data_ptr, n_fingers, timestamp, frame):
    #print threading.current_thread(), device, data_ptr, n_fingers, timestamp, frame
    for i in xrange(n_fingers):
        data = data_ptr[i]
        d = [data_ptr[i].normalized.position.x * 100, data_ptr[i].normalized.position.y * 100]
        self.handler(i, d, n_fingers)
    return 0

def main():
    app = QtGui.QApplication(sys.argv)
    ex = Handler()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main() 

【问题讨论】:

    标签: python class pyqt ctypes typeerror


    【解决方案1】:

    完全未经测试,但试试这个:

    MTContactCallbackFunction = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int,
                                    MTDataRef, ctypes.c_int,
                                    ctypes.c_double, ctypes.c_int)
    
    class Handler(QThread):
      trackPadTouched = pyqtSignal(str)
      def __init__(self, parent=None):
        ...
        self.MTRegisterContactFrameCallback.argtypes = [MTDeviceRef, MTContactCallbackFunction]
        ...
    
      @MTContactCallbackFunction
      def my_callback(device, data_ptr, n_fingers, timestamp, frame):
        ...
    

    【讨论】:

    • my_callback 需要是可以调用self.handler 的方法,所以保留问题中的版本。而是让实例__init__ 设置self._callback = MTContactCallbackFunction(self.my_callback),它通过Python 引用使回调实例保持活动状态。然后把注册改成使用self.MTRegisterContactFrameCallback(device, self._callback)
    • 顺便说一句,为每个实例增加共享库引用计数(即使用CDLL 加载它)是浪费时间,就像在__init__ 中定义所有函数原型一样,因此您可以提供将这些定义至少移动到类级别(如果不是模块级别)的版本。
    • @eryksun 您的方法解决了问题。既然我有一个工作模型,我将清理程序的其余部分以提高速度。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    • 2016-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-24
    • 1970-01-01
    相关资源
    最近更新 更多