【问题标题】:Is there a google-script method like Application.Intersect(Target, Range) in Excel?Excel 中是否有类似 Application.Intersect(Target, Range) 的谷歌脚本方法?
【发布时间】:2019-06-03 11:38:18
【问题描述】:

现在我明白这个问题更深层次了,并且与事件的跟踪有关。

在 Excel 中,我使用以下代码:

If Not Intersect(Target, Sh.Range("$A$1:$A$300")) Is Nothing sub_do_something()

这里,Target——选中单元格的地址,Intersect判断单元格是否属于指定范围。

我在系统中使用它来填写和计算项目的成本。

用户单击计算模板特定部分中的一行。该脚本确定所选单元格的地址并将用户切换到目录的特定工作表。接下来,用户单击所需的目录行,脚本复制该行中一定范围的单元格并将用户返回到计算中。发生这种情况时,复制的数据会插入到一系列单元格中,从选定的单元格开始。

因此,创建一个可以有超过 100 个位置的计算被大大简化了。

在 Excel 中,一切正常,但很快我计划将此项目转移到基于云的服务,而 Google 表格是最佳选择。

唉,在 GAS 中只能跟踪某些事件,例如,使用 onOpen 或 onEdit 触发器。 Excel 有更多的跟踪 events

在 StackOverflow 上搜索后,发现了几个与跟踪事件相关的类似问题,例如,How to find where user's cursor is in Document-bound scriptCan we implement some code that fires upon selecting something in google document?Google app script monitor spreadsheet selected ranges

从这些问题的答案可以看出,在 GAS 中没有 Excel 中的 Intersect(Target, Range) 这样简单的解决方案。 最后一个示例使用侧边菜单,从中运行脚本,每秒查询工作表 5 次,并在“数据”字段中显示活动单元格的地址。

很遗憾,此代码对我不起作用。在调试器中,getActiveRange() 函数工作正常,但这段代码不起作用:

$(document).ready(() => {
   setInterval(()=>{
   google.script.run.withSuccessHandler(log).getActiveRange();
   },200)    
  })       
  log(e) => {
    $('#data').val(e)
  }

问题。

如果有人做过类似的事情,请分享您的经验。 或者告诉我为什么这个例子不起作用。如果他能复活,我会让他适应我的任务。

【问题讨论】:

  • 据我了解,您想检查一个单元格是否在指定范围内?看看this post
  • @s1c0j1 谢谢,但这并不是您所需要的。使用 onEdit 触发器,一切都很清楚,但在我的示例中,没有单元格 change event 用户单击单元格并出现 SelectionChange Event。这是来自 Excel,但逻辑是相同的。这是一个单元格的值尚未更改但单元格已被选中的事件,我需要捕获它。
  • 对。抱歉。是的,很遗憾,但 Google Apps 脚本似乎无法跟踪用户选择。此外,您最常触发的脚本是每分钟一次。你可以通过确保你的函数运行至少一分钟并每分钟触发一次来解决这个问题..
  • @s1c0j1 在 Excel 中,用户现在花费大约 1 秒时间从目录中选择一项并将其传输到计算。因此,完成计算只需几分钟。如果以每分钟 1 次的频率执行此操作,则将需要几个小时。在Google app script monitor spreadsheet selected ranges 中,每 200 毫秒查询一次工作表。那会很好,但是这个例子对我不起作用。你试过了,这段代码对你有用吗?
  • 范围可以在一个函数中检查多次,因此不会每分钟一次。我没有尝试过该代码,因为我不相信它可以在 Google Apps 脚本编辑器中工作。它看起来很陌生,我认为这是从编辑器外部调用脚本的另一种方式。不过我不能确定。

标签: excel vba google-apps-script google-sheets


【解决方案1】:

这是一个想法。不过我不能让它工作。

也许其他人可以给出更好的答案。

此外,我认为 GAS 无法让函数 24/7 运行,因为总运行时间存在限制。如果最后一次更新时间超过 10 分钟之前,您可能希望添加一个退出脚本的代码保护。

function checkSelection() {

    var spreadsheet = SpreadsheetApp.getActive();
    var targetRange = spreadsheet.getRange('activate');
    // Change your named ranged name here

    var tCol = targetRange.getColumn();
    var tLastCol = targetRange.getLastColumn();
    var tRow = targetRange.getRow();
    var tLastRow = targetRange.getLastRow();

    var num = 0;

    for (num; num < 115; ++num) {
    // Repeats the code below 100 times

        var range = spreadsheet.getActiveRange();
        var row = range.getRow();
        var col = range.getColumn();

        if (col >= tCol && col <= tLastCol && row >= tRow && row <= tLastRow) {
            range.setBackground('#000000');
            // Change the code in this block to your code.
        }

        SpreadsheetApp.flush();
        Utilities.sleep(500);
        // Waits half a second before repeating
    }
}

