我目前正在基於線程How to get variable data from a class的GUI上工作。由於會有大量的數據需要處理,我想使用一個Model-Class,它通過Observer得到它的更新。Python 2.7 - 如何在Tkinter GUI中使用Observer,在哪些幀之間切換?
眼下,在頁面的一個變化在ttk.Combobox
通過<<ComboboxSelect>>
註冊,被拉進Controller
的變量self.shared_data
並傳遞給Model
。這樣,不使用Oberserver/Observable邏輯。相反,只要用戶在GUI中採取相應的操作,就會更改Model
中的數據。
I,然而,會喜歡不必須使用綁定像<<ComboboxSelect>>
以改變Model
相應的數據,但是觀察員/可觀察的邏輯,用於檢測,即,即條目"Inputformat"
在詞典self.shared_data
的Controller
內是然後刷新Model
的數據,即self.model_data
,其中保存了ttk.Combobox
的實際狀態。
總之,我要實現以下,通過使用觀測器:
用戶在ttk.Combobox
選擇即「條目01」 - > self.shared_data [「Inputformat」]在Controller
現在充滿用「Entry 01」 - > Observer/Observable邏輯檢測到 - >Model
中的相應變量正在改變。
爲了讓您有一些工作,這裏是代碼。
# -*- coding: utf-8 -*-
import csv
import Tkinter as tk # python2
import ttk
import tkFileDialog
# Register a new csv dialect for global use.
# Its delimiter shall be the semicolon:
csv.register_dialect('excel-semicolon', delimiter = ';')
font = ('Calibri', 12)
'''
###############################################################################
# Model #
###############################################################################
'''
class Model:
def __init__(self, *args, **kwargs):
# There shall be a variable, which is updated every time the entry
# of the combobox is changed
self.model_keys = {}
self.model_directories = {}
def set_keys(self, keys_model):
self.model_keys = keys_model
keys = []
keyentries = []
for key in self.model_keys:
keys.append(key)
for entry in self.model_keys:
keyentries.append(self.model_keys[entry].get())
print "model_keys: {0}".format(keys)
print "model_keyentries: {0}".format(keyentries)
def get_keys(self):
keys_model = self.model_keys
return(keys_model)
def set_directories(self, model_directories):
self.model_directories = model_directories
print "Directories: {0}".format(self.model_directories)
def get_directories(self):
model_directories = self.model_directories
return(model_directories)
'''
###############################################################################
# Controller #
###############################################################################
'''
# controller handles the following: shown pages (View), calculations
# (to be implemented), datasets (Model), communication
class PageControl(tk.Tk):
''' Initialisations '''
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs) # init
tk.Tk.wm_title(self, "MCR-ALS-Converter") # title
# initiate Model
self.model = Model()
# file dialog options
self.file_opt = self.file_dialog_options()
# stores checkboxstatus, comboboxselections etc.
self.shared_keys = self.keys()
# creates the frames, which are stacked all over each other
container = self.create_frame()
self.stack_frames(container)
#creates the menubar for all frames
self.create_menubar(container)
# raises the chosen frame over the others
self.frame = self.show_frame("StartPage")
''' Methods to show View'''
# frame, which is the container for all pages
def create_frame(self):
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
container = ttk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
return(container)
def stack_frames(self, container):
self.frames = {}
for F in (StartPage, PageOne, PageTwo):
page_name = F.__name__
frame = F(parent = container, controller = self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
# overarching menubar, seen by all pages
def create_menubar(self, container):
# the menubar is going to be seen by all pages
menubar = tk.Menu(container)
menubar.add_command(label = "Quit", command = lambda: app.destroy())
tk.Tk.config(self, menu = menubar)
# function of the controller, to show the desired frame
def show_frame(self, page_name):
#Show the frame for the given page name
frame = self.frames[page_name]
frame.tkraise()
return(frame)
''' Push and Pull of Data from and to Model '''
# calls the method, which pushes the keys in Model (setter)
def push_keys(self):
self.model.set_keys(self.shared_keys)
# calls the method, which pulls the key data from Model (getter)
def pull_keys(self):
pulled_keys = self.model.get_keys()
return(pulled_keys)
# calls the method, which pushes the directory data in Model (setter)
def push_directories(self, directories):
self.model.set_directories(directories)
# calls the method, which pulls the directory data from Model (getter)
def pull_directories(self):
directories = self.model.get_directories()
return(directories)
''' Keys '''
# dictionary with all the variables regarding widgetstatus like checkbox checked
def keys(self):
keys = {}
keys["Inputformat"] = tk.StringVar()
keys["Outputformat"] = tk.StringVar()
return(keys)
''' Options '''
# function, which defines the options for file input and output
def file_dialog_options(self):
#Options for saving and loading of files:
options = {}
options['defaultextension'] = '.csv'
options['filetypes'] = [('Comma-Seperated Values', '.csv'),
('ASCII-File','.asc'),
('Normal Text File','.txt')]
options['initialdir'] = 'C//'
options['initialfile'] = ''
options['parent'] = self
options['title'] = 'MCR-ALS Data Preprocessing'
return(options)
''' Methods (bindings) for PageOne '''
def open_button(self):
self.get_directories()
''' Methods (functions) for PageOne '''
# UI, where the user can selected data, that shall be opened
def get_directories(self):
# open files
file_input = tkFileDialog.askopenfilenames(** self.file_opt)
file_input = sorted(list(file_input))
# create dictionary
file_input_dict = {}
file_input_dict["Input_Directories"] = file_input
self.push_directories(file_input_dict)
'''
###############################################################################
# View #
###############################################################################
'''
class StartPage(ttk.Frame):
''' Initialisations '''
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller = controller
self.labels()
self.buttons()
''' Widgets '''
def labels(self):
label = tk.Label(self, text = "This is the start page", font = font)
label.pack(side = "top", fill = "x", pady = 10)
def buttons(self):
button1 = ttk.Button(self, text = "Go to Page One",
command = lambda: self.controller.show_frame("PageOne"))
button2 = ttk.Button(self, text = "Go to Page Two",
command = lambda: self.controller.show_frame("PageTwo"))
button_close = ttk.Button(self, text = "Close",
command = lambda: app.destroy())
button1.pack(side = "top", fill = "x", pady = 10)
button2.pack(side = "top", fill = "x", pady = 10)
button_close.pack(side = "top", fill = "x", pady = 10)
class PageOne(ttk.Frame):
''' Initialisations '''
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller = controller
self.labels()
self.buttons()
self.combobox()
''' Widgets '''
def labels(self):
label = tk.Label(self, text = "On this page, you can read data", font = font)
label.pack(side = "top", fill = "x", pady = 10)
def buttons(self):
button_open = ttk.Button(self, text = "Open",
command = lambda: self.controller.open_button())
button_forward = ttk.Button(self, text = "Next Page >>",
command = lambda: self.controller.show_frame("PageTwo"))
button_back = ttk.Button(self, text = "<< Go back",
command = lambda: self.controller.show_frame("StartPage"))
button_home = ttk.Button(self, text = "Home",
command = lambda: self.controller.show_frame("StartPage"))
button_close = ttk.Button(self, text = "Close",
command = lambda: app.destroy())
button_open.pack(side = "top", fill = "x", pady = 10)
button_forward.pack(side = "top", fill = "x", pady = 10)
button_back.pack(side = "top", fill = "x", pady = 10)
button_home.pack(side = "top", fill = "x", pady = 10)
button_close.pack(side = "top", fill = "x", pady = 10)
def combobox(self):
entries = ("", "Inputformat_01", "Inputformat_02", "Inputformat_03")
combobox = ttk.Combobox(self, state = 'readonly', values = entries,
textvariable = self.controller.shared_keys["Inputformat"])
combobox.current(0)
combobox.bind('<<ComboboxSelected>>', self.updater)
combobox.pack(side = "top", fill = "x", pady = 10)
''' Bindings '''
# wrapper, which notifies the controller, that it can update keys in Model
def updater(self, event):
self.controller.push_keys()
class PageTwo(ttk.Frame):
''' Initialisations '''
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller = controller
self.labels()
self.buttons()
self.combobox()
''' Widgets '''
def labels(self):
label = tk.Label(self, text = "This is page 2", font = font)
label.pack(side = "top", fill = "x", pady = 10)
def buttons(self):
button_back = ttk.Button(self, text = "<< Go back",
command = lambda: self.controller.show_frame("PageOne"))
button_home = ttk.Button(self, text = "Home",
command = lambda: self.controller.show_frame("StartPage"))
button_close = ttk.Button(self, text = "Close",
command = lambda: app.destroy())
button_back.pack(side = "top", fill = "x", pady = 10)
button_home.pack(side = "top", fill = "x", pady = 10)
button_close.pack(side = "top", fill = "x", pady = 10)
def combobox(self):
entries = ("Outputformat_01", "Outputformat_02")
combobox = ttk.Combobox(self, state = 'readonly', values = entries,
textvariable = self.controller.shared_keys["Outputformat"])
combobox.bind('<<ComboboxSelected>>', self.updater)
combobox.pack(side = "top", fill = "x", pady = 10)
''' Bindings '''
# wrapper, which notifies the controller, that it can update keys in Model
def updater(self, event):
self.controller.push_keys()
if __name__ == "__main__":
app = PageControl()
app.mainloop()
你的問題很難理解。我建議刪除「編輯」和「重新編輯」和「重新編輯」部分。我不在乎你編輯過多少次。只是重申整個問題而不是追加附錄。你可以刪除問題中3/4的單詞,並且仍然可以解決問題。 –