Excel帳票のオートメーションを高速化するために、VB.netとApache NPOI 2.5.1でプログラムを書いてみました。
セルに斜め罫線を引く方法をネットで調べましたが、VB.netの文法に対応していない複雑な方法によるサンプルプログラムが公開されているだけで、「実現は不可能」という結論でした。
ところが、私が挑戦してみたところ、簡単にできました。
<ソースリスト>
'Excel97Book (.xls) 斜め罫線を引く サンプル
'Copyright (c) 2020 oka-da.com
'NPOI Ver.2.5.1.0 を使用
Imports NPOI.HSSF.UserModel
Imports NPOI.SS.UserModel
Imports NPOI.SS.Util
'(HSSF EXCEL97用 HSSFCell
'(XSSF EXCEL2007用 XSSFCell
Class MainWindow
Private Property XlsFileName As String = "C:\Users\o\Desktop\x1.xls"
Private Property NPOI_book As IWorkbook = Nothing
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Open_xlsFile(NPOI_book, XlsFileName)
Dim sheet_A1 As ISheet = NPOI_book.GetSheet("Sheet1")
'Excel VBA rangeのシミュレート
Dim rg As New POI_Range(NPOI_book, sheet_A1)
'セル座標をA1に設定する
rg.SetAddr("A1")
rg.draw斜罫線(BorderDiagonal.Both, BorderStyle.Thick, IndexedColors.Tan)
'再計算を行う ■これをPOI側でやっておかないと非常に危険、Excel側でどんなに再計算を行っても計算されないことがある
NPOI_book.GetCreationHelper().CreateFormulaEvaluator().EvaluateAll()
SaveBook(XlsFileName)
'Excelを閉じる
NPOI_book.Close()
NPOI_book = Nothing
'Excelファイルを閲覧
Dim p As System.Diagnostics.Process = System.Diagnostics.Process.Start(XlsFileName)
Me.Close()
End Sub
'ExcelファイルをNPOIで開く
Private Sub Open_xlsFile(ByRef book As IWorkbook, ByVal fs As String)
Try
book = WorkbookFactory.Create(fs)
Catch ex As Exception
End Try
End Sub
'Excelファイルを保存する
Private Sub SaveBook(ByVal filePath As String)
Using fs As New System.IO.FileStream(filePath, IO.FileMode.Create)
NPOI_book.Write(fs)
End Using
End Sub
Public Class NpoiLib
Public Shared Property xls列名 As String() = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
"W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV", "AW"}
End Class
'POIでrangeをシミュレートする
Public Class POI_Range
Private Property _x0 As Integer 'セルを示す座標X (列)
Private Property _y0 As Integer 'セルを示す座標Y (行)
Private Property NPOI_book As IWorkbook
Private Property _sheet As ISheet
Public Sub New(ByRef b As IWorkbook, ByRef s As ISheet)
NPOI_book = b
_sheet = s
End Sub
'罫線を引く
Public Sub draw斜罫線(ByVal 斜め形状 As NPOI.SS.UserModel.BorderDiagonal,
ByVal thickness As NPOI.SS.UserModel.BorderStyle,
ByVal color1 As NPOI.SS.UserModel.IndexedColors)
Dim style = NPOI_book.CreateCellStyle()
style.BorderDiagonalLineStyle = thickness
style.BorderDiagonal = 斜め形状
style.BorderDiagonalColor = color1.Index
setStyle(style)
End Sub
'セル書式を設定する
Public Sub setStyle(ByVal style As ICellStyle)
Dim row = If(_sheet.GetRow(_y0 - 1), _sheet.CreateRow(_y0 - 1))
Dim cell1 = If(row.GetCell(_x0 - 1), row.CreateCell(_x0 - 1))
cell1.CellStyle = style
End Sub
'定義されたセル名,またはR1C1形式によりrangeの指す座標を設定する
Public Sub SetAddr(ByVal cs As String)
Dim add1 As CellRangeAddress
Dim ina1 As IName = NPOI_book.GetName(cs)
If ina1 IsNot Nothing Then
add1 = CellRangeAddress.ValueOf(ina1.RefersToFormula())
_x0 = add1.FirstColumn + 1
_y0 = add1.FirstRow + 1
Exit Sub
End If
Dim s As String = cs
Dim c As Char
Dim i, j As Integer
For i = 0 To cs.Length - 1
c = cs.Substring(i, 1)
j = Convert.ToInt32(c) 'ASCIIコード
If j < &H41 Then
'csから数字以降の文字列をIntegerに変換、_y0に代入
If Integer.TryParse(cs.Substring(i), _y0) Then
Else
_y0 = 0
End If
Exit For
End If
Next
'CSのアルファベット部分を配列要素内からクエリー
If i > 0 Then
s = cs.Substring(0, i)
For i = 0 To NpoiLib.xls列名.Length - 1
If s = NpoiLib.xls列名(i) Then
_x0 = i + 1
GoTo L100
End If
Next
End If
_x0 = 0
L100:
If _x0 < 1 Or _y0 < 1 Then Exit Sub
End Sub
End Class
End Class
<実行結果>
従来、Excelオートメーションで行っていた処理を全てNPOIに置換しようと試みましたが、不可能なこともあります。
(1)行削除が用意されておらず、行をシフトする方法で代用すると書式が崩れる。
(2)セルの書式設定は一言で表現すると、かなり複雑。特定の行・列全体を書式も含めてコピー・貼り付けするのは避けた方が無難。
サンプルプログラムでは、Excel VBAのrangeクラスをシミュレートしています。まだ開発途中なので一部を公開しただけですが、Offsetによる参照の移動を実装すると、プログラムが楽になります。
オカダ・システムエンジニアリング研究所