使用Excel VBA在Kendo UI小部件中select/操作项目

卡住了 – 需要帮助!

我正在尝试在我们内部公司网站的IE网页上自动执行操作项目。 我可以填写任何types的文本对象 ,点击提交button等,但有几个项目是在网格/表(Kendo网格)下拉列表中。 我似乎无法弄清楚如何从这些网格/表格或下拉菜单中进行select。

我尝试了所有我能想到的,都无济于事。 我已经使用getElementById()getElementsByTagName()getElementsByName() ,甚至一些networking抓取技术。

不幸的是,由于网页在内部网站上,没有其他人能够对其进行testing。

这是我的代码的主要部分

  'After opening the web page, inserting a number, selecting the "search" ' (all from the VBA script), I have to use a "mousemove", "mousedown" and ' "mouseup" to select the item, whick is what the "myClick" subroutine does myClick '<<< THIS IS WHAT I WANT TO GET RID OF >>> 'I left the following segment in to show that I'm able to do several other functions myDocs = ie.Document.getElementById("DispatchComments").Value If myInfo = True Then ie.Document.getElementById("DispatchComments").Value = "__" & myCell5 & "__" & myDocs Else: End If 'IF ESTIMATED TIME IS LESS THAN 0, ENTER 120 - Enter estimated time If ie.Document.getElementById("TotalEstimatedTime").Value < 10 Then ie.Document.getElementById("TotalEstimatedTime").Value = 120 Else: End If End With End Sub 

