ExcelVBA ~ セル範囲の初期化(空白セル化)と「意図せず余計な折り返し設定が突然発生・あるいは・残ってしまうバグ」に対する注意事項 ~ 特にPDFをExcel化した際にその表(セル)をどこかにコピペした場合やWordデータなどをコピペした場合など。
※まだ書きかけです。すみません。
※間違ってたらすみません。
※メモ書きなので、自分でも意味不明な箇所も多いです。ごめんなさい。
※注意01
●ユーザーフォームの代わりに、シートをフォームに見立てて使っている場合を想定しています。
その場合は、列幅が固定されていなければならないし、行高が勝手に変わると困るので。
(↑これが本来のまともな使い方。特に顧客名簿入力にユーザーフォームを理由もなく
安易に使う事は超愚かで、それを理由もなく安易に利用事例として教えるExcel講師は
超無能か本物のバカ。無駄が増えて仕方なくなるので。
もちろん特別な理由があるならいいのですが・・・。
ユーザーフォームは、ダイアログ的な、ユーザーとの双方向での
「各種の設定関連」だけに使うことが基本だと思います。
ユーザーフォームの中に、別のサブフォームを埋め込むこともできないのですから。)
●見積書や請求書などの自動印刷用のシートを作ってある場合も想定しています。
この場合も、列幅が固定されていなければならないし、行高が勝手に変わると困るので。
●「Range.Clear」はフォームがわりのシートや自動印刷のためのシートにおいては、
「セルの色も罫線も消してしまう」ので「使えない」という想定です。
なので、各種書式設定を個別に初期状態に戻さないといけません。
●「Range.ClearContents」を使った場合のみ、そのあとに使う想定です。
※注意02
↓本記事を書く原因となった、Excelの「仕様という名のバグ」の図↓
↑こんな不具合が、「自動印刷したい」「でも行高は1行分のまま固定じゃないと困る」「見積書や請求書」に出てきたらどう思いますか?「うざい!!」「超超超迷惑!!!」以外の何物でもありません。
本記事は、「印刷をしたいシート」で、
上図のような不具合が出るのを回避する目的で書いていますが、
なかでも、見積書や請求書の作成などで、
『 文字列型のセルの値が「2単語程度を含む短いコメントのみ」で、「本来、その文字列の中間に無駄な改行があってはいけない」』、
というケースを想定しています。
また、https://happy-tenshoku.com/post-9110/#i-2 や、
https://blog.goo.ne.jp/edo-toddler/e/d3b0b0743fc1178ac487809c23441672
のような形で解決でき、プログラミングが不要なケースもあります。
その場合は、本記事は不要です。
あるいは、上記のような操作をプログラム化するのもいいと思います。
『 Activesheet.Range("A1:Z1000").RowHeight = 18.75 』、や、
『 Activesheet.Cells.RowHeight = 18.75 』、
みたいなプログラムでOKのようです。(※行高の数値は初期値でもなんでもOK。)
それだけで、
「もし値に、意図しない余計な改行、あるいは、意図した正式な改行が含まれていたとしても」、
勝手に「折り返しON」にならなくなります。
(手動でのドラッグでの行高変更をした場合も同じ結果になります。)
ただ、この場合、「Range.EntireRow.AutoFit」や行番号境界上でのダブルクリックをしないと、「折り返し」設定をOFFにしても「F2+Enter」で行高が自動的に広がりません。
それはそれで困るので、ここでは、それ以外のプログラム方法を取ります。
不具合の元凶の「見えてきにくい余計な改行」を消して、折り返し設定などを解除します。
※参考
ちなみにですが、少し整理しますと、
「余計な改行が値の中間や末尾などに含まれている場合」、
(a)行番号の境界線上で、手動でドラッグで行高を変更するか、
(b)行番号の上で右クリックして、(高さの数値を変えなくてもいいので)OKだけするか、
(c)VBAで『 Activesheet.Cells.RowHeight = 18.75 』などと明示的に行高を設定すると、
「F2+Enter」の操作などで、行高が2行分、3行分と、広がって自動フィットすることはなくなります。
ただし、例えば意図せず「値の一部しか表示されない」という状況も生まれてきます。
(※(a)~(c)を行った状態で折り返し設定をOFFにすると、
値に値に改行が含まれていない場合・かつ・列幅が短いだけであってそれで2行表示されるようなセルは、1行になって列の境界をはみ出して、値のすべてが表示されます。
値に改行が1つでも含まれている場合は、「F2+Enter」の操作には反応しないままです。行高が2行分、3行分と、自動で広がって自動フィットすることはなくなります。ただし、「値の一部しか表示されません」ので、データを閲覧し忘れる・見失う可能性があります。)
その「無反応状態」を解除するには、
(d)行番号の境界線上でダブルクリックするか、
(e)VBAで『 Range.EntireRow.AutoFit 』をするか、です。
そうすると、「いったん折り返し設定をOFFにしたとしても」、(再度勝手に折り返し設定がONになり)「F2+Enter」の操作に再度反応するようになり、行高が2行分、3行分と、自動的に広がって自動フィットする状態に戻ります。
===============
以下本文です。
(※今回は「罫線やセルの色までは消したくない場合」を想定していますので、
それらも全部消してしまう「Range.Clear」メソッドは「使えない」、
という前提です。)
セル範囲を空白にする際に、VBAですとClearContentsなどを使うことが多いですが、「折り返し表示」のセル設定が勝手に設定されてしまう場合がありますので、その設定も解除せねばならないケースがあります。
多くは、コピペしたセル範囲のどこかのセルで、「余計な改行」が値の中に含まれてしまっている場合です。
特に文字列の中間ではなくて末尾に余計な改行が入っている場合です。非
常に分かりにくいのでそれが原因と意外と気づけません。
その場合、F2+Enterの操作などをすると、行の高さがその値の長さに伴って、意図せず、異常に高くなってしまいます。
これはExcelのバグです。
マイクロソフトや「Excel盲信・大好き」のバカユーザーはアホなので「仕様です」と言うでしょうけど・・・。
実際はどう見てもバグでして、本来なら、
セルの値が文字列データの場合、その値の中間や末尾に改行が含まれている場合は、
『セルのコピペ先でもどこでも、何だろうが、必ず「折り返し表示」設定が自動的にONなって、見た目的に2行分3行分に変化してわかりやすくするべきなのに』、
実際には、改行が末尾などに含まれているにもかかわらず、「折り返し表示」がOFFになってしまった「まま」のケースがあるのです。しかも、行高も初期設定どおり「18.75」の「まま」で。(特に値の末尾に余計な改行があるとそれが隠れているので本当に分かりづらいです。)
つまり、わざわざF2+Enterなどの操作をしないと、「18.75」が解除された2行分3行分、の表示にならないのです。
つまり、折り返し表示になるはずがそうならず、「気づけない・気づきにくい」わけです。
これはExcelの修正をサボったバグだと思います。20年以上、放置されています。
そして、もっと悪いことに、このバグをExcelのクソレジェンドどもが「ひとっこと」も、説明しません。PCが小数で計算間違いする、というのと同じように、重要なことなのに説明しません。
↓
余計な改行が入っていたら、いついかなる場合も、上図の⑤のように、行の高さが広がって「折り返しON」になればいいのですが、①の状態のように正常な状態に見えてしまうため、「まさか、余計な改行が原因」、とはなかなか気づけません。
更に悪いことに、①の状態のセルを「他のExcelファイルに」「コピペ・その他の操作や、VBAでの転記プログラム実行をしたあとなど」で「しか」、その問題が顕在化しないことも少なくありません。(※コピペの場合、それだけでは顕在化しませんが、コピペ先でセルをダブルクリックしたり、「F2+Enter」したりすると、不具合が顕在化します。)
他のユーザーが、コピー元ファイルに「知らないうちに」「勝手に」改行を入れて、あとで行高を直した場合も同じ不具合が起こります。
コピペ元のファイルは見た目が正常で行の高さもデフォのままだけれども、例えばVBA転記先では、勝手に折り返し設定になって、行の高さが2行分、3行分、になってしまう。
コピペ元のファイルは見た目が正常なだけに、余計に気付きにくいです。
1行分で済むにしろ、2行分・3行分になるにしろ、どこかの段階で突然「勝手にそうなる(=1行分の行高が2行分、3行分になってしまう)」ので、特に、「レイアウトが絶対に崩れてはいけない利用シーン」の場合は、マジで、本当に困るわけです。そして、原因が非常にわかりづらい。
余計な改行だけなら、何をやっても勝手に折り返しONにならず、ちゃんとOFFのまま、というのでもいいのですが・・・。
というか、本来なら、ユーザーはもともと「折り返し設定ON」に「してない」わけなんだから、「折り返しいやだ」と言ってるわけなんだから、なら、いついかなる場合でも、余計な改行が入っていても、「勝手に折り返しON」になんかなっちゃいかんでしょ?
これは20年放置されているバグなのに、Excelクソレジェンドどもはまったくもって、全然教えやがりません。
おかしな日本語使いたくなるくらい腹立ちます。
「お前ら20年以上も講師やってやがって知らないはずないんだから最初に言っとけや!自分の本にくらい書けや!」と。
本来なら全ての市販書籍に書かれてないといけないほどの、20年も直ってない超有名らしきバグ/FAQトラブルなのに、どの市販書籍にも全然書いてありません。
なお、このバグは、F2+Enter操作以外には、VBAでの転記作業ミスなどでも発生するかもしれません。
なので、そのようなトラブルを回避するために、ClearContentsのほかに、以下の処理もしなければならないケースがあります。
(01)すべてのセルの値の「余計な改行」を全部消す。
(02)「折り返し表示」のセルを全部OFFに戻す。 など。
これは、特に、どこかのExcelシートをそのままコピペしたような場合に起こります。
特に気づきにくいのは、PDFをExcelファイルに変換し、そのExelファイルの表の内容をコピペした時などです。PDFには、『内部的なテキストには「余計な見えない改行」が入っているのに・しかし「PDF上には見えてこない」場合があります。
そして悪いことにExcelファイルに変換した際、その直後は行の高さは変わっていない状態で、けれども、他のファイルに任意のセル範囲をコピペするなどをすると、そのコピペ先のExcelファイルの方で異常が顕在化する』、という場合がちょくちょくあります。PDFを作るソフト自体もメチャクチャな場合があり、その場合、値がメチャクチャに勝手に書き変えられてしまい(PDFの見た目だけ正常で、内部的にはテキスト部分がメチャメチャに破壊されている)、それが、Excel変換時にそのまま顕在化してしまうことがあります。
PDF以外や、Excel自体にも似たケースがあるかもしれないので、注意が必要です。
ところで、「余計な改行が入る」という場合は、つまり、
「セルの値が文字列型の値である」、ということですが、
その場合、
「(01)すべてのセルの値の「余計な改行」を全部消す。」という操作をすると、
そのプログラムの内容が簡易的な場合は、例えば「長めの文」で、
「本来は本当に改行したい箇所までが、全部1行につながってしまう」、
ということが起こります。
本記事は、そういう長い文章的なものは、今回は面倒くさいので考えません。
見積などで、「2単語程度を含む短いコメントだけ」で、「本来、その文字列の中間に無駄な改行があってはいけない」というケースを想定しています。
その場合、以降に挙げた「SyosikiClear01()」プロシージャような感じのコードになります。
値は残して、余計な改行と書式だけクリアしたい、というようなケースです。
呼び出し方法としましては、
Call SyosikiClear01(Activesheet.Range("A1:g100")) とかはもちろんできますし、
Call SyosikiClear01(Worksheets("シート名")Range("A1,C3:D3,F5;G10")) のように、
他のシートの離れた複数のセル範囲のクリア+解除ができます。
なお、「o_Range.Replace What:=vbLf, Replacement:="", LookAt:=xlPart, MatchCase:=False」
と書いたように、余計な改行の削除を「置換」操作によって行うほかに、
「For Each」で「指定したセル範囲のセルを全部ループして1個1個設定し直す」ということもできますが、それだとちょっと「遅くなる」ので、ここでは「For Each」はあえて使っていません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
' ' '######################################################################## 'セルの値は残し、余計な改行と意図しない邪魔な書式を解除する ' '呼び出し例 'Call SyosikiClear01(Activesheet.Range("A1,C3:D3,F5;G10")) ' ↑このように、複数の離れたセル範囲にも使えます。 '値もクリアしてしまいたい場合は、ClearContentsの命令も。 '「Range.Clear」はセルの色も罫線も消えてしまうので使えないという想定。 '「Range.ClearContents」を使った場合のみ、そのあとに使う想定。 '######################################################################## Sub SyosikiClear01(o_Range As Range) ' o_Range.Replace What:=vbLf, Replacement:="", LookAt:=xlPart, MatchCase:=False ' '↑指定したセル範囲のセルの、その値に含まれる余計な改行を「置換」操作で全部消す。 ' '↑「For Each」のループは、遅くなるのでひとまずは使わない。 ' '↑ ※基本、コメントアウトして、この関数の外でやるほうがいいかも? o_Range.WrapText = False '↑同セル範囲の、折り返し表示のALL解除。 o_Range.MergeCells = False '↑セル結合も解除(意図せず結合セルがコピペされてしまった場合を想定して) o_Range.ShrinkToFit = False '↑「縮小して表示」の設定も解除。 o_Range.EntireRow.AutoFit '↑行をオートフィットさせる。行の境界をダブルクリックした操作と同じ。 '↑これで、行高の「固定」が「完全に」解除される。 '↑ユーザーフォーム代わりの画面などで、2行分を固定したい行には '↑やってはいけないので、その場合はコメントアウトするか、 '↑別の関数を作るか、既定値の引数やスイッチを作って分岐させる、などをする。 ' o_Range.EntireColumn.AutoFit ' '↑列をオートフィットさせる。列の境界をダブルクリックした操作と同じ。 ' '↑これで、列幅の「固定」が解除される。 ' '↑しかし、基本的には使ってはいけない。コメントアウト。 ' '↑理由は、ユーザーフォーム代わりの画面などで、「常に列幅を固定したい列のほうが多い」から。 ' '↑これやると、列幅が全部初期値の幅に戻ってしまう。 ' '↑(見積書や請求書など)列幅が変わってしまうと困るシートの「自動印刷」でも困ることになる。 ' '↑どうしても使いたいなら、 ' '↑別の関数を作るか、スイッチを作って分岐させる、などをする。 ' 'そのほか、必要に応じて以下のことも。 ' '(マクロの記録で記録された他の書式のことや値のクリアなど。) ' ' o_Range.ClearContents ' o_Range.HorizontalAlignment = xlGeneral ' o_Range.VerticalAlignment = xlCenter ' o_Range.Orientation = 0 ' o_Range.AddIndent = False ' o_Range.IndentLevel = 0 ' o_Range.ReadingOrder = xlContext End Sub ' ' |
なお、セルの値も(ムダな改行もろとも)消してしまいたい、という場合はこちら。
↓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
' ' '############################################################### 'セルの値も意図しない邪魔な書式も消す。 '当然余計な改行もセルの値の削除で消える。 ' '呼び出し例 'Call CellAllClear01(Activesheet.Range("A1,C3:D3,F5;G10")) ' ↑このように、複数の離れたセル範囲にも使えます。 '############################################################### Sub CellAllClear01(o_Range As Range) o_Range.ClearContents '↑指定したセル範囲のセルの、無駄な改行もろとも、値と数式を消す。 o_Range.WrapText = False '↑同セル範囲の、折り返し表示のALL解除。 o_Range.MergeCells = False '↑セル結合も解除(意図せず結合セルがコピペされてしまった場合を想定して) o_Range.ShrinkToFit = False '↑「縮小して表示」の設定も解除。 ' 'そのほか、必要に応じて以下のことも。 ' '(マクロの記録で記録された他の書式のこと。) ' ' o_Range.HorizontalAlignment = xlGeneral ' o_Range.VerticalAlignment = xlCenter ' o_Range.Orientation = 0 ' o_Range.AddIndent = False ' o_Range.IndentLevel = 0 ' o_Range.ReadingOrder = xlContext End Sub ' ' |
なお、引数を作成して、どの設定をON・OFFするかをそれで指定する形にしてもよいと思います。
また、余計な改行を消すコードは、自作関数に含めない形のほうがのちのちは良いかも?しれません。
あるいは、あえて「含めるモノ」と「含めないモノ」の「2つを作っておいても」いいとも思います。