【问题标题】:How to call an existing LibreOffice python macro from a python script如何从 python 脚本调用现有的 LibreOffice python 宏
【发布时间】:2015-04-02 15:46:40
【问题描述】:

目前我用这个来调用现有的 LibreOffice 宏:

def OnLOtimestamp(self):
        try:
            pid= Popen(['lowriter '"'"'vnd.sun.star.script:fs2TimeStamp.py$fs2_TimeStamp?language=Python&location=user'"'"],shell=True).pid
        except OSError, e:
            self.notify_show("Timestamp Error",str(e))
        self.ma2.SetLabel("Macro timestamp")
        self.database['Time_stamp'] = self.database['Time_stamp'] + 1

关键位是 Popen 调用,其中宏名称是 fs2TimeStamp.py,函数是 fs2_TimeStamp,但这感觉像是在逃避,我宁愿通过 Uno 直接调用。 我的研究表明,我可能需要使用 MasterScriptProvider、XscriptProvider 和 XscriptInvocation,但尝试破译 Uno API 就像在糖浆中游泳。 有人有使用 Uno 在 Libreoffice 中调用现有宏的代码示例吗?

编辑:
到目前为止,答案似乎是否定的! 这是当前的游戏状态。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
##
# a python script to run a libreoffice python macro externally
#
import uno
from com.sun.star.connection import NoConnectException
from com.sun.star.uno  import RuntimeException
from com.sun.star.uno  import Exception
from com.sun.star.lang import IllegalArgumentException
def test2(*args):
    localContext = uno.getComponentContext()
    localsmgr = localContext.ServiceManager
    resolver = localsmgr.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext )
    try:
        ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
    except NoConnectException as e:
        print ("LibreOffice is not running or not listening on the port given - ("+e.Message+")")
        return
    except IllegalArgumentException as e:
        print ("Invalid argument given - ( "+ e.Message+ ")")
        return
    except RuntimeException as e:
        print ("An unknown error occurred: " + e.Message)
        return

    servmgr = ctx.ServiceManager
    desktop = servmgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
    model = desktop.getCurrentComponent()
#    scriptP = model.getScriptProvider()
#    print("scriptP", scriptP)
    scriptx = model.getScriptProvider().getScript('vnd.sun.star.script:fs2TimeStamp.py$fs2_TimeStamp?language=Python&location=user')
    print("scriptx", scriptx)
    try:
        scriptx.invoke("",0,0)
    except IllegalArgumentException as e:
        print ("The command given is invalid ( "+ e.Message+ ")")
        return
    except RuntimeException as e:
        print("An unknown error occurred: " + e.Message)
        return
    except Exception as e:
        print ("Script error ( "+ e.Message+ ")")
        print(e)
        return
    except:
        print("Error")
    return(None)

test2()

当在 Libreoffice 中作为宏调用时,此代码运行良好,并且 scriptx 打印为:

scriptx <pythonscript.PythonScript object at 0x7fa2879c42e8>

但是,当从命令行运行时,脚本什么也不做,并且 scriptx 打印为:

scriptx pyuno object (com.sun.star.script.provider.XScript)0x1e749d8{, supportedInterfaces={com.sun.star.lang.XTypeProvider,com.sun.star.script.provider.XScript}}

所以 getScriptProvider 或 getScript 都没有提供他们需要的东西。我目前不知道缺少什么,但我从骨子里觉得我已经接近解决方案了。

谁能看到我哪里出错了?

