1

I'm trying to get a USB camera to display a live video feed to a PyQt5 application. I have working code for a wx wrapper but I need this to work in PyQt5. After many searches I just can't find the right syntax.

Here's the working WX code:

import wx
from wx.lib.activexwrapper import MakeActiveXClass
from win32com.client import gencache

class mainFrm( wx.Frame ):
    def __init__( self, *args, **kwds ):
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__( self, *args, **kwds )

        self.dcamModule = gencache.EnsureModule( '{6B9BD678-9710-44D9-9282-A088094E4216}', 0, 1, 0 )       
        dcamClass = MakeActiveXClass( self.dcamModule.ActiveGeni, eventObj = self )
        self.camera = dcamClass( self, -1 )

        self.camera.SetSize(( 752, 480 ))
        self.SetClientSize( ( 752, 480 ))

        self.camera.Acquire = True 
        self.camera.Display = True


if __name__ == '__main__':
    GUI = wx.PySimpleApp( 0 )
    frame_1 = mainFrm( None, -1, "" )
    GUI.SetTopWindow( frame_1 )
    frame_1.Show()
    GUI.MainLoop()

When I debug what is happening this is what I get as the objects are built:

print(self.dcamModule)
<module 'win32com.gen_py.6B9BD678-9710-44D9-9282-A088094E4216x0x1x0' from '...\\AppData\\Local\\Temp\\3\\gen_py\\3.5\\6B9BD678-9710-44D9-9282-A088094E4216x0x1x0.py'>

print(dcamClass)
<class 'wx.lib.activexwrapper.AXControl_ActiveGeni'>

print(self.camera)
<win32com.gen_py.None.AXControl_ActiveGeni>

Here is the PyQt5 that I've tried. Is doesn't give an error but it doesn't start the camera either:

import sys
from PyQt5 import uic, QtWidgets
from PyQt5.QAxContainer import QAxWidget

qtCreatorFile = "ui\\camera_form.ui"
LandingPageUI, LandingPageBase = uic.loadUiType(qtCreatorFile)

class cameraForm(LandingPageBase, LandingPageUI):

    def __init__(self,  parent=None):
        QtWidgets.QMainWindow.__init__(self)
        LandingPageBase.__init__(self)
        self.setupUi(self)

        self.ocx = QAxWidget("'{6B9BD678-9710-44D9-9282-A088094E4216}', 0, 1, 0 ")
#Is there something else to do here?
        self.ocx.Acquire = True
        self.ocx.Display = True
        self.axWidget = self.ocx     #axWidget is the QaXWidget on the form


if __name__ == "__main__":
    app=QtWidgets.QApplication.instance() 
    if not app: 
         app = QtWidgets.QApplication(sys.argv)

    window = cameraForm()
    window.show()
    sys.exit(app.exec_())


When I try the PyQt version this is what I get when debugging:

print(self.axWidget)
<PyQt5.QAxContainer.QAxWidget object at 0x036C4C60>

It seems that the MakeActiveXClass step for wx is doing something that isn't done with PyQt but I can't figure out what it should be instead.

Here are some resources that I've referenced so far:

win32.Dispatch vs win32.gencache in Python. What are the pros and cons?

What can you do with COM/ActiveX in Python?

I've tried QCamera as well but it does not recognize the camera.

jshort
  • 353
  • 1
  • 2
  • 15

2 Answers2

1

Making self.axWidget = self.ocx does not cause self.ocx to replace self.axWidget in the window, the solution is to use self.axWidget by setting the control using the setControl() method:

class cameraForm(LandingPageBase, LandingPageUI):
    def __init__(self, parent=None):
        super(cameraForm, self).__init__(parent)
        self.setupUi(self)

        self.axWidget.setControl("{6B9BD678-9710-44D9-9282-A088094E4216}")
        self.axWidget.setProperty("Acquire", True)
        self.axWidget.setProperty("Display", True) 

(Code not tested)

Community
  • 1
  • 1
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks for answering! There must be multiple problems with my code because that didn't solve it. See my edit with debug output. – jshort Feb 08 '20 at 05:52
  • @jshort I don't understand why you think debug in Wx and Qt should be similar. On the other hand what is the output of `self.axWidget.generateDocumentation()`? – eyllanesc Feb 08 '20 at 05:56
  • @jshort try changing `self.axWidget.setProperty("Acquire", True)` to `self.axWidget.dynamicCall("Acquire", True)` and `self.axWidget.setProperty("Display", True) ` to `self.axWidget.dynamicCall("Display", True)` – eyllanesc Feb 08 '20 at 06:10
  • generateDocumentation() didn't produce anything and it wasn't picky about the dynamicCall but you were right, of course, about how to use setControl. Never did get it to work with the CLSID though – jshort Feb 08 '20 at 22:14
0

Got it to work by finding the right call in the setControl. Not sure why the CLSID didn't work but this did:

    self.axWidget.setControl("ActiveGeni.ActiveGeni")

I'm excited to use this feature in Qt but I'm still not sure how to see what other activeX I can call. For example I could use "Microsoft Web Browser" and load a PDF but not "Adobe PDF Reader". How do I see what is available?

jshort
  • 353
  • 1
  • 2
  • 15