115 次重复 * 500ms 等待似乎运行了将近一分钟,然后触发器将再次触发整个函数。

【讨论】:

  • 对于基本用户,90 分钟/天是当前触发器运行时间限制。
【解决方案2】:

两个范围的交集

您可以使用它来计算两个范围的交集。它需要以下形式的对象:{rg1:'A1Notation String',rg2:'A1Notation String'}

function calculateIntersection1(rgObj) {
  var iObj={};
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getActiveSheet();
  var rg1=sh.getRange(rgObj.rg1);
  var rg2=sh.getRange(rgObj.rg2);
  var iObj={rg1colst:rg1.getColumn(),rg1colen:rg1.getColumn()+rg1.getWidth()-1,rg1rowst:rg1.getRow(),rg1rowen:rg1.getRow()+rg1.getHeight()-1,rg2colst:rg2.getColumn(),rg2colen:rg2.getColumn()+rg2.getWidth()-1,rg2rowst:rg2.getRow(),rg2rowen:rg2.getRow()+rg2.getHeight()-1};
  if(iObj.rg1colst>iObj.rg2colen || iObj.rg1colen<iObj.rg2colst || iObj.rg1rowst>iObj.rg2rowen || iObj.rg1rowen<iObj.rg2rowst || iObj.rg2colst>iObj.rg1colen || iObj.rg2colen<iObj.rg1colst || iObj.rg2rowst>iObj.rg1rowen || iObj.rg2rowen<iObj.rg1rowst) {
    return '<h1>No intersecting cells</h1>';
  }else{
    var vA1=rg1.getValues();
    var v1=[];
    var vA2=rg2.getValues();
    var v2=[];
    for(var i=0;i<vA1.length;i++){
      for(var j=0;j<vA1[i].length;j++){
        var s=Utilities.formatString('(%s,%s)', iObj.rg1rowst+i,iObj.rg1colst+j);
        v1.push(s);
      }
    }
    for(var i=0;i<vA2.length;i++){
      for(var j=0;j<vA2[i].length;j++){
        var s=Utilities.formatString('(%s,%s)', iObj.rg2rowst+i,iObj.rg2colst+j);
        v2.push(s);
      }
    }
    var oA=[];
    for(var i=0;i<v1.length;i++){
      var idx=v2.indexOf(v1[i]);
      if(idx>-1){
        oA.push(v2[idx]);
      }
    }
    return Utilities.formatString('Intersecting Cells: %s', oA.join(', '));
  }
}

它要么返回字符串“No Intersecting Cells”,要么返回一个以(row, column) 格式标识相交单元格的字符串。

【讨论】:

    【解决方案3】:

    我从事过一个类似的项目,解决方案如下:

    function onSelectionChange(e)
    {
      var ss = e.source;
      var Sh = ss.getActiveSheet();
      var range = Sh.getRange("A1:A300");
      var target = e.source.getActiveRange();
    
      //check for intersection
      if(RangeIntersects(target, range))
      {
        Logger.log("Changed Row: " + target.getRow() + "\nValue: " + target.getValue());
      }
    }
    
    //returns true if target intersects with the predefined range
    function RangeIntersects(target, range)
    {
      return (target.getLastRow() >= range.getRow()) && (range.getLastRow() >= target.getRow()) && (target.getLastColumn() >= range.getColumn()) && (range.getLastColumn() >= target.getColumn());
    }
    
    

    【讨论】:

    • 谢谢,但出现错误:“ReferenceError: Sh is not defined at onEdit”。如果添加 var ss = e.source; var Sh = ss.getActiveSheet(),它有效,但仅在编辑单元格时有效。如果您只选择一个单元格,但不对其进行编辑,则它不起作用。
    • @BorisBaublys 帖子已被修改。如果您希望在选择单元格时执行某些操作,请将 onEdit(e) 函数更改为 onSelectionChange(e)。
    • 是的,onSelectionChange 解决了这个问题,谢谢!如果您在答案中将 onEdit 更正为 onSelectionChange,那么我可以将他作为决定。
    • @BorisBaublys,它已被修改。如果解决了问题,请将解决方案标记为已接受。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    • 2011-06-18
    • 1970-01-01
    相关资源
    最近更新 更多