質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

4581閲覧

GoogleAppScriptでスプレッドシートの背景色カウント&シート編集をトリガーにシート全体の値を更新したい

Risney

総合スコア148

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

2クリップ

投稿2020/04/24 06:20

編集2020/05/13 02:33

目的

会社で工数を管理するツールを作成したい。
イメージ説明
サンプルのスプレッドシートの図を確認して頂ければイメージが付きやすいと思うのですが、
B列の月曜日のセルに右の業務一覧から、業務を選択してコピペをします。
そうするとH列にB列内の背景色をカウントした数が表示されます。
背景色の参照をしているのはG列の業務一覧のセルです。

前提・実現したいこと

① GoogleAppScriptでスプレッドシートの指定の列の背景色カウント
② 「工数再計算」という独自のボタンをトリガーに指定セルを更新したい
↳更新したいのはH列の関数が入っているセルです

発生している問題・エラーメッセージ

①の背景色のカウントについては実現できましたが、
②でつまずいております。

「onEdit」などを使って、
スプレッドシートを更新しても、値は更新されず、
毎回セルに関数を張りなおさないと数字が更新されない状態です。

該当のソースコード

GoogleAppScript

1function getBackgroundColor(rangeSpecification) { 2 var sheet = SpreadsheetApp.getActiveSheet(); 3 var cell = sheet.getRange(rangeSpecification); 4 return cell.getBackground(); 5} 6 7function sumWhereBackgroundColorIs(color, rangeSpecification) { 8 var sheet = SpreadsheetApp.getActiveSpreadsheet(); 9 var range = sheet.getRange(rangeSpecification); 10 var x = 0; 11 for (var i = 1; i <= range.getNumRows(); i++) { 12 for (var j = 1; j <= range.getNumColumns(); j++) { 13 var cell = range.getCell(i, j); 14 if(cell.getBackground() == color) 15 x += parseFloat(cell.getValue()); 16 } 17 } 18 return x; 19} 20 21function countCellsWithBackgroundColor(color, rangeSpecification) { 22 var sheet = SpreadsheetApp.getActiveSpreadsheet(); 23 var range = sheet.getRange(rangeSpecification); 24 var x = 0; 25 for (var i = 1; i <= range.getNumRows(); i++) { 26 for (var j = 1; j <= range.getNumColumns(); j++) { 27 var cell = range.getCell(i, j); 28 if(cell.getBackground() == color) 29 x++; 30 } 31 } 32 return x; 33} 34 35//スプレッドシートに独自メニューボタンを追加 36//https://tonari-it.com/gas-spreadsheet-addmenu-onopen/#toc3 37function onOpen(e){ 38 //メニュー配列 39 var myMenu=[ 40 {name: "工数再計算", functionName: "recalculate"}, 41 ]; 42 43 //メニューを追加 44 SpreadsheetApp.getActiveSpreadsheet().addMenu("再計算",myMenu); 45} 46 47//選択したシートを再計算させる 48function recalculate(){ 49 var activeRange = SpreadsheetApp.getActiveRange(); 50 var originalFormulas = activeRange.getFormulas(); 51 var originalValues = activeRange.getValues(); 52 53 var valuesToEraseFormula = []; 54 var valuesToRestoreFormula = []; 55 56 originalFormulas.forEach(function(outerVal, outerIdx){ 57 valuesToEraseFormula[outerIdx] = []; 58 valuesToRestoreFormula[outerIdx] = []; 59 outerVal.forEach(function(innerVal, innerIdx){ 60 if('' === innerVal){ 61 //The cell doesn't have formula 62 valuesToEraseFormula[outerIdx][innerIdx] = originalValues[outerIdx][innerIdx]; 63 valuesToRestoreFormula[outerIdx][innerIdx] = originalValues[outerIdx][innerIdx]; 64 }else{ 65 //The cell has a formula. 66 valuesToEraseFormula[outerIdx][innerIdx] = ''; 67 valuesToRestoreFormula[outerIdx][innerIdx] = originalFormulas[outerIdx][innerIdx]; 68 } 69 }) 70 }) 71 72 activeRange.setValues(valuesToEraseFormula); 73 activeRange.setValues(valuesToRestoreFormula); 74} 75 76function onInstall(e) { 77 onOpen(e); 78}

以下の関数をExcelのH11に挿入しています。
「範囲B1:B31のセルの色」と「G11の色」が一致した数が「H11」に表示されます。

