openpyxl修改后无法读取
Openpyxl is unable to read after modifying
要求:
1.create 使用 Tkinter 的图形用户界面
2.Update excel 通过从 Tkinter 条目小部件获取值
3.Read 同一工作簿的另一个 sheet
4.plot 图在 Tkinter 中使用 window。
问题:所有功能都可以正常工作,除了同时修改和读取一个接一个。
加载工作簿 data_only=False 以保留公式。当我从 "SIMULATION" sheet 中读取链接到 "Input" 的单元格时,我已经在 "INPUT" sheet.Then 中成功修改 excel sheet有公式,没有数据。
用 Excel 打开 excel 文件并关闭它,现在如果我 运行 python 程序再次没有修改功能,程序可以读取单元格值和绘图。
在程序工作簿的读取功能期间,第二次使用 data_only = True 加载单元格值。
任何建议都会对我很有帮助。
from tkinter import *
from tkinter import ttk
from openpyxl import load_workbook
import datetime
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class Root(Tk):
f = Figure(figsize=(20,8))
a = f.add_subplot(111)
entryString1=0
entryString2=0
entryString3=0
entryString4=0
entryString5=0
entryString6=0
def __init__(self):
super(Root, self).__init__()
self.title("Python Tkinter Dialog Widget")
self.state("zoomed")
self.frame = ttk.Frame(self,borderwidth=2, relief="solid")
self.frame.pack(side='top',fill=X,padx=10,pady=20)
self.entry()
self.button()
self.canvas = FigureCanvasTkAgg(self.f, self.frame)
self.canvas.get_tk_widget().pack(fill="both",padx=10,pady=20)
self.canvas.draw()
def entry(self):
self.frame2 = ttk.Frame(self)
self.frame2.pack(fill=X,padx=10,pady=20)
self.labelentry1 = ttk.Label(self.frame2,text = "V Past Main begin period: ")
self.labelentry1.pack(fill=X,side='left',anchor=W)
self.entry1 = ttk.Entry(self.frame2)
self.entry1.pack(fill=X,side='left')
self.labelentry2 = ttk.Label(self.frame2,text = " V Past PS begin period: ")
self.labelentry2.pack(fill=X,side='left')
self.entry2 = ttk.Entry(self.frame2)
self.entry2.pack(fill=X,side='left')
self.labelentry3 = ttk.Label(self.frame2,text = " Adv 0% Main: ")
self.labelentry3.pack(fill=X,side='left')
self.entry3 = ttk.Entry(self.frame2)
self.entry3.pack(fill=X,side='left')
self.labelentry4 = ttk.Label(self.frame2,text = " Adv 0% PS: ")
self.labelentry4.pack(fill=X,side='left')
self.entry4 = ttk.Entry(self.frame2)
self.entry4.pack(fill=X,side='left')
self.labelentry5 = ttk.Label(self.frame2,text = " Single premium already paid: ")
self.labelentry5.pack(fill=X,side='left')
self.entry5 = ttk.Entry(self.frame2)
self.entry5.pack(fill=X,side='left')
self.labelentry6 = ttk.Label(self.frame2,text = " Yearly premium already paid: ")
self.labelentry6.pack(fill=X,side='left')
self.entry6 = ttk.Entry(self.frame2)
self.entry6.pack(fill=X,side='left')
def button(self):
self.frame3 = ttk.Frame(self)
self.frame3.pack(side='bottom')
self.labelFrame = ttk.LabelFrame(self.frame3,text = "Regenrate Graph")
self.labelFrame.pack(padx=10)
self.button = ttk.Button(self.labelFrame, text = "Click",command = self.fileDialog)
self.button.pack(padx=10)
def fileDialog(self):
self.entryString1 = self.entry1.get()
self.entryString2 = self.entry2.get()
self.entryString3 = self.entry3.get()
self.entryString4 = self.entry4.get()
self.entryString5 = self.entry5.get()
self.entryString6 = self.entry6.get()
#Load excel file
self.filename = "C:\Users\ramit\Desktop\Projection V0.3_Shankha .xlsx"
#load excel file to modify
self.work_book = load_workbook (self.filename)
self.sheet = self.work_book['Inputs']
if len(self.entryString1) != 0:
self.sheet.cell(row=4,column=5).value=int(self.entryString1)
if len(self.entryString2) != 0:
self.sheet.cell(row=5,column=5).value=int(self.entryString2)
if len(self.entryString3) != 0:
self.sheet.cell(row=6,column=5).value=int(self.entryString3)
if len(self.entryString4) != 0:
self.sheet.cell(row=7,column=5).value=int(self.entryString4)
if len(self.entryString5) != 0:
self.sheet.cell(row=9,column=5).value=int(self.entryString5)
if len(self.entryString6) != 0:
self.sheet.cell(row=10,column=5).value=int(self.entryString6)
self.work_book.save(self.filename)
self.work_book = None
#load excel file to read
self.work_book = load_workbook (self.filename,data_only=True)
self.sheet_1 = self.work_book['Simulation']
self.x = []
self.y = []
for i in range(10, 17):
self.x.append (self.sheet_1.cell(row=i + 1,column=1).value)
self.y.append (self.sheet_1.cell(row=i + 1,column= 77).value)
self.a.clear()
print(self.x)
print(self.y)
self.a.set_xlabel('Simulation date')
self.a.set_ylabel('Reserve')
self.a.plot(self.x, self.y, color='cyan', label='Projection')
self.canvas.draw()
root = Root()
root.mainloop()
问题是 openpyxl 不计算 excel 中的公式。它只会 return 由 excel 或 'None' 保存的最后一个值(data_only=True)。后者是当您更改输入单元格并使用 [cell].value 通过公式调用单元格的值时发生的情况。当您不更改 sheet 时,您将获得 excel 中设置的值,这就是为什么当您 disable/don 未对 excel 功能进行输入时您的代码有效的原因.
解决该问题的最简单方法是使用 xlwings,它应该可以按照您的预期工作。还有一些其他选项。例如直接使用 windows excel 命令更新 sheet 然后使用 openpyxl 读取,但我觉得交换模块是更简单的解决方案。您可能还想考虑将函数带到流程的 python 端,并将结果写入 excel sheet.
how to get formula result in excel using xlwings
import xlwings as xw
sheet = xw.Book(r'C:/path/to/file.xlsx').sheets['sheetname']
result = sheet['X2'].value
要求: 1.create 使用 Tkinter 的图形用户界面 2.Update excel 通过从 Tkinter 条目小部件获取值 3.Read 同一工作簿的另一个 sheet 4.plot 图在 Tkinter 中使用 window。
问题:所有功能都可以正常工作,除了同时修改和读取一个接一个。
加载工作簿 data_only=False 以保留公式。当我从 "SIMULATION" sheet 中读取链接到 "Input" 的单元格时,我已经在 "INPUT" sheet.Then 中成功修改 excel sheet有公式,没有数据。
用 Excel 打开 excel 文件并关闭它,现在如果我 运行 python 程序再次没有修改功能,程序可以读取单元格值和绘图。
在程序工作簿的读取功能期间,第二次使用 data_only = True 加载单元格值。
任何建议都会对我很有帮助。
from tkinter import *
from tkinter import ttk
from openpyxl import load_workbook
import datetime
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class Root(Tk):
f = Figure(figsize=(20,8))
a = f.add_subplot(111)
entryString1=0
entryString2=0
entryString3=0
entryString4=0
entryString5=0
entryString6=0
def __init__(self):
super(Root, self).__init__()
self.title("Python Tkinter Dialog Widget")
self.state("zoomed")
self.frame = ttk.Frame(self,borderwidth=2, relief="solid")
self.frame.pack(side='top',fill=X,padx=10,pady=20)
self.entry()
self.button()
self.canvas = FigureCanvasTkAgg(self.f, self.frame)
self.canvas.get_tk_widget().pack(fill="both",padx=10,pady=20)
self.canvas.draw()
def entry(self):
self.frame2 = ttk.Frame(self)
self.frame2.pack(fill=X,padx=10,pady=20)
self.labelentry1 = ttk.Label(self.frame2,text = "V Past Main begin period: ")
self.labelentry1.pack(fill=X,side='left',anchor=W)
self.entry1 = ttk.Entry(self.frame2)
self.entry1.pack(fill=X,side='left')
self.labelentry2 = ttk.Label(self.frame2,text = " V Past PS begin period: ")
self.labelentry2.pack(fill=X,side='left')
self.entry2 = ttk.Entry(self.frame2)
self.entry2.pack(fill=X,side='left')
self.labelentry3 = ttk.Label(self.frame2,text = " Adv 0% Main: ")
self.labelentry3.pack(fill=X,side='left')
self.entry3 = ttk.Entry(self.frame2)
self.entry3.pack(fill=X,side='left')
self.labelentry4 = ttk.Label(self.frame2,text = " Adv 0% PS: ")
self.labelentry4.pack(fill=X,side='left')
self.entry4 = ttk.Entry(self.frame2)
self.entry4.pack(fill=X,side='left')
self.labelentry5 = ttk.Label(self.frame2,text = " Single premium already paid: ")
self.labelentry5.pack(fill=X,side='left')
self.entry5 = ttk.Entry(self.frame2)
self.entry5.pack(fill=X,side='left')
self.labelentry6 = ttk.Label(self.frame2,text = " Yearly premium already paid: ")
self.labelentry6.pack(fill=X,side='left')
self.entry6 = ttk.Entry(self.frame2)
self.entry6.pack(fill=X,side='left')
def button(self):
self.frame3 = ttk.Frame(self)
self.frame3.pack(side='bottom')
self.labelFrame = ttk.LabelFrame(self.frame3,text = "Regenrate Graph")
self.labelFrame.pack(padx=10)
self.button = ttk.Button(self.labelFrame, text = "Click",command = self.fileDialog)
self.button.pack(padx=10)
def fileDialog(self):
self.entryString1 = self.entry1.get()
self.entryString2 = self.entry2.get()
self.entryString3 = self.entry3.get()
self.entryString4 = self.entry4.get()
self.entryString5 = self.entry5.get()
self.entryString6 = self.entry6.get()
#Load excel file
self.filename = "C:\Users\ramit\Desktop\Projection V0.3_Shankha .xlsx"
#load excel file to modify
self.work_book = load_workbook (self.filename)
self.sheet = self.work_book['Inputs']
if len(self.entryString1) != 0:
self.sheet.cell(row=4,column=5).value=int(self.entryString1)
if len(self.entryString2) != 0:
self.sheet.cell(row=5,column=5).value=int(self.entryString2)
if len(self.entryString3) != 0:
self.sheet.cell(row=6,column=5).value=int(self.entryString3)
if len(self.entryString4) != 0:
self.sheet.cell(row=7,column=5).value=int(self.entryString4)
if len(self.entryString5) != 0:
self.sheet.cell(row=9,column=5).value=int(self.entryString5)
if len(self.entryString6) != 0:
self.sheet.cell(row=10,column=5).value=int(self.entryString6)
self.work_book.save(self.filename)
self.work_book = None
#load excel file to read
self.work_book = load_workbook (self.filename,data_only=True)
self.sheet_1 = self.work_book['Simulation']
self.x = []
self.y = []
for i in range(10, 17):
self.x.append (self.sheet_1.cell(row=i + 1,column=1).value)
self.y.append (self.sheet_1.cell(row=i + 1,column= 77).value)
self.a.clear()
print(self.x)
print(self.y)
self.a.set_xlabel('Simulation date')
self.a.set_ylabel('Reserve')
self.a.plot(self.x, self.y, color='cyan', label='Projection')
self.canvas.draw()
root = Root()
root.mainloop()
问题是 openpyxl 不计算 excel 中的公式。它只会 return 由 excel 或 'None' 保存的最后一个值(data_only=True)。后者是当您更改输入单元格并使用 [cell].value 通过公式调用单元格的值时发生的情况。当您不更改 sheet 时,您将获得 excel 中设置的值,这就是为什么当您 disable/don 未对 excel 功能进行输入时您的代码有效的原因.
解决该问题的最简单方法是使用 xlwings,它应该可以按照您的预期工作。还有一些其他选项。例如直接使用 windows excel 命令更新 sheet 然后使用 openpyxl 读取,但我觉得交换模块是更简单的解决方案。您可能还想考虑将函数带到流程的 python 端,并将结果写入 excel sheet.
how to get formula result in excel using xlwings
import xlwings as xw
sheet = xw.Book(r'C:/path/to/file.xlsx').sheets['sheetname']
result = sheet['X2'].value