Google Apps 脚本 - 表格 - 条件格式 - X = 突出显示

Google Apps Script - Sheets - Conditional Formatting - X = highlight

我有一个 sheet 有超过 100,000 个单元格(很快将超过 300,000 个单元格)用作甘特图。每个单元格都有一个 IF 公式,如果相应列的 header(日期)在行的开始日期和结束日期之间,则 returns 字母 X。

但是显着减慢 sheet 的是它背后的条件格式。条件格式表示如果单元格的值为 X,则将单元格的背景颜色和字体颜色更改为绿色。如果没有 X,背景颜色应该是白色。据我所知,由于条件格式会在您对 sheet 进行任何编辑时重新计算,因此性能非常差。所以我的想法是删除条件格式并将其添加为脚本,并带有一个菜单按钮,我可以随时单击它 运行,而不是每次进行条件格式 运行ning对 sheet.

的编辑

这是我得到的脚本,它不起作用。我已经尝试了几十种变体,但找不到有用的东西 - 有时我把它变成 运行 没有错误,有时有错误。是不是我的语境哪里不对?

function formatting() {

  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet 1");
  var range = ss.getRange("A1:A100");
  var cellValue = range.getValues();
  if (cellValue === 'X') {
    ss.range.setBackgroundColor('#000000'); }
  else {
    cellValue.setBackgroundColor('#ffffff'); }
}
  • cellValues是一个二维数组;必须检查每个单元格是否为 X。 运行 它循环获取被测元素的 (x, y)。
  • ss.rangecellValue 都不能用来设置背景。必须 ss.getRange(x, y).setBackground... 使用 (x, y) 坐标指定 Xed 单元格。

还没有测试过,但这应该有效:

function formatting() {
  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet 1");
  var range = ss.getRange("A1:A100");
  for (var x = 0; x < range.length; x++) {
    for (var y = 0; x < range[0].length; y++) {
      if (cellValue == 'X') {
        ss.getRange(x, y).setBackgroundColor('#000000');
      } else {
        ss.getRange(x, y).setBackgroundColor('#ffffff');
      }
    }
  }
}

虽然这可能是您要找的东西,但速度方面存在问题。另一种方法是在需要时 add/remove 规则。如果经常手动重新创建太多,可以使用 ConditionalFormatRule 以编程方式完成。

这是使用批处理函数的方法 Range.setBackgrounds()。此函数采用二维值数组作为参数,允许您在单个 API 调用中为一个范围设置所有单元格背景。

还要注意函数 Range.getValues() returns 一个二维值数组。要检查每个单独的单元格值,您需要遍历数组。

由于您将二维数组同时作为输入和输出进行处理,因此构建背景值输出数组的逻辑反映了您需要用于检查当前单元格值的逻辑。因此,您可以在遍历单元格值时构建背景值的二维数组。

function setCellBackgrounds() {
  // The name of the sheet to process.
  var sheetName = "Sheet1";
  // The range of cells to inspect.
  var range = "A1:Z100";

  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  var range = sheet.getRange(range);
  var values = range.getValues();
  var colors = [];
  for (var x = 0; x < values.length; x++) {
    colors[x] = [];
    for (var y = 0; y < values[x].length; y++) {
       if (values[x][y] == 'X') {
         colors[x][y] = '#999999';
       } else {
         colors[x][y] = '#ffffff';
       }
    }
  }
  range.setBackgrounds(colors);
}

使用批处理函数,而不是重复调用非批处理版本,是a documented Apps Script best practice

如前所述,, you are not referencing the check correctly. However, using setBackground is not really amenable to even 100 cells, much less so 1000 or 300,000. You will find it a requirement to use the batch method Range#setBackgrounds() 包含您希望应用的背景颜色的“二维”数组。

您可以进一步减少对大量 API 的需求,方法是使用有关甘特图电子表格的构建和操作的特定于应用程序的详细信息来减少您修改的范围。也许 X 只能在刚刚编辑过的单元格中出现或消失,或者它们只能从左到右或从上到下等填充。

此函数假定最坏情况 - 每次调用它时,您都需要重新计算背景颜色。

function greenify() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("Gantt");
  const HAS_X = "green", NO_X = null;
  const dr = sheet.getDataRange();
  const colors = dr.getBackgrounds();
  const VALUES = dr.getValues();

  // Inspect the value array and modify the corresponding index in colors.
  for (var r = 0, rows = VALUES.length; r < rows; ++r)
    for (var c = 0, cols = VALUES[0].length; c < cols; ++c)
      colors[r][c] = (VALUES[r][c] === "X") ? HAS_X : NO_X;

  // Write the output.
  dr.setBackgrounds(colors);
}

如果只考虑刚修改的单元格,我建议使用"simple trigger."