[英]tkinter: How to serialize a treeview?
我正在開發一個 python tkinter 應用程序,它將初始數據從 yaml 文件讀取到分層的 TreeView 中,以便用戶進一步編輯。
要實現“保存數據”和“撤消”功能,我是否應該遍歷樹視圖並將數據重建為要序列化(pickle)的 python 對象? 或者是否有一個 python 模塊允許,例如,指定要保存的樹視圖和輸出文件?
我懷疑是否有任何 Python 模塊可以滿足您的需求,即使有,我認為您也不希望圍繞使用它來構建您的應用程序。 相反,您最好將事物解耦並將主要數據存儲在獨立於人機界面的東西中(這可能是也可能不是圖形,並且將來可能會發生變化或以其他方式更改)。 這有時稱為應用程序“模型”。
這樣做將允許您加載和保存它,而不管當前的人機界面是什么。 因此,例如,如果內部模型由一個或多個 Python 對象組成,您就可以自由使用pickle
。 或者,您可以將數據保存回 yaml 格式的文件中,這將使稍后再次加載它變得容易,因為程序已經可以做到這一點。
同樣,當用戶編輯 TreeView 時,應該對模型進行等效的更改以保持兩者同步。
從編碼中抽出一些時間並熟悉模型–視圖–控制器 (MVC)設計模式。
開箱即用,答案是否定的,您不能序列化TreeView
。 dill
可能是開箱即用序列化的最佳選擇……它無法pickle TreeView
對象。
>>> import ttk
>>> import Tkinter as tk
>>>
>>> f = tk.Frame()
>>> t = ttk.Treeview(f)
>>>
>>> import dill
>>> dill.pickles(t)
False
>>> dill.detect.errors(t)
PicklingError("Can't pickle 'tkapp' object: <tkapp object at 0x10eda75e0>",)
>>>
您也許能夠弄清楚如何腌制TreeView
,然后將該方法添加到pickle
注冊表中……但是,您可能需要做一些認真的工作來找出無法腌制的原因。
您可以看到發生了什么,它命中了Tkinter.Tk
對象的__dict__
,並在嘗試腌制某些東西時死亡。
>>> dill.detect.trace(True)
>>> dill.dumps(t)
C2: ttk.Treeview
D2: <dict object at 0x1147f5168>
C2: Tkinter.Frame
D2: <dict object at 0x1147f1050>
C2: Tkinter.Tk
D2: <dict object at 0x1148035c8>
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.3.dev0-py2.7.egg/dill/dill.py", line 194, in dumps
dump(obj, file, protocol, byref, fmode)#, strictio)
File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.3.dev0-py2.7.egg/dill/dill.py", line 184, in dump
pik.dump(obj)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump
self.save(obj)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 725, in save_inst
save(stuff)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.3.dev0-py2.7.egg/dill/dill.py", line 678, in save_module_dict
StockPickler.save_dict(pickler, obj)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 681, in _batch_setitems
save(v)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 725, in save_inst
save(stuff)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.3.dev0-py2.7.egg/dill/dill.py", line 678, in save_module_dict
StockPickler.save_dict(pickler, obj)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 681, in _batch_setitems
save(v)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 725, in save_inst
save(stuff)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
f(self, obj) # Call unbound method with explicit self
File "/Users/mmckerns/lib/python2.7/site-packages/dill-0.2.3.dev0-py2.7.egg/dill/dill.py", line 678, in save_module_dict
StockPickler.save_dict(pickler, obj)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 649, in save_dict
self._batch_setitems(obj.iteritems())
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 681, in _batch_setitems
save(v)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 313, in save
(t.__name__, obj))
pickle.PicklingError: Can't pickle 'tkapp' object: <tkapp object at 0x10eda7648>
>>>
那個東西是一個tkapp
對象。
所以,如果你想進一步挖掘,你可以使用dill.detect
的方法來幫助你找出它不酸洗的確切原因……並嘗試繞過它。
我懷疑腌制小部件是否正確。 您可能也不想走將狀態從treeview
中提取到影子類中並保存該類的方法。 問題是樹視圖並沒有真正在構建時考慮到保存狀態的良好分離。
如果您可以重新設計以將應用程序的狀態與小部件本身完全分開,那么更有可能做您想做的事。 因此,當您詢問How to serialize a treeview
,這實際上不是您要問的。 您想知道如何保存應用程序的狀態。
有一些包可以很容易地做這樣的事情。 我建議你看看enaml
和/或traits
。 enaml
是一個聲明性標記,它要求您構建一個描述應用程序界面如何工作的類。 它迫使您將所顯示內容的內部工作與操作用戶界面所需的代碼分開……而且它以一種非常容易構建的方式來實現——應用程序的狀態與用戶界面是分開的接線。 因此,您構建的類的實例在任何時候都包含應用程序的狀態——無論它是否有 UI,或者兩個或三個 UI。 它使保存應用程序的狀態變得非常容易,因為您永遠不必擔心保存 UI 的狀態——UI 沒有狀態——它只是在應用程序頂部繪制的布局。 那么你就不必擔心酸洗小部件了......
在此處查看enaml
: https : //github.com/nucleic/enaml
和這里的traits
: http : //docs.enthought.com/traits
另一個問答顯示了如何在退出時pickle 樹視圖並在啟動時重新加載它:
OP 的信息如下:
#----------TreeViewlist----------------------
Header =['Website','Username','Password','etc']
樹狀視圖的要點是記錄 OP 訪問的每個網站、使用的用戶 ID 和使用的密碼。
總結接受的答案:
x=[tree.item(x)['values'] for x in tree.get_children()]
filehandler = open('data.pickle', 'wb')
pickle.dump(x,filehandler)
filehandler.close()
items = []
try:
filehandler = open('data.pickle', 'rb')
items = pickle.load(filehandler)
filehandler.close()
except:
pass
for item in items:
tree.insert('','end',values=item)
答案看起來很直接(對我來說),但如果您有任何問題,請在下面發表評論。 如果您在代碼中看到缺陷或錯誤,請在上面的鏈接中發表評論。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.