|
■No82709 (HARE さん) に返信 > 5〜10が特にわかりません > お手数掛けて申し訳ないです。
連続長文になりましたが、最後の 8〜10 について。
=============== 【Range オブジェクト】 ---------------
>> (8) 得られたシートに対し、Range プロパティでセルを指定してデータを書き込めますか?
既に御存知と思いますが、Worksheet オブジェクトでは、 個々のセルやセル範囲を Range オブジェクトとして扱います。
たとえば、 todaySheet.Cells(1, 2).Value = "本日の記録" とか、 todaySheet.Range("A2").Value = "本日の記録" といった具合です。 Cells プロパティや Range プロパティで、Range オブジェクトを取得できます。
Range オブジェクトの扱いについて、注意点が二つあります。
1つ目:Value プロパティについて
たとえば、 todaySheet.Range("A2").Value = "本日の記録" といったコードを、 todaySheet.Range("A2") = "本日の記録" と記述しないようにしましょう。 Range プロパティは ReadOnly なので、文字列などを代入することはできません。 読み書きの際には、Value プロパティを通じて行うようにします。
2つ目:オブジェクト解放について
Excel.Range オブジェクトは、後始末を忘れられがちです。 先の「ReleaseComObject」を意識した場合、Range プロパティ利用時は todaySheet.Range("A2").Value = "本日の記録" ではなく、 Dim oRange As Excel.Range = todaySheet.Range("A2") oRange.Value = "本日の記録" System.Runtime.InteropServices.Marshal.ReleaseComObject(oRange) と書いた方が望ましいです。
特に注意するのは、Cells プロパティの場合で、 todaySheet.Cells(1, 2).Value = "本日の記録" というコードを、解放処理も意識して記述した場合、 Dim oRange1 As Excel.Range = todaySheet.Cells Dim oRange2 As Excel.Range = DirectCast(oRange1(1, 2), Excel.Range) oRange2.Value = "本日の記録" System.Runtime.InteropServices.Marshal.ReleaseComObject(oRange2) System.Runtime.InteropServices.Marshal.ReleaseComObject(oRange1) のように書く事になります。
注意点に先に触れたところで、Range オブジェクトの基本的な使い方について:
元のコードでは、一つ一つのセルに値をセットしていたようですが、たとえば newWorksheet.Range("B2:E3").Value = "TEST" のようにすれば、2 行 4 列の範囲(計 8 セル)すべてに 「TEST」という文字列を書き込むこともできます。
逆に、 Dim obj As Object = Sheet1.Range("B2:E3").Value のように、複数セル範囲で取得した場合、戻り値は 2 次元配列になります。 (単一セルが相手の場合は、配列にはなりません)
これを利用して、複数セルの範囲に対して、「.Value = 配列」で代入してやれば、 複数のセル範囲に、まとめて異なる値をセットすることも出来ます。
VB と Excel の間の通信は比較的低速なので、読み書き回数が多くて 処理時間が何十秒もかかるような場合は、この方法で一括書き込みを 行うことで、処理速度を大幅に短縮できます。
なお、値ではなく数式を扱う場合には、Value プロパティの代わりに Formula プロパティや FormulaR1C1 プロパティを使います。
Range オブジェクトにはこの他、セル書式を扱うための NumberFormat プロパティや 右寄せ中央揃えなどを扱う、HorizontalAlignment / VerticalAlignment プロパティ、 セルを結合あるいは結合解除するための Merge / UnMerge メソッドなどがありますが、 説明しきれないのでとりあえずここまで。
=============== 【保存と後始末】 ---------------
既に元のコードで > Book.SaveAs(FilePath) と書かれているので、ある程度御存知かと思いますが、次は >> (9) ワークブックの SaveAs メソッドを用いて、"201701.xlsx" というファイル名に上書き保存できますか? についてです。
SaveAs を使うと、新しいファイル名で保存できます。 新規ブックのように、ファイル名が未設定の場合もこれを使います。
一方、現在開いているファイルへの上書き保存の場合は、 SaveAs の代わりに、引数無しの Save メソッドを使います。 既存のファイルを Workbooks.Open して上書き編集するだけなら、 Book.SaveAs ではなく Book.Save を使うだけで良いでしょう。
あるいは、SaveAs を上書き保存のために使うことも出来ますが、 その場合、上書き確認のダイアログが表示されることになります。 このダイアログで No や Cancel が選択された場合、 SaveAs メソッドは失敗して実行時エラーとなります。
この確認ダイアログを抑制する場合には、あらかじめ、 Application オブジェクトの DisplayAlerts プロパティを False にしておきます。たとえば Dim bAlerts As Boolean = ExcelApp.DisplayAlerts ExcelApp.DisplayAlerts = False '警告を抑制 Book.SaveAs(FilePath) ExcelApp.DisplayAlerts = bAlerts '元に戻す といった感じです。
また、未保存状態でワークブックを閉じようとすると、 保存確認のダイアログが表示されますが、これも DisplayAlerts で抑制できます。
あるいは、DisplayAlerts は True のままであっても、 Book.Saved = True のようにすれば、そのブックはまだ変更されていないことになるため、 ユーザーがワークブックを閉じる際の保存確認が表示されなくなります。
ワークブックをユーザーに閉じさせるのではなく、プログラムから閉じるのならば、 Book.Close() とします。あるいは編集状態を破棄して閉じるために「Book.Close(False)」としたり、 保存して閉じるために「Book.Close(True, FilePath)」とすることもできます。
後は最後に、 >> (10) 処理完了後、Close メソッドでワークブックを閉じ、Quit メソッドで Exxel 本体を終了させられますか? ということで、 ExcelApp.Quit() を呼び出せば OKです。 Excel を閉じずに開きっぱなしにするのなら、Quit はしなくても構いませんが。
全てが終わったら、使い終わった Excel オブジェクトの変数を適宜、ReleaseComObject してお仕舞いです。
実際には For や For Each の場合も、適宜解放が必要だったりしますので、 もっと早い段階で解放すべきケースもありますが……慣れないと難しいところなので、 初心者を脱するまでは、解放処理については後で考えた方が良いかもしれません。
|