Excel

1 2=countCellsWithBackgroundColor(getBackgroundColor("G11"), "B1:B31") 3 業務一覧(昼休憩)↑   ↑範囲(月曜日の列) 

このサンプルの画像の場合、
「昼休憩(青のセル)」は「範囲(月曜日の列)」内で1つです。

試したこと

・H11のセルをコピーまたは切り取りしてそのままH11にペーストしても値は更新されない
↳コピーまたは切り取り後に一度セルの値を削除してペーストすると値は更新される。
・teratail内で似ている質問があったので
onEditメソッド内に以下の文章を入れたところ、
編集したセルに最終更新日時がメモとして挿入されたのを確認しているので、

onEditのメソッドの挙動は問題ないと思います。

GoogleAppScript

1function onEdit(e){ 2 var range = e.range; 3 if(range.getColumn() == 1){ 4 range.setNote('Last modified: ' + new Date()); 5 } 6}

・以下記事を参考に関数を実行
セルの数式を取得→セルの数式削除→取得した数式をペースト
Google Sheetで選択したセルを再計算させるApps Script

参考URL

今回こちらのScriptを組む上で参考にしたURL集です。

・全体の構成
webapps.stackexchange.com
しゃのんあどべんとかれんだー 2日目 (忘年会幹事のちょっとしたお悩みをちょっと解決してくれるかもしれない GAS)

・スプレッドシートへのアクセス方法
【Qiita】Google Apps Script で Spreadsheet にアクセスする方法まとめ

・トリガー
Google公式ドキュメント
GAS入門 スプレッドシートのセル編集時のイベントトリガーまとめ
Google Spreadsheetのトリガーの「編集時」と「値の変更」の違いを検証してみた

・Tetatail内の似ている質問
【GoogleAppsScript】OnEditを特定の範囲においてのみ動作させる方法

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mkk

2020/05/08 04:09

やりたいことの全体像が分からず、回答がつきにくいのかもしれません。 背景色をカウントしたいのは分かりましたが、何の目的でカウントして何を管理したいのでしょう?   また、 > シートの値をどこか編集したのをトリガーにシート全体の値を更新したい セルの色を変えたのをトリガーではなく、値変更をトリガーにするという意味でしょうか? どんな値がどこに入っているのか分かりませんが、値の編集とはなんのことでしょうか? シート全体の値とは?シート全体に何かの計算後の値を入れる場所が用意してあるのでしょうか? 「範囲C1:C31のセルの色」と「A9の色」が一致した数が「A2」に表示されます。と記載されていますが、これ以外にあるのですか?   > =countCellsWithBackgroundColor(getBackgroundColor("A9"), "C1:C31") 業務一覧(昼休憩)↑   ↑範囲(月曜日の列)  業務一覧(昼休憩) とか 範囲(月曜日の列) と書いてありますが、これもよく分かりません。 カレンダー形式で何かを管理している?勤怠関係の何かのカウントをしようとしているのでしょうか。 私の読解力がないのかもしれませんが、目的や全体像がはっきりしていた方が回答がいただけるのではないでしょうか。
okina

2020/05/08 15:24

僕が理解力不足か、読み落としているのかもしれませんが、 値を編集したと気に、シート全体を更新するの更新というのは何を指すのでしょう? シート中の関数を全部実行したいってことですか?
Risney

2020/05/13 02:35

>mkk様 ご指摘ありがとうございます。 おっしゃる通り、質問が漠然としていました。 目的とイメージ図を追加し、内容を修正致しましたので、確認して頂ければ幸いです。
Risney

2020/05/13 02:38

>okina様 ご指摘ありがとうございます。 また、わかりにくい質問で大変申し訳ございません。 トリガーを「再計算ボタン(独自で作成したボタン)を押下」に変更しました。 そしてその再計算ボタンを押下した際に更新する箇所は、 シート全体ではなく指定のセルを指すという文章を追加いたしました。
guest

回答2

0

ベストアンサー

追記していただき、とても内容が分かりやすくなりました。

まず質問への回答からですが、説明のため長文となります。
自動計算がされない原因は、カスタム関数の引数に問題があります。

=countCellsWithBackgroundColor(getBackgroundColor("G11"), "B1:B31")

カスタム関数で再計算がかかるのは、計算対象として指定されているセルに変化があった場合です。
いやいやちゃんと "B1:B31" って指定してるよ?って思うかも知れませんが、
この書き方では "B1:B31" という文字列の扱いになります。

