0

我使用以下代码从 xlwings 模块在 VBA 中调用 RunPython:

Sub Portfolio_Optimze()
RunPython ("import quotes; quotes.get_quote()")
SolverAdd CellRef:="$H$18:$H$24", Relation:=1, FormulaText:="$J$18:$J$24"
SolverAdd CellRef:="$B$15:$G$15", Relation:=4
SolverOk SetCell:="$H$16", MaxMinVal:=1, ValueOf:=0, ByChange:="$B$15:$G$15", _
    Engine:=1, EngineDesc:=" GRG Nonlinear "
SolverSolve

如何让 SolverAdd 代码等到 RunPython 代码完全完成?

4

3 回答 3

2

一些信息开始:​​Mac 上的 Excel 只允许外部进程在 Excel 空闲时写入单元格,即没有宏运行时。这就是为什么RunPythonMac 上的调用作为后台进程运行的原因,只有在调用宏完成运行时才会真正启动。

我会建议以下两种解决方案之一:

1) 也在 Python 中对求解器部分进行编程,例如使用scipy.optimize.

2) 将求解器 VBA 放入它自己的 Sub 并从 Python 调用它。这是当前 xlwings 下一版本的计划功能,请参见此处,但您现在可以像这样解决(假设wb是您的工作簿):

app = xlwings.Application(wkb=wb)
app.xl_app.run_VB_macro('SolverMacro')

UPDATE,从 v0.7.1 开始,现在得到了适当的支持:

>>> solver_macro = wb.macro('SolverMacro')
>>> solver_macro()
于 2015-06-19T07:58:21.593 回答
1

另一种方法是在 python 代码末尾的隐藏工作表中更改一个值,并使用一个Worksheet_Change片段来触发一些 vba 代码。如果隐藏表是“补充”,则在 python 代码末尾添加类似这样的内容:

Range('Supplement', 'A1').value = Range('Supplement', 'A1').value +1

“补充”表中的 vba 可能是:

Private Sub Worksheet_Change(ByVal Target As Range)
    If Not Intersect(Target, Me.Range("A1")) Is Nothing Then
        Worksheets("Main1").Range("A1").WrapText = True
    End If
End Sub

请记住,Application.EnableEvents需要= True

于 2015-09-12T18:07:10.420 回答
0

可能有点笨拙,但也请查看Application.OnTime可让您安排代码在设定时间运行的方法。因此,将您的求解器代码放入另一个过程中,调用RunPython然后安排求解器过程,例如 10 秒的时间。

或者,可能是一个更好的答案,让 python 代码在完成后写入一个Range或文本文件。带有求解器代码的 proc 将查看范围或文件以查看 python 是否已完成。如果 python 没有完成,则安排自己在 N 秒内再次运行,否则运行求解器。

于 2015-06-19T07:08:32.860 回答