解决 openpyxl 垂直分页符和水平分页符同时添加的问题
前言
十天前知乎上有人提问 python:openpyxl模块怎么给表格添加分页符?实现分页打印功能?,看到问题之后,我很快的给他了一个如何添加垂直分页符或水平分页符的示例,你以为问题就结束了?我是这么以为的,但是事实证明,我太天真了,就在我给出示例的几分钟后,他在我的回答下评论了,说是同时添加垂直分页符和水平分页符失败了.
我当时的第一反应:
心里想着,肯定是他的写法有问题,毫不犹豫的回复到," 没有试过同时添加两种分页符的操作,默认是水平分页符,如果你先添加了垂直分页符的话,应该后面需要重新声明:openpyxl.worksheet.pagebreak.PageBreak.tagname = "rowBreaks",听着自己飞快击打键盘的声音,自己不经有点飘飘然.就在沉浸在自己的YY当中,又过去了几分钟,他用正确的代码错误的结果狠狠的摔在了我的脸上:
col_break = openpyxl.worksheet.pagebreak.Break(5) #创建分页符,参数5:在第5/6中间分页
sheet1.page_breaks.tagname = 'rowBreaks' #分页符属性设置为行分页符
sheet1.page_breaks.append(col_break) #把分页符对象添加到sheet对象里
row_break = openpyxl.worksheet.pagebreak.Break(3) #创建分页符
sheet1.page_breaks.tagname = 'colBreaks' #分页符属性设置为列分页符
sheet1.page_breaks.append(row_break) #把分页符对象添加到sheet对象里
"结果是在第3和5列添加了两个垂直分页符,是哪里有问题?大师",他问道. 我看了一眼代码好像没有错,我的心有点慌了,双手开始微微颤抖起来,一遍又一遍地仔细地巡视着代码,视图找出错误反驳他,但是并没有,抱着最后的希望,我把他的代码复制到自己的文件中,然后敲下回车符, excel 文件静静的生成在目录下,这可能是我最后的希望了.拿鼠标的手不自觉的颤抖起来,那么小的屏幕,那么大的文件,鼠标怎么半天都没办法移动上去,我深吸一口气,控制住自己手,终于把鼠标一上去了,双击excel,闭上眼睛,再睁开,我知道,我错了.但是就这么放弃了吗?绝不!我要把这个问题打到!
亮剑
"是时候展示真正的技术了"
俗话说"解铃还须系铃人",我们还得自己看一下问题代码:
# example.py
from openpyxl import Workbook
from openpyxl.compat import range
from openpyxl.utils import get_column_letter
from openpyxl.worksheet.pagebreak import Break, PageBreak
wb = Workbook()
ws = wb.active
for row in range(1, 20):
for col in range(1,30):
_ = ws.cell(column=col, row=row, value="{0}".format(get_column_letter(col)))
col_break = Break(5) #创建分页符,参数5:在第5/6中间分页
ws.page_breaks.tagname = 'rowBreaks' #分页符属性设置为行分页符
ws.page_breaks.append(col_break) #把分页符对象添加到sheet对象里
row_break = Break(3) #创建分页符
ws.page_breaks.tagname = 'colBreaks' #分页符属性设置为列分页符
ws.page_breaks.append(row_break) #把分页符对象添加到sheet对象里
wb.save(filename = dest_filename)
从代码上应该是后面的 page_breaks 把前面的覆盖了, 那让我们看看 page_breaks 究竟是什么东西.
class Worksheet(_WorkbookChild):
# 省略部分代码
def _setup(self):
self.page_breaks = PageBreak() # 再看 PageBreak
class PageBreak(Serialisable):
tagname = "rowBreaks"
# 省略部分代码
def append(self, brk=None):
"""
Add a page break
"""
vals = list(self.brk)
if not isinstance(brk, Break):
brk = Break(id=self.count+1)
vals.append(brk)
self.brk = vals
从 example 中我们不难发现,我们是通过修改 page_breaks 的 tag_name 去决定插入的分页符是垂直分页符还是水平分页符的.但是 page_breaks 现在只有一个 PageBreak 这就难怪后声明的会把前面的覆盖了,那么如果我们把 page_breaks 变成 PageBreak 的列表呢?
First Blood -- page_breaks
说改咱就改啊,首先尝试修改 WorkSheet 类
class Worksheet(_WorkbookChild):
# 省略部分代码
def _setup(self):
self.page_breaks = [PageBreak()]
然后再修改一下 example.py
from openpyxl import Workbook
from openpyxl.compat import range
from openpyxl.utils import get_column_letter
from openpyxl.worksheet.pagebreak import Break, PageBreak
wb = Workbook()
dest_filename = 'empty_book.xlsx'
ws = wb.active
for row in range(1, 20):
for col in range(1,30):
_ = ws.cell(column=col, row=row, value="{0}".format(get_column_letter(col)))
rowPageBreak = PageBreak()
rowPageBreak.tagname = 'rowBreaks'
colPageBreak = PageBreak()
colPageBreak.tagname = 'colBreaks'
ws.page_breaks = [rowPageBreak, colPageBreak]
ws.page_breaks[0].append(Break(id=5))
ws.page_breaks[1].append(Break(id=3))
wb.save(filename = dest_filename)
敲下回车,心里那个美滋滋,还没高兴几秒钟,就出问题了,果然做人还是得低调一点
Traceback (most recent call last):
File "test.py", line 24, in <module>
wb.save(filename = dest_filename)
File "F:\workspace\python\test_openpyxl\test_openpyxl\lib\site-packages\openpyxl\workbook\workbook.py", line 391, in save
save_workbook(self, filename)
File "F:\workspace\python\test_openpyxl\test_openpyxl\lib\site-packages\openpyxl\writer\excel.py", line 284, in save_workbook
writer.save(filename)
File "F:\workspace\python\test_openpyxl\test_openpyxl\lib\site-packages\openpyxl\writer\excel.py", line 266, in save
self.write_data()
File "F:\workspace\python\test_openpyxl\test_openpyxl\lib\site-packages\openpyxl\writer\excel.py", line 83, in write_data
self._write_worksheets()
File "F:\workspace\python\test_openpyxl\test_openpyxl\lib\site-packages\openpyxl\writer\excel.py", line 203, in _write_worksheets
xml = ws._write()
File "F:\workspace\python\test_openpyxl\test_openpyxl\lib\site-packages\openpyxl\worksheet\worksheet.py", line 893, in _write
return write_worksheet(self)
File "F:\workspace\python\test_openpyxl\test_openpyxl\lib\site-packages\openpyxl\writer\worksheet.py", line 151, in write_worksheet
xf.write(ws.page_breaks.to_tree())
AttributeError: 'list' object has no attribute 'to_tree'
看了一眼错误信息,发现了从中作祟的家伙再 worksheet.py 的 151 行, 让我们悄悄地看一眼,打枪的不要.
# worksheet.py
# 省略部分代码
if ws.page_breaks:
xf.write(ws.page_breaks.to_tree())
原来是我们修改了 page_breaks 之后, page_breaks 有时候不再是孤家寡人了,我们需要考虑它有另外的 PageBreak 的情况了.
Double Kill -- Worksheet
# worksheet.py
# 省略部分代码
if ws.page_breaks:
if isinstance(ws.page_breaks,list):
for page_break_item in ws.page_breaks:
xf.write(page_break_item.to_tree())
else:
xf.write(ws.page_breaks.to_tree())
回车,毫无问题,人生啊就是这么寂寞如雪~~~
后记
已经在 openpyxl 提了相应的issue,目前再写测试用例,过段时间就提交 PR 了
解决 openpyxl 垂直分页符和水平分页符同时添加的问题的更多相关文章
- Microsoft office(1)分页符和分节符
Microsoft office下的页面布局中的分页符和分节符的区别: 分页符:标记一页的终止并开始下一页的点 分节符:插入分节符并在下一页开始新节 一般情况下,分节符在分页符外围,分节符一般是各种格 ...
- solr深分页,游标操作分页,解决性能问题
solr深分页,游标操作分页,解决性能问题 @Test public void pageByCursor() { try { solrServer.connect(); String query = ...
- pagebean pagetag java 后台代码实现分页 demo 前台标签分页 后台java分页
java 后台代码实现分页 demo 实力 自己写的 标签分页 package com.cszoc.sockstore.util; import java.util.HashMap;import ja ...
- MvcPager 概述 MvcPager 分页示例 — 标准Ajax分页 对SEO进行优化的ajax分页 (支持asp.net mvc)
该示例演示如何使用MvcPager最基本的Ajax分页模式. 使用AjaxHelper的Pager扩展方法来实现Ajax分页,使用Ajax分页模式时,必须至少指定MvcAjaxOptions的Upda ...
- php分页类代码带分页样式效果(转)
php分页类代码,有漂亮的分页样式风格 时间:2016-03-16 09:16:03来源:网络 导读:不错的php分页类代码,将类文件与分页样式嵌入,实现php查询结果的精美分页,对研究php分页原理 ...
- PHP+jQuery 列表分页类 ( 支持 url 分页 / ajax 分页 )
/* ******* 环境:Apache2.2.8 ( 2.2.17 ) + PHP5.2.6 ( 5.3.3 ) + MySQL5.0.51b ( 5.5.8 ) + jQuery-1.8.3.mi ...
- 解决 placeholder 垂直不居中,偏上的问题
解决 placeholder 垂直不居中,偏上的问题 安卓浏览器显示placeholder 垂直不居中,而iphone没问题,搜了一下答案,解决方法是把input的line-height去掉就行 参考 ...
- LayUI分页,LayUI动态分页,LayUI laypage分页,LayUI laypage刷新当前页
LayUI分页,LayUI动态分页,LayUI laypage分页,LayUI laypage刷新当前页 >>>>>>>>>>>> ...
- Angularjs的真分页,服务端分页,后台分页的解决方案
背景:项目的框架使用的是Angularjs,在做数据展示的时候,使用的是ng-table.用过ng-table的人都知道,他是自带分页的,默认分页方式是假分页.也就是一口气把所有的数据从数据库里取出来 ...
随机推荐
- kindle paperwhite3 连不上WIFI解决方法
确定能连接上其它的设备比如手机.如果是密码没错,路由器也正常,但是你还是连接不上,那就跟我之前遇到一样了.你先让你的kpw连接一次,不要动,再检查下你路由器连接的客户端列表(我的是在DHCP服务器一栏 ...
- [sh]sed 4个功能
[root@lanny test]# cat test.txt test liyao lanny 经典博文: http://oldboy.blog.51cto.com/2561410/949365 h ...
- 【Android】4.3 屏幕布局和旋转
分类:C#.Android.VS2015:创建日期:2016-02-06 为了控制屏幕的放置方向(纵向.横向),可以在Resource下同时定义两种不同的布局文件夹:layout和layout-lan ...
- hdu 5289 Assignment(给一个数组,求有多少个区间,满足区间内的最大值和最小值之差小于k)
1.区间是一段的,不是断开的哟 2.代码是看着标程写的 3.枚举左端点,二分右端点流程: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L ...
- hdu 1532 最大流
#include <cstdio> #include <iostream> #include <algorithm> #include <queue> ...
- Linux环境下搭建测试环境(LAMP详细说明)
一.安装虚拟机与CentOS7 传送门:https://www.cnblogs.com/mrgavin/p/9372393.html 注意:以下安装,我都是用的root权限. 二.安装Apache1. ...
- 三、为什么String在Java中是不可更改的
String在Java中是个不可更改的类.一个不可更改的类简单来说就是这个类的所有实例是不可以更改的.所有的实例信息在创建的时候被初始化而且信息是不可以更改的.不可更改的类有很多好处.这篇文章总结了为 ...
- div设置contentEditable="true"作为文本编辑器,定位光标解决办法
function set_focus(el) { el = el[0]; // jquery 对象转dom对象 el.focus(); if ($.browser.msie) { ...
- javaee 架构师之路
Java程序员 高级特性 反射.泛型.注释符.自动装箱和拆箱.枚举类.可变 参数.可变返回类型.增强循环.静态导入 核心编程 IO.多线程.实体类. 集合类.正则表达式. XML和属性文件 图形编程 ...
- 简单的java程序
1.二分查找,java的输入与输出 package com; public class Firstapp{ public static void main(String args[]) { java. ...