【问题标题】:Selecting/actioning items in Kendo UI widgets using Excel VBA使用 Excel VBA 在 Kendo UI 小部件中选择/操作项目
【发布时间】:2017-03-30 20:02:38
【问题描述】:

卡住了 - 需要帮助!

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

我已经尝试了我能想到的一切,但无济于事。我用过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>

【问题讨论】:

  • 如果你注释掉On Error Resume Next,你会得到错误,在哪一行?
  • 我只是按“原样”在代码上试了一下,没有出现任何错误。
  • 之前的代码 sn-p 是一团糟。我重做了它以使其更易于阅读和理解。
  • 也许有人可以给我一个 javascript 解决方案,或者至少 something 来尝试。我已经尝试了所有我能想到或在这个网站和其他网站上找到的东西。 米奇
  • 此页面是否与您尝试自动化的页面相似? .....demos.telerik.com/kendo-ui/grid/index

标签: vba excel internet-explorer kendo-ui


【解决方案1】:

这是如何选择 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


来源:

来自official Kendo UI API documentation 的select 方法1:

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

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

请注意,这实际上是错误。第一行在索引 0 处,not 索引 1。select 方法的字符串参数被视为 jQuery 选择器,来自 official jQuery API documentation 的 :eq() 选择器@987654325 @:

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

【讨论】:

  • 天啊,罗宾,单行工作只有一个例外,这很容易弄清楚。这部分的索引号select('tr:eq(6) 完美地选择了行。感谢您提供的解决方案、出色的文档以及花时间向老人展示新事物。问候
  • @Mitch 太好了!您还需要知道如何从剑道下拉列表中进行选择吗?如果是这样,问另一个问题,在这里发表评论,我会帮助你。并且不要忘记包含所有相关的 HTML。
  • 是的,我仍然需要知道如何做一个下拉菜单。此时我所做的只是“打开”下拉菜单并手动选择一个选项。在问另一个问题之前,我需要自己解决这个问题,看看我是否能先弄清楚。这是我现在使用的代码Set objButton = ie.Document.getElementById("Tank_ID") objButton.Focus objButton.Click
  • 我发布了一个新问题,其中包含代码、jquery 脚本和一些我尝试在下拉列表框中选择项目的内容。我想我也需要一些帮助,如果你不介意的话。你可以在这里找到它 (stackoverflow.com/questions/46497282/…)
【解决方案2】:

这是在黑暗中拍摄的……哈哈

这可能是一个类似的页面

单步代码

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

【讨论】:

  • 感谢@jsotola 的努力。尽管到目前为止都没有工作,k-link 有 74 个元素,它们“点击”了所有但该行的内容。但是我仍在尝试不同的类名、标签名、索引号。我不会放弃。米奇
  • 我刚刚用你上面的方法解决了我一直在处理的一个完全不同的问题(并且把我的头发拉了过来)。只是想花点时间说声谢谢!我知道这有一天会派上用场。
【解决方案3】:

这是我的尝试。我试图在 cmets 中尽可能多地解释。让我知道进展如何,根据发布的 HTML,这似乎应该可行,但请让我们知道 :)

我假设您已经打开了一个 IE 窗口并需要获取指向该窗口的指针。将 getIEPointer 函数中的“myWebSiteURL”更新为您尝试访问的站点的 URL。在这种情况下,少即是多,因为我正在进行通配符匹配。例如。寻找 '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

【讨论】:

  • 感谢 Ryan 抽出宝贵时间查看此内容。我不确定框架的事情。一切都是动态的,基于沿途做出的某些选择。我没有遇到打开页面、在租用名称文本条目中输入数字并单击搜索按钮的问题。就在那时, item/s 的行/s 出现了。这就是我卡住的地方。我将在星期四回来工作并尝试您的脚本(因为我无法在家中尝试)。再次感谢
  • 好的,米奇,谢谢。也许这只是我,但你的问题还是有点不清楚。您是否尝试从表中查找/选择特定行?如果为真,从一行到下一行是否有任何可识别的特征会缩小搜索范围?
  • Ryan,如果您单击上面的屏幕截图,它会显示屏幕,因为它看起来像我卡住的点。我认为一个简单的点击就可以了,但我尝试过的每个场景都没有任何作用。我知道用鼠标单击行(行)后,其中一个代码行会更改为class = "k-State-Selected", aria - Selected = "true" 之类的内容,我认为这是&lt;tr role="row" data-uid="db62d811-4337-477c-a0fd-0e9e036670bb"&gt; 行的一部分,但我不确定。
  • 我问了这个页面的作者怎么做,他给我发了这个:.Document.getElementById("drgdLease").Data("kendogrid").Select ("tr:eq(1)"),但这给了我一个“不支持这个方法”的错误。然后我因为写了未经授权的东西而受到惩罚,所以他的任何帮助都结束了。
  • 所以你试图点击一行,点击一个列标题,或者别的什么?我仍然有点不清楚结果应该是什么。您是否必须单击其中一个单元格才能以某种方式获得数据?
猜你喜欢
  • 1970-01-01
  • 2020-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多