单元格格式仅适用于可见(未过滤)行

Posted

技术标签:

【中文标题】单元格格式仅适用于可见(未过滤)行【英文标题】:Cells formatting works only on visible (not filtered) rows 【发布时间】:2015-02-19 11:44:43 【问题描述】:

我正在使用 GDrive 电子表格和 Google 应用脚本。我需要更改所有单元格的格式和背景颜色,并且需要以编程方式进行。以下代码效果很好:

ss.getRange(1, 1, ss.getLastRow(), ss.getLastColumn()).setNumberFormat("@STRING@").setBackground("cyan");

唯一的问题是它适用于可见的行/列 - 即,如果您根据特定列值过滤工作表,则上面的代码将仅适用于当前显示的行。

例如,我有以下电子表格

我继续在第二列添加过滤器:

如您所见,我选择在 zxc 值上过滤第二列。现在我需要使用谷歌应用脚​​本将电子表格的单元格格式化为青色背景。代码如下:

function testFormat()
  var id = "theIdOfMySpreadsheet";
  var sheet = SpreadsheetApp.openById(id);
  var ss = sheet.getSheets()[0];
  ss.getRange(2, 1, ss.getLastRow() - 1, ss.getLastColumn()).setBackground("cyan");

这是电子表格上的结果:

一切似乎都很好。但是看看如果我删除过滤器会发生什么:

5 行中只有 2 行具有正确的背景颜色,即使我已将其设置在 整个 范围内。我已经测试了返回范围的长度,它可以正常工作,因为它返回 5 行和 3 列。

你们中有人遇到过这个问题吗?如何强制它更改过滤出的行的背景?

【问题讨论】:

【参考方案1】:

如果有相当于 Data - Turn Off Filter 的 Apps Script 方法,那么您可以清除隐藏的行。但目前来看,这种可能性是不存在的。

一个选项是在应用任何过滤器之前首先突出显示整个范围以及所有数据。当范围被过滤到一个较小的列表时,颜色格式只会出现在较小的列表中。放回去的时候会返回整个列表。

您首先过滤,然后应用背景。尝试先应用背景颜色。

如果您不能这样做,那么您可以使用可安装的 onChange 触发器来监控 OTHER 事件类型。 OTHER 事件类型由数据过滤器和其他事件触发。

但您需要知道过滤器前后的状态。所以你需要以某种方式记录原始状态,然后检查是否有变化,比如显示的行数。

【讨论】:

我需要的是在继续使用气体脚本之前以编程方式取消工作表过滤器,我需要通过代码来完成,因为我无法手动删除过滤器。无论如何,我认为这是不可能的,不幸的是,当前类 api 没有提供任何允许这样做的功能:( 无论如何感谢您的建议!【参考方案2】:

如果您想要所有行的背景颜色,为什么不先更改颜色然后应用过滤器? (注意:我的声誉不允许我发表评论,因此我将其发布为答案)

【讨论】:

【参考方案3】:

这是我为解决这个问题而编写的一个函数。 它检查工作表上的过滤器并停用列上存在的任何过滤条件,在指定范围内设置背景颜色,然后重新激活过滤条件。

// Globals
var SS = SpreadsheetApp.getActive();
var SH = SS.getSheetByName('Data');

var COLOR = 
  draft: '#d9ead3', // light green
  published: '#93c47d' // dark green
;

function colorBg_(sheet, a1Notations, color) 
  // color must be null to reset
  // calling the .setBackground method with undefined does nothing 
  // and with no argument throws an error
  color = color? color: null;

  // calling .getRangeList with wrapping a1Notation strings in an array throws an error
  a1Notations = !Array.isArray(a1Notations)? [a1Notations]: a1Notations;

  const filter = sheet.getFilter(); // returns null if there is no filter present (does not throw error)
  if (!filter)  // no filter, no problems

    // this works fine even with a single range in the list
    sheet.getRangeList(a1Notations).setBackground(COLOR.published);

   else  // temporary remove filters so color will be applied to all visible rows

    const headerColumns = filter.getRange().getValues()[0];

    const filterCriterias = headerColumns.reduce(function(criterias, column, index) 
      const columnPosition = index + 1;
      const criteria = filter.getColumnFilterCriteria(columnPosition);
      if (criteria) 
        criterias[columnPosition] = criteria;
      
      return criterias;
    , );

    const filteredColumnPositions = Object.keys(filterCriterias);

    filteredColumnPositions.forEach(function(columnPosition) 
    // const columnPosition = parseInt(key, 10); // this step is unnecessary, 
    // columnPosition can be a number or a string
      filter.removeColumnFilterCriteria(columnPosition);
    );

    // now that filters are inactive and all rows are visible, set the color
    sheet.getRangeList(a1Notations).setBackground(color);

    // replace filter criteria on columns
    filteredColumnPositions.forEach(function(columnPosition) 
      filter.setColumnFilterCriteria(columnPosition, filterCriterias[columnPosition]);
    );
  


function colorDefault (color) 
  const a1Notation = 'E2:F';
  colorBg_(SH, a1Notation) // colorBg_ function will default color argument to null


function colorPublished () 
  var a1Notations = [
    'E3:F6',
    'F8',
    'E10'
  ];
  colorBg_(SH, a1Notations, COLOR.published);

【讨论】:

【参考方案4】:
//Enter your sheet name in getSheetByName function.

function clearFilter() 
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssId = ss.getId();
var sheetId = ss.getSheetByName("SheetName");
var filter =sheetId.getFilter();

for(var i=1;i<=column.length;i++)//colunm.length means number of columns.

    filter.removeColumnFilterCriteria(i);


【讨论】:

虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的回答添加解释并说明适用的限制和假设。

以上是关于单元格格式仅适用于可见(未过滤)行的主要内容,如果未能解决你的问题,请参考以下文章

TableView 的屏幕截图不仅适用于可见单元格,而且适用于所有可用单元格

将 DGV 中的单元格类型从 ComboBox 更改为 TextBox 仅适用于第 0 行?

如何仅自动填充可见单元格?

VBA代码将一个单元格的条件格式复制到未指定范围的单元格

在 VBA 过滤表中选择第一 10 行可见单元格

Excel VBA 自动过滤器然后更改字段值并填写错误处理空白单元格的可能性