【问题标题】:Python - Saving state of a program between restarts?Python - 在重新启动之间保存程序的状态?
【发布时间】:2013-01-06 14:54:41
【问题描述】:

我想知道如何保存程序的当前设置,使其保持不变,除非另有说明,对方案重新启动或重新启动计算机。比如windows默认程序便签,它把文字保存在里面,这样即使电脑关机也可以使用。

是否有某种模块可以导入?我的程序基本上是一个任务列表程序,您可以在其中将内容添加到列表中,并使用 wxPython 复选框将其勾选。即使在程序退出后,是否有任何可能的方法来保持它的状态?

如果有人可以向我展示我的代码示例,我将不胜感激,别担心,我不会只是简单地复制它并完成它。对我来说,这将被视为一种学习体验,以便我将来使用它。谢谢。

这是我的程序:

import wx, sys,os

mylist = []

class test(wx.Frame):

def __init__(self, parent, id):


    self.count = 1
    #Frame
    wx.Frame.__init__(self,parent,id,'List',size = (200,500))
    #Panel
    self.panel = wx.Panel(self)
    item = wx.TextEntryDialog(None, "List Title")
    if item.ShowModal() == wx.ID_OK:
        print 'here'
        answer = item.GetValue()
        mylist.append(answer)
        print mylist
        windtitle = wx.StaticText(self.panel, -1, answer, (10,10))
        windtitle.SetForegroundColour("blue")


    addButton = wx.Button(self.panel, label = "+ Add", pos=(40,450), size = (60,-1))
    finishButton = wx.Button(self.panel, label = "Finish", pos=(110,450), size = (60,-1))

    self.Bind(wx.EVT_BUTTON, self.addtomenu, addButton)
    self.Bind(wx.EVT_BUTTON, self.finish, finishButton)

def finish(self, event):
    self.Destroy()
    sys.exit()

def addtomenu(self,event):

    newitem = wx.TextEntryDialog(None, "New Item")
    if newitem.ShowModal() == wx.ID_OK:
        count = len(mylist)+1
        print count
        yaxis = 20*count
        if count == 21:
            wx.StaticText(self.panel, -1, "List To Full", (10, yaxis))
        else:
            answer = newitem.GetValue()
            mylist.append(answer)
            print mylist
            self.Bind(wx.EVT_CLOSE, self.closewindow)
            wx.CheckBox(self.panel, -1, answer, (10,yaxis), size = (200,-1)) 



def closewindow(self, event):
    self.Destroy()






if __name__ == "__main__":
    app=wx.PySimpleApp()  #Blood
    frame = test(parent=None, id = -1)  #Skin
    frame.Show()
    app.MainLoop()  #Heart