例えばSUM関数使う時、
=sum("B1:B31")ってやりませんよね。
=sum(B1:B31)と指定すると思います。
なので、引数を "B1:B31" ではなく B1:B31 とすることで、
B1~B31のセルに変更があった場合に自動再計算してくれます。

ただ、B1:B31 と指定すると別の問題が生まれます。
関数に渡されるデータがそのセル範囲の配列になるため、セルの背景色が取れません。
そこで変わった方法ですが、countCellsWithBackgroundColorに3つめの引数として B1:B31 を入れてはどうでしょう。
ちなみにこれは引数として渡すものの、関数内では使いません。
引数として渡しておけば、自動再計算してくれるからってだけですね。

結論

セルに入れる関数

=countCellsWithBackgroundColor(getBackgroundColor("G11"), "B1:B31", B1:B31)

 
関数の中身

function countCellsWithBackgroundColor(color, rangeSpecification, dummy) { var sheet = SpreadsheetApp.getActiveSpreadsheet(); var range = sheet.getRange(rangeSpecification); var x = 0; for (var i = 1; i <= range.getNumRows(); i++) { for (var j = 1; j <= range.getNumColumns(); j++) { var cell = range.getCell(i, j); if(cell.getBackground() == color) x++; } } return x; }

 

蛇足ですが、、、
見た感じ、G列の項目はそれぞれ違う色で、違う文字が入りそうですね。
それなら私なら、B列はドロップダウン選択にしてG列の項目を選択できるようにして
条件付き書式を使って自動でB列に色が付くようにします。
そしてH列のカウントは countif 関数を使って、文字でカウントします。
GASいらないので楽ちんですね。
今回の目的に合わないのかもしれませんが。

投稿2020/05/13 05:28

mkk

総合スコア378

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Risney

2020/05/13 06:01

わかりやすい回答と解説までありがとうございます! カスタム計算で再計算が掛からない理由をご指摘頂きましたが、 今回の修正で追加した「function recalculate()」というメソッドは セル内を一度削除して張りなおしているので、 再計算されると思っていました… おっしゃる通り、G列には他に項目が入ります。 そしてドロップダウン式にしていない理由がありまして… 例えばオレンジ色のG15の「社内業務」ですが、 G列からコピペした後に、セル内に「社内業務:なにをしたか」という形で追記し、 それを他のシートに引っ張って日報用に使用するつもりなのです。 プルダウン式にすると選択したものに追記ができないので、 また他のセルに記入して繋げるという作業が発生してしまうのです。 日報の文章に反映するというところまで今回の質問に記載してしまうと、 とんでもなく長文になってしまうと思い記載していなかったのですが…
mkk

2020/05/13 06:37

デバッグ実行で試してみましたが、再貼付の場合に recalculate関数 は呼ばれるものの、 countCellsWithBackgroundColor関数は呼ばれていませんでした。 この辺りの仕様がわかりませんが、この方法ではカスタム関数の再呼び出しができないのかもしれませんね。 なるほどなるほど、そういう意図があったのですね。 完全な蛇足でした。 カスタム関数を使うと再計算の待ちが出てくるので、出来るだけ使わない方法が良いかと思ってのことでした。
Risney

2020/05/13 07:10

ご確認ありがとうございます! はい、そこまでは記載していなくて申し訳ありませんが… そうなるとご教授頂いた方法で工数は管理して、 他のセルで詳細を書いてがっちゃんこするのが現時点での解決策かもしれません。 なので全く蛇足ではないです! 解決法の一つではあるので参考にさせて頂きます!
Risney

2020/05/18 02:13

お疲れ様です。 mkk様、先日はご回答ありがとうございました。 関数の中身は変えずに「countCellsWithBackgroundColorに3つめの引数として B1:B31を書く」 ということを実施したところ、問題なく文字が反映されるようになりました! また、トリガーがなくて問題はなさそうなので、一旦ここの質問は閉じようと思います。 質問の仕方等もご教授頂きありがとうございました! また何かあれば宜しくお願い致します。
guest

0

Excel内関数の引数に「B1:B31」を追加。

EXcel

1=countCellsWithBackgroundColor(getBackgroundColor("G11"), "B1:B31",B1:B31) 2 業務一覧(昼休憩)↑   ↑範囲(月曜日の列) 

投稿2020/05/18 02:39

Risney

総合スコア148

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問