使用Excel VBA选择/操作Kendo UI小部件中的项目

时间:2017-03-30 20:02:39

标签: excel vba excel-vba internet-explorer kendo-ui

坚持 - 需要帮助!

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

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

不幸的是,由于网页位于内部网站上,因此没有其他人可以对其进行测试。

这是我的代码的主要部分

 '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

`

输入租约号码并点击搜索按钮后,这是screen shot。我设法选择行的唯一方法是以编程方式在显示的三个白色背景区域之一中单击鼠标。我的代码使用mousemove和坐标来选择行,向下滚动到坦克下拉列表并单击它打开,这样我就可以手动选择坦克编号。

这部分代码是我被困的地方

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>

检查我正在尝试选择的区域的元素显示此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 k-i-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 k-i-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 k-i-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>

3 个答案:

答案 0 :(得分:2)

这是如何选择kendoGrid的第一行:

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


以下是演示官方Kendo UI Grid Widget Demo页面上的等效代码的演示。

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

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

在这种情况下, 下面的代码中使用的解决方法将无效 ,因为它将始终(错误地)检测选定的行。需要一种不同的解决方法。 (我可以想到一些 - 最合适的可能取决于你的确切用例。)

'============================================================================================
' 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方法 official Kendo UI API documentation 1

  

示例 - 选择第一个和第二个表行   
...

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

请注意,这实际上是 错误 。第一行是索引0,不是索引1. select方法的字符串参数被视为jQuery选择器,official jQuery API documentation表示:eq()选择器< SUP> 2

  

eq选择器

     

说明:*在匹配的集合中选择索引 n 的元素。*

     

jQuery(":eq(index)")

     要匹配的元素的

索引: 的索引。

有趣的是,tbody对象的official Kendo UI API documentation通过 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

答案 1 :(得分:0)

这是一个在黑暗中的镜头....大声笑

这可能是一个类似的页面

单步代码

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

答案 2 :(得分:0)

这是我的尝试。我试着在评论中尽可能多地解释。让我知道它是怎么回事,根据发布的HTML,似乎这应该有用,但请告诉我们:)

我假设您已经打开了IE窗口,需要获取指向该窗口的指针。将 getIEPointer 函数中的“ myWebSiteURL ”更新为您尝试访问的网站的网址。在这种情况下,因为我正在进行通配符匹配,所以更少。例如。寻找'goo'会匹配'Good'和'Google'的网址。

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