【问题讨论】:

    标签: python wxpython save restart


    【解决方案1】:

    这是一个示例,说明如何将程序的状态保存在 JSON 文件中。您已经有一个finish 方法,当程序退出或Finish 按钮关闭时调用该方法。我们现在可以使用它来调用 save 方法,将状态保存到 JSON 文件中。

    def finish(self, event):
        self.save()
        self.Destroy()
        sys.exit()
    
    def save(self):
        windtitle = self.windtitle.GetLabelText()
        checkboxes = [{'checked': child.IsChecked(),
                       'label': child.GetLabel()}
                      for child in self.panel.GetChildren()
                      if isinstance(child, wx.CheckBox)]
        data = {
            'windtitle':windtitle,
            'checkboxes':checkboxes,
            }
        with open(CONFIGFILE, 'w') as f:
            json.dump(data, f)
    

    您可以通过以下方式读取 JSON 数据以重构 GUI:

    def load(self):
        if os.path.exists(CONFIGFILE):
            with open(CONFIGFILE, 'r') as f:
                data = json.load(f)
            title = data['windtitle']
            self.windtitle = wx.StaticText(self.panel, -1, title)
            self.vbox.Add(self.windtitle)
            for checkbox in data['checkboxes']:
                label = checkbox['label']
                cb = wx.CheckBox(
                    self.panel, -1, checkbox['label'])
                self.vbox.Add(cb)                
                cb.SetValue(checkbox['checked'])
        else:
            self.create_windtitle()
        self.create_buttons()
    

    例如:

    import wx, sys, os
    import json
    
    CONFIGFILE = os.path.expanduser('~/tasklist.json')
    class test(wx.Frame):
        def __init__(self, parent, id):
            frame = wx.Frame.__init__(self, parent, id, 'List', size = (200,500))
            self.panel = wx.Panel(self)
            self.panelbox = wx.BoxSizer(wx.VERTICAL)                
    
            self.vbox = wx.BoxSizer(wx.VERTICAL)        
            self.load()
    
            self.panelbox.Add(self.vbox)        
            self.panelbox.Add(self.buttonbox)
    
            self.panel.SetSizer(self.panelbox)
            self.panelbox.Fit(self)
    
            self.Bind(wx.EVT_BUTTON, self.addtomenu, self.addButton)
            self.Bind(wx.EVT_BUTTON, self.finish, self.finishButton)
            self.Bind(wx.EVT_CLOSE, self.finish)
    
        def create_buttons(self):
            self.buttonbox = wx.BoxSizer(wx.VERTICAL)                
            self.addButton = wx.Button(
                self.panel, label = "+ Add")
            self.finishButton = wx.Button(
                self.panel, label = "Finish")
            self.buttonbox.Add(self.addButton)
            self.buttonbox.Add(self.finishButton)
    
        def create_windtitle(self):
            item = wx.TextEntryDialog(None, "List Title")
            if item.ShowModal() == wx.ID_OK:
                answer = item.GetValue()
                self.windtitle = wx.StaticText(self.panel, -1, answer)
                self.windtitle.SetForegroundColour("blue")
    
        def addtomenu(self, event):
            newitem = wx.TextEntryDialog(None, "New Item")
            if newitem.ShowModal() == wx.ID_OK:
                if len(self.mylist) > 5:
                    wx.StaticText(self.panel, -1, "List To Full")
                else:
                    answer = newitem.GetValue()
                    cb = wx.CheckBox(self.panel, -1, answer)
                    self.vbox.Add(cb)
            self.panelbox.Fit(self)
    
        def finish(self, event):
            self.save()
            self.Destroy()
            sys.exit()
    
        @property
        def mylist(self):
            return [ child.GetLabel()
                     for child in self.panel.GetChildren()
                     if isinstance(child, wx.CheckBox) ]
    
        def save(self):
            windtitle = self.windtitle.GetLabelText()
            checkboxes = [{'checked': child.IsChecked(),
                           'label': child.GetLabel()}
                          for child in self.panel.GetChildren()
                          if isinstance(child, wx.CheckBox)]
            data = {
                'windtitle':windtitle,
                'checkboxes':checkboxes,
                }
            with open(CONFIGFILE, 'w') as f:
                json.dump(data, f)
    
        def load(self):
            if os.path.exists(CONFIGFILE):
                with open(CONFIGFILE, 'r') as f:
                    data = json.load(f)
                title = data['windtitle']
                self.windtitle = wx.StaticText(self.panel, -1, title)
                self.vbox.Add(self.windtitle)
                for checkbox in data['checkboxes']:
                    label = checkbox['label']
                    cb = wx.CheckBox(
                        self.panel, -1, checkbox['label'])
                    self.vbox.Add(cb)                
                    cb.SetValue(checkbox['checked'])
            else:
                self.create_windtitle()
            self.create_buttons()
    
    if __name__ == "__main__":
        app = wx.PySimpleApp()  #Blood
        frame = test(parent = None, id = -1)  #Skin
        frame.Show()
        app.MainLoop()  #Heart
    

    顺便说一下,不要使用明确的位置来在您的 GUI 中放置小部件。那条路通向疯狂。如果您使用位置(例如pos = (10,yaxis)),随着您的 GUI 增长,修改布局变得越来越困难。每个元素的位置都依赖于其他元素的位置,并且很快变得无法管理。

    每个 GUI 框架都提供了一些更明智的方法来实现漂亮的布局。我对wxpython不是很熟悉,但是好像用BoxSizers。我上面使用的布局非常简陋。我确信通过对 wxpython 布局设计模式的一些研究可以实现更好的布局。


    有时我需要找出一个小部件的所有属性和方法是什么。例如,我不知道如何询问 Panel 它包含哪些 Checkboxes。我是用这个函数找到的:

    def describe(obj):
        for key in dir(obj):
            try:
                val = getattr(obj, key)
            except AttributeError:
                continue
            if callable(val):
                help(val)
            else:
                print('{k} => {v}'.format(k = key, v = val))
            print('-'*80)
    
    describe(self.panel)
    

    这是我在 utils_debug 中的功能。

    【讨论】:

    • 可能有一个 wxpython 特定的应用程序析构函数
    • 谢谢你,这是我在 wxpython 中的第一个程序,我只是想尽我所能。我知道 Tkinter 中的 .pack() 函数,我希望在 wxpython 中有类似的东西。我肯定会研究 BoxSizer,并研究您的代码,看看它是如何工作的,再次感谢您 :)
    • 还有这个模块 utils_debug,我怎么得到这个?我一直在寻找最后 10 分钟,但根本找不到任何东西。我没有这个模块。
    • 您可以删除 utils_debug -- 我发布的代码中的任何地方都没有使用它。你不会在网上找到它。但是,我编辑了我的帖子以展示我如何使用它的 describe 函数来搜索小部件属性。
    • 我喜欢#Blood、#Skin、#Heart cmets - 非常可爱。
    【解决方案2】:

    您可能希望将按钮的状态存储在列表或字典等数据集合中,然后您可以编组或序列化数据

    例如

    my_button_states = {"button1":True}
    import json
    with open("states.json", 'w') as output:
        json.dump(my_button_states, output)
    

    稍后只需将 json 重新加载回程序并通过循环遍历 dict 来设置按钮

    例如

    with open("states.json") as fp:
        my_button_states = json.loads(fp)
    # inside your frame or something.... idk where you put them.
    for button, state in my_button_states.iteritems():
        setattr(self, button, state)
    

    您可以使用json,或者有些人可能会建议使用pickle,但json 可能是更好的选择。

    使用您的代码,您可能想要执行类似的操作

    json.dump(mylist, output)
    

    当然是在我的例子中

    【讨论】:

    • 我所有的按钮都已经存储在一个列表中,所以基本上只需编写更多程序来检查该列表并将它们转换为复选框?似乎是个好主意,但是这个 json 模块是什么,我将如何存储这个列表,以便即使在计算机关闭时也能保存它?我对 python 还很陌生。
    • @user1952975 你要存储的按钮是什么?
    • 我已经上传了我的代码,如您所见,目前非常简单。我将如何在我的代码中实现您所说的内容?对不起我的最后评论,我的意思是“输入”而不是“按钮”:D
    • 谢谢,我现在就试试。
    • @Jokob 我遇到了一个错误,考虑到我对这整个 json 东西还是新手,我有点迷茫。我了解 json save 是您要求它保存到 file.json 中的内容。然后你可以使用你展示的那个例子来回调它,但是我得到了一个错误:mylist = json.loads(fp),它说它需要一个字符串......:c 请帮助
    【解决方案3】:

    只是一个简短的通知。我想知道是否有内置的解决方案——毕竟,我们大多数人迟早都会面临这个问题。

    原来,有一个叫做PersistenceManager的东西可以用来简单地保存和恢复状态。

    注意,我没用过,只是偶然发现的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-19
      • 1970-01-01
      • 1970-01-01
      • 2019-06-27
      • 1970-01-01
      • 2011-04-30
      • 1970-01-01
      • 2012-10-23
      相关资源
      最近更新 更多