`

这是input租赁号码并点击searchbutton后的屏幕截图 。 我设法select行的唯一方法是以编程方式在显示的三个白色背景区域之一中单击鼠标。 我的代码使用鼠标移动和坐标来select行,向下滚动到一个坦克下拉,并点击它打开,所以我可以手动select一个坦克号码。

这部分代码是我卡住的地方

 Set myChoice1 = ie.Document.getElementById("drgdLease").getElementsByTagName("tr")(1) With myChoice1 .getElementsByTagName("td")(0).Focus '<<---Works all the way to here .FireEvent ("onmouseover") '<<---No errors from this point on .FireEvent ("onmousedown") 'but doesn't do anything .FireEvent ("onmouseup") .FireEvent ("onclick") '<<---some other things tried .FireEvent ("ondblclick") .FireEvent ("onselect") td.innerText = value td.innerHTML = value End With '<tr role="row" data-uid="db62d811-4337-477c-a0fd-0e9e036670bb"> ' <td role="gridcell">998262</td> '<<---This is the info/row I need to select ' <td role="gridcell">HENDERSON (SMACKOVER) STORAGE</td> ' <td role="gridcell">ORYAN OIL &amp; GAS</td> 

检查我想要select的区域的元素显示这个HTML

  name="Result"> <div class="k-widget k-grid" id="drgdLease" style="-ms-touch-action: double-tap-zoom pinch-zoom;" data-role="grid"> <table class="k-selectable" role="grid" style="-ms-touch-action: double-tap-zoom pinch-zoom;" data-role="selectable"> <colgroup> <col> <col> <col> </colgroup> <thead class="k-grid-header" role="rowgroup"> <tr role="row"> <th class="k-header k-with-icon" scope="col" data-title="Lease Number" data-index="0" data-field="LeaseCode" data-role="columnsorter"> <a tabindex="-1" class="k-header-column-menu" href="#"> <span class="k-icon ki-arrowhead-s"></span> </a> <a class="k-link" href="/LeaseProfiles/GetLeasesSearch?Length=9&amp;drgdLease-sort=LeaseCode-asc">Lease Number</a> </th> <th class="k-header k-with-icon" scope="col" data-title="Lease Name" data-index="1" data-field="LeaseName" data-role="columnsorter"> <a tabindex="-1" class="k-header-column-menu" href="#"> <span class="k-icon ki-arrowhead-s"></span> </a> <a class="k-link" href="/LeaseProfiles/GetLeasesSearch?Length=9&amp;drgdLease-sort=LeaseName-asc">Lease Name</a> </th> <th class="k-header k-with-icon" scope="col" data-title="Lease Operator" data-index="2" data-field="LeaseOperator.OperatorName" data-role="columnsorter"> <a tabindex="-1" class="k-header-column-menu" href="#"> <span class="k-icon ki-arrowhead-s"></span> </a> <a class="k-link" href="/LeaseProfiles/GetLeasesSearch?Length=9&amp;drgdLease-sort=LeaseOperator.OperatorName-asc">Lease Operator</a> </th> </tr> </thead> <!-- This is what the code looks like before selecting the item. ie: before clicking anywhere on the row. --> <tbody role="rowgroup"> <tr role="row" data-uid="db62d811-4337-477c-a0fd-0e9e036670bb"> <td role="gridcell">998262</td> <td role="gridcell">HENDERSON (SMACKOVER) STORAGE</td> <td role="gridcell">ORYAN OIL &amp; GAS</td> </tr> </tbody> </table> <!-- This is what the code changes to after clicking the row. Note the class and arial are added on the `tr role` line, which may be binding the data. --> <tr role="row" data-uid="db62d811-4337-477c-a0fd-0e9e036670bb" class = "k-state- selected" arial = "true"> <td role="gridcell">998262</td> <td role="gridcell">HENDERSON (SMACKOVER) STORAGE</td> <td role="gridcell">ORYAN OIL &amp; GAS</td> 

这是如何selectkendoGrid的第一行:

 ie.Document.parentWindow.execScript "$('#drgdLease').data('kendoGrid').select('tr:eq(0)');" 

下面是一个演示,展示了正式的Kendo UI Grid Widget Demo页面上的等效代码。

请注意可能的竞争条件的解决方法。 虽然这种特殊的竞争条件也适用于您的情况,但您还需要了解另一种竞争条件。

有可能,在开始search租赁号码之后, kendoGrid完成更新之前,您的代码可能会尝试select第一行。 这将导致默认显示的数据/先前的search数据的第一行被选中, 然后网格被更新,导致select消失。

在下面的代码中使用的解决方法在这种情况下将不起作用 ,因为它总是(错误地)检测选定的行。 需要一个不同的解决方法。 (我可以想一些 – 最合适的可能取决于你的具体使用情况。)

 '============================================================================================ ' Module : <in any standard module> ' Version : 0.1 ' Part : 1 of 1 ' References : Microsoft Internet Controls [SHDocVw] ' Source : https://stackoverflow.com/a/46483783/1961728 '============================================================================================ ' Required if late binding SHDocVw Private Enum tagREADYSTATE READYSTATE_UNINITIALIZED = 0 READYSTATE_LOADING READYSTATE_LOADED READYSTATE_INTERACTIVE READYSTATE_COMPLETE End Enum Public Sub AutomateKendoUI() ' Create and use a new instance of IE With New SHDocVw.InternetExplorer '##Late Binding: CreateObject("InternetExplorer.Application") .Visible = True ' False is default .Navigate "http://demos.telerik.com/kendo-ui/grid/index" Do Until .Busy = False And .ReadyState = SHDocVw.tagREADYSTATE.READYSTATE_COMPLETE: DoEvents: Loop '##Late Binding: = tagREADYSTATE.READYSTATE_COMPLETE ##No Enums: = 4 ' Get and use the main DOM With .Document ' Race Condition Work-Around ' Kendo UI may not have finished loading the Grid data before we invoke its select method. ' Therefore, we continue to invoke the method until a selected row is detected. Do .parentWindow.execScript "$('#grid').data('kendoGrid').select('tr:eq(0)');" On Error Resume Next Dim elm_tr As MSHTML.HTMLTableRow: Set elm_tr = .querySelector("#grid tr.k-state-selected") On Error GoTo 0 Loop While elm_tr Is Nothing End With End With End Sub 

资料来源:

select方法1的官方Kendo UI API文档 :

示例 – select第一个和第二个表格行

 var grid = $("#grid").data("kendoGrid"); grid.select("tr:eq(1), tr:eq(2)"); 

请注意,这实际上是错误的 。 第一行是索引0, 而不是索引1. select方法的string参数被视为jQueryselect器,并从官方的jQuery API文档中为:eq()select器2

eqselect器

说明: *在匹配集合内的索引n处select元素。*

jQuery(":eq(index)")

索引:要匹配的元素的基于的索引。

有趣的是, tbody对象的官方Kendo UI API文档虽然3

示例 – 获取第一个表格行

 var grid = $("#grid").data("kendoGrid"); var row = grid.tbody.find("tr:eq(0)"); 


1 http://docs.telerik.com/kendo-ui/api/javascript/ui/grid#methods-select
2 https://api.jquery.com/eq-selector/
3 http://docs.telerik.com/kendo-ui/api/javascript/ui/grid#fields-tbody

这里是在黑暗中拍摄….大声笑

这可能是一个类似的页面

单步代码

 Option Explicit Sub extractKendo() ' Dim IE As Object ' Set IE = CreateObject("InternetExplorer.Application") Dim ie As InternetExplorer Set ie = New InternetExplorer ie.Visible = True ie.navigate "http://demos.telerik.com/kendo-ui/grid/index" While ie.readyState <> 4 Or ie.Busy DoEvents Wend Dim doc As HTMLDocument Set doc = ie.Document Dim elm As IHTMLElementCollection Set elm = doc.getElementsByClassName("k-link k-pager-nav") elm(0).Click elm(4).Click elm(0).Click elm(3).Click elm(3).Click elm(3).Click elm(0).Click Set elm = doc.getElementsByClassName("k-list-scroller") Set elm = elm(1).getElementsByTagName("li") elm(0).Click elm(1).Click elm(2).Click elm(3).Click ie.Quit Set ie = Nothing End Sub 

这是我的尝试。 我尽可能在评论中解释。 让我知道这是怎么回事,基于HTML张贴,这似乎应该工作,但请让我们知道:)

我假设你已经有一个IE窗口打开,并需要获得一个指向该窗口的指针。 将getIEPointer函数中的“ myWebSiteURL ”更新为您尝试访问的站点的URL。 在这种情况下,我正在做一个通配符比较less。 例如,寻找“goo”会匹配“Good”和“Google”的url。

 Option Explicit Public Sub getElements() Dim ie As Object 'I'm assuming you already have it open in IE, if not, then load the page Set ie = getIEPointer("myWebSiteURL") 'Exit if the window couldn't be located If ie Is Nothing Then Debug.Print "No Window Found!" Exit Sub End If Dim element As Object 'get the Div element which contains all the elements we are interested in 'If this doesn't work, make sure your pages doesn't contain FRAMES 'Here's a page about Frames 'https://stackoverflow.com/questions/16699267/vba-ie-automation-read-iframe Set element = ie.Document.getElementById("drgdLease") 'Select the first instance of the tbody element in the drgdLease div Set element = element.getElementsByTagName("tbody")(0) 'Select the first instance of the td, inside the TBody Set element = element.getElementsByTagName("td")(0) 'Interact with the element element.Click element.Value = "12345" End Sub 'This function will return an IE object, I'm assuming the page is already open Private Function getIEPointer(ByRef UrlPart As String) As Object Dim window As Object For Each window In CreateObject("Shell.Application").Windows() If window.LocationURL Like "*" & UrlPart & "*" Then Set getIEPointer = window Exit Function End If Next Set getIEPointer = Nothing End Function