先日に引き続きopenpyxlで遊んでいた時に調べた内容のメモです。
・複数セルを選択した状態での罫線引き
◇公式ドキュメントはここ
openpyxl - A Python library to read/write Excel 2010 xlsx/xlsm files — openpyxl 2.6.2 documentation
◇公式ソースコードはこっち
Bitbucket
複数セルを選択した状態での罫線引き
最終的にこういう線を引きたかったんです。 罫線の範囲が入力によって変化するアプリ(おもちゃ)を作っていたので、罫線範囲が不定な状況で自動的に罫線引きたいなと。
エクセルを通常のGUIで操作する時は、5列選択して左右は実線、列間は点線を引いて5列分の書式をコピペ、行でも同じことをやる、って感じで操作すると思います。
ただ調べても範囲指定したセル群の列間/行間の罫線引きが無さそうだったので、1行(1列)の範囲で指定して線を引きました。
※公式ドキュメントからのコピペと、日曜プログラマーのコードです。
まずは公式にあるマージセルの操作関数を持ってくる。
https://openpyxl.readthedocs.io/en/stable/styles.html#cell-styles-and-named-styles
from openpyxl.styles import Border, Side, PatternFill, Font, GradientFill, Alignment from openpyxl import Workbook def style_range(ws, cell_range, border=Border(), fill=None, font=None, alignment=None): top = Border(top=border.top) left = Border(left=border.left) right = Border(right=border.right) bottom = Border(bottom=border.bottom) first_cell = ws[cell_range.split(":")[0]] if alignment: ws.merge_cells(cell_range) first_cell.alignment = alignment rows = ws[cell_range] if font: first_cell.font = font for cell in rows[0]: cell.border = cell.border + top for cell in rows[-1]: cell.border = cell.border + bottom for row in rows: l = row[0] r = row[-1] l.border = l.border + left r.border = r.border + right if fill: for c in row: c.fill = fill
フォントなど使わないのもありますが、とりあえずそのまま持ってきて使ってました。
で、目的の罫線を引くには、列間と行間の線を引けないため外枠の罫線のみを使う。
まぁ対象範囲の全列/全行の処理をそれぞれ書いていく感じ。
## ワークブックとワークシートの定義 wb = Workbook() ws = wb.active ## 数字からエクセル列アルファベットへの変換関数(1→A、27→AAみたいな変換) def toAlpha(num): h=int((num-1-26)/(26*26)) i=int((num-1-(h*26*26))/26) j=int(num-(i*26)-(h*26*26)) Alpha='' for k in h,i,j: if k!=0: Alpha+=chr(k+64) return Alpha ##罫線の定義 # 罫線の線種と色の定義(solid:実線、dot:点線) solid = Side(border_style="thin", color="000000") dot = Side(border_style="dotted", color="000000") # 縦線の線種と位置の定義(縦線は列の左だけ線を引く) border_ver_solid = Border(left=solid) border_ver_dot = Border(left=dot) # 横線の線種と位置の定義(横線は行の上だけ線を引く) border_hor_solid = Border(top=solid) border_hor_dot = Border(top=dot) ## 縦線を引いていく # 5の倍数の時だけsolid(実線)で引く ver_start='2' ver_end='30' for col in range(1,27): retuAlpha=toAlpha(3+col) # 罫線範囲を定義(ここでは1周目に'D2:D30'、2周目に'E2:E30'、・・) ver_range=retuAlpha+ver_start+':'+retuAlpha+ver_end if (col-1) % 5 ==0: style_range(ws,ver_range,border=border_ver_solid) else: style_range(ws,ver_range,border=border_ver_dot) ## 横線も引く # こっちも5の倍数だけsolid hor_start='B' hor_end='AD' for row in range(1,27): gyouNum=row+3 #横線の範囲(ここでは1回目'B4:AD4'、2回目'B5:AD5'、・・・) hor_range=hor_start+str(gyouNum)+':'+hor_end+str(gyouNum) if (row-1) % 5 ==0: style_range(ws,hor_range,border=border_hor_solid) else: style_range(ws,hor_range,border=border_hor_dot) ## 列の幅を変更 for i in range(1,30+1): ws.column_dimensions[toAlpha(i)].width=3 ## エクセル保存 wb.save('test.xlsx')
とりあえず、これを順次実行すれば目的である格子型の罫線が引けます。
あ、ちなみにここで書いたコードの出力はLibre Officeでも開けました。 別のエントリでopenpyxlでのシートコピーのエントリも書いてますが、それもちゃんとできてました。
おわり。