【问题讨论】:

    标签: python macros wxpython libreoffice


    【解决方案1】:

    最后,我有一个可行的解决方案。叮!董!

    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    ##
    # a python script to run a libreoffice python macro externally
    #
    import uno
    from com.sun.star.connection import NoConnectException
    from com.sun.star.uno  import RuntimeException
    from com.sun.star.uno  import Exception
    from com.sun.star.lang import IllegalArgumentException
    def test2(*args):
        localContext = uno.getComponentContext()
        localsmgr = localContext.ServiceManager
        resolver =  localsmgr.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext )
        try:
            ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
        except NoConnectException as e:
            print ("LibreOffice is not running or not listening on the port given - ("+e.Message+")")
            return
        msp = ctx.getValueByName("/singletons/com.sun.star.script.provider.theMasterScriptProviderFactory")
        sp = msp.createScriptProvider("")
        scriptx = sp.getScript('vnd.sun.star.script:fs2TimeStamp.py$fs2_TimeStamp?language=Python&location=user')
        try:
            scriptx.invoke((), (), ())
        except IllegalArgumentException as e:
            print ("The command given is invalid ( "+ e.Message+ ")")
            return
        except RuntimeException as e:
            print("An unknown error occurred: " + e.Message)
            return
        except Exception as e:
            print ("Script error ( "+ e.Message+ ")")
    
    return(None)
    
    test2()
    

    注意:为清楚起见,现有的 python 脚本称为fs2TimeStamp.py,它包含定义为def fs2_TimeStamp(*args):的1(一)个函数
    见行:

    scriptx = sp.getScript('vnd.sun.star.script:fs2TimeStamp.py$fs2_TimeStamp?language=Python&location=user')   
    

    它存储在$HOME/.config/libreoffice/4/user/Scripts/python

    要使此解决方案发挥作用,libreoffice 必须在监听模式下运行,因此请使用以下命令启动 libreoffice:

    soffice "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;" --writer --norestore
    

    nohup soffice "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;" --writer --norestore &
    

    您也可以使用更直接的方法(在本例中为 writer):

    lowriter "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp"
    

    nohup lowriter "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp" &
    

    另请注意,您必须使用 python3

    运行脚本

    【讨论】:

      【解决方案2】:

      这是第一个答案的更简单和更通用的版本,它非常倾向于我的具体问题,它称为宏,然后通过 TCP 与另一个程序通信,然后插入通过 TCP 连接发送的文本。
      此版本将独立运行,并且应该可以立即复制。
      和以前一样,您必须在侦听模式下启动 LibreOffice 编写器(有关选项,请参阅上一个答案):

      lowriter "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp"
      

      这是外部python例程,必须用python3运行:

      #!/usr/bin/python3
      # -*- coding: utf-8 -*-
      ##
      # a python script to run a libreoffice python macro externally
      # NOTE: for this to run start libreoffice in the following manner
      # soffice "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;" --writer --norestore
      # OR
      # nohup soffice "--accept=socket,host=127.0.0.1,port=2002,tcpNoDelay=1;urp;" --writer --norestore &
      #
      import uno
      from com.sun.star.connection import NoConnectException
      from com.sun.star.uno  import RuntimeException
      from com.sun.star.uno  import Exception
      from com.sun.star.lang import IllegalArgumentException
      def uno_directmacro(*args):
          localContext = uno.getComponentContext()
          localsmgr = localContext.ServiceManager
          resolver = localsmgr.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext )
          try:
              ctx = resolver.resolve("uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
          except NoConnectException as e:
              print ("LibreOffice is not running or not listening on the port given - ("+e.Message+")")
              return
          msp = ctx.getValueByName("/singletons/com.sun.star.script.provider.theMasterScriptProviderFactory")
          sp = msp.createScriptProvider("")
          scriptx = sp.getScript('vnd.sun.star.script:directmacro.py$directmacro?language=Python&location=user')
          try:
              scriptx.invoke((), (), ())
          except IllegalArgumentException as e:
              print ("The command given is invalid ( "+ e.Message+ ")")
              return
          except RuntimeException as e:
              print("An unknown error occurred: " + e.Message)
              return
          except Exception as e:
              print ("Script error ( "+ e.Message+ ")")
              print(e)
              return
          return(None)
      
      uno_directmacro()
      

      这是 LibreOffice python 宏 directmacro.py 应该位于:

      $HOME/.config/libreoffice/4/user/Scripts/python
      

      (假设这里使用 LibreOffice 版本 4)

      directmacro.py 宏:

      #!/usr/bin/python
      class FontSlant():
          from com.sun.star.awt.FontSlant import (NONE, ITALIC,)
      
      def directmacro(*args):
      #get the doc from the scripting context which is made available to all scripts
          desktop = XSCRIPTCONTEXT.getDesktop()
          model = desktop.getCurrentComponent()
          text = model.Text
          tRange = text.End
          cursor = desktop.getCurrentComponent().getCurrentController().getViewCursor()
          doc = XSCRIPTCONTEXT.getDocument()
          parentwindow = doc.CurrentController.Frame.ContainerWindow
      
      # your cannot insert simple text and text into a table with the same method
      # so we have to know if we are in a table or not.
      # oTable and oCurCell will be null if we are not in a table
          oTable = cursor.TextTable
          oCurCell = cursor.Cell
          insert_text = "This is text inserted into a LibreOffice Document\ndirectly from a macro called externally"
          Text_Italic = FontSlant.ITALIC
          Text_None = FontSlant.NONE
          cursor.CharPosture=Text_Italic
          if oCurCell == None: # Are we inserting into a table or not?
              text.insertString(cursor, insert_text, 0)
          else:
              cell = oTable.getCellByName(oCurCell.CellName)
              cell.insertString(cursor, insert_text, False)
          cursor.CharPosture=Text_None
          return None 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-26
        • 2023-03-11
        • 2014-02-20
        • 1970-01-01
        相关资源
        最近更新 更多