2016-08-02 3 views
1

У меня есть основной файл, который содержит в основном GUI (код Tkinter). Окно, которое имеет Label, область Text, где текст обновляется при действии пользователей и Button.Python: как получить доступ к атрибуту класса из модуля

# ~/main.py 
import Tkinter 
import buttonevent 
from itertools import cycle 

msglist = ['main_msg1\n', 'main_msg2\n', 'main_msg3\n', 'main_msg4\n'] 


class Root(object): 

    def __init__(self, master): 
     self.msglist = cycle(msglist) 
     self.master = master 
     self.frame1 = Tkinter.Frame(master) 
     self.frame1.pack() 
     Root.status = Tkinter.StringVar() 
     self.status_info = Tkinter.Label(self.frame1, textvariable=Root.status) 
     self.status_info.pack() 
     Root.status.set("Set by constructor") 

     self.frame2 = Tkinter.Frame(master) 
     self.frame2.pack() 
     Root.textinfo = Tkinter.Text(self.frame2, width=20, height=10) 
     Root.textinfo.insert(Tkinter.END, 'message 1') 
     Root.textinfo.config(font='Arial') 
     Root.textinfo.pack() 
     Root.textinfo.config(bg=master.cget('bg'), relief=Tkinter.SUNKEN) 
     Root.textinfo.configure(state='disabled') 

     self.frame3 = Tkinter.Frame(master) 
     self.frame3.pack() 
     self.button = Tkinter.Button(self.frame3, text='Ok', command=self.ok) 
     self.button.pack() 

    def ok(self): 
     text_info(self.msglist.next()) 
     buttonevent.do_event() 
     buttonevent.do_stuff() 


def text_info(msg): 
    Root.textinfo.configure(state='normal') 
    Root.textinfo.insert(Tkinter.END, msg) 
    Root.textinfo.see(Tkinter.END) 
    Root.textinfo.configure(state='disabled') 


if __name__ == '__main__': 
    root = Tkinter.Tk() 
    main_window = Root(root) 
    root.mainloop() 

Действия пользователя определены в другом файле.

# ~/buttonevent.py 

from itertools import cycle 
import main 

do_msg = ['do_msg1\n', 'do_msg2\n', 'do_msg3\n', 'do_msg4\n'] 
msg = cycle(do_msg) 


def do_event(): 
    # do something 
    main.text_info(msg.next()) 


def do_stuff(): 
    # do something 
    print 'doing stuff' 

Ранее код находился в одном файле, теперь я пытаюсь записать его как несколько файлов на основе его функциональности. В основном, когда пользователь делает что-то, сообщение будет отображаться на области Text. Так как поле Text отображает сообщение и имеет некоторую общность при каждом отображении/активности/обновлении, я создал для него функцию как text_info в основном файле.

Скажите, если я хочу отправить другое сообщение в поле Text для обновления из другого файла, например из файла buttonevent.py, как я могу его достичь.

, когда я запускаю его я получаю сообщение об ошибке, как

$ python main.py 
do_msg1 

Exception in Tkinter callback 
Traceback (most recent call last): 
    File "/home/miniconda2/lib/python2.7/lib-tk/Tkinter.py", line 1537, in __call__ 
    return self.func(*args) 
    File "main.py", line 38, in ok 
    buttonevent.do_event() 
    File "/home/buttonevent.py", line 14, in do_event 
    main.text_info(xx) 
    File "/home/main.py", line 51, in text_info 
    Root.textinfo.configure(state='normal') 
AttributeError: type object 'Root' has no attribute 'textinfo' 
  1. Как вызвать функцию в главном PY-файла из другого PY-файла.
  2. , что это лучший способ, Должен ли я использовать в class или function для text_info в main.py файле
  3. Если это не правильный путь к коду, пожалуйста, поправьте меня.
+0

'textinfo' является атрибутом класса, который не установлен, пока вы не инициализирована по крайней мере один экземпляр класса Root .. Вам нужно создать экземпляр класса Root в исходном файле перед вами может использовать функцию text_info. Код в методе '__init__' никогда не выполняется, если не создается экземпляр хотя бы одного объекта. Ага. Проблема в том, что у вас есть 'if __name__ == '__main __':', что означает, что все после этого не будет выполняться при импорте main ... –

ответ

1

Вы можете добиться того, что вы хотите, давая ссылку экземпляра Root в качестве параметра ваши функции:

Вместо присвоения класса Root:

Root.status = Tkinter.StringVar() 

Назначают его в Корневой экземпляр:

self.status = Tkinter.StringVar() 

Нет причин назначать его классу Root вместо экземпляра self, поскольку его Владение также является частью экземпляра Root: это компоненты экземпляра Root (части Tkinter), которые запускают событие для обновления. Вы могли бы дать себя в качестве параметра вашей buttonevent:

def ok(self): 
    text_info(self.msglist.next()) 
    buttonevent.do_event(self) 
    buttonevent.do_stuff(self) 

И тогда вы можете сделать text_info часть вашего класса:

class Root(object): 

    ... 

    def text_info(self, msg): 
     self.textinfo.configure(state='normal') 
     self.textinfo.insert(Tkinter.END, msg) 
     self.textinfo.see(Tkinter.END) 

И изменить buttonevent к этому:

def do_event(root_instance): 
    # do something 
    root_instance.text_info(msg.next()) 
1

Все «Корень». изменено как «я». main.py

# ~/main.py 
import Tkinter 
import buttonevent 
from itertools import cycle 
curwin=None 
msglist = ['main_msg1\n', 'main_msg2\n', 'main_msg3\n', 'main_msg4\n'] 
class Root(object): 

    def __init__(self, master): 
     self.msglist = cycle(msglist) 
     self.master = master 
     self.frame1 = Tkinter.Frame(master) 
     self.frame1.pack() 
     self.status = Tkinter.StringVar() 
     self.status_info = Tkinter.Label(self.frame1, textvariable=self.status) 
     self.status_info.pack() 
     self.status.set("Set by constructor") 
     self.curmsg='message 1\n' 
     self.frame2 = Tkinter.Frame(master) 
     self.frame2.pack() 
     self.textinfo = Tkinter.Text(self.frame2, width=20, height=10) 
     self.textinfo.insert(Tkinter.END, 'message 1\n') 
     self.textinfo.config(font='Arial') 
     self.textinfo.pack() 
     self.textinfo.config(bg=master.cget('bg'), relief=Tkinter.SUNKEN) 
     self.textinfo.configure(state='disabled') 

     self.frame3 = Tkinter.Frame(master) 
     self.frame3.pack() 
     self.button = Tkinter.Button(self.frame3, text='Ok', command=self.ok) # "Ok" function defined for click event 
     self.button.pack() 

    def ok(self): 
     #self.text_info(buttonevent.curmsg) 
     self.textinfo.configure(state='normal') 
     self.textinfo.insert(Tkinter.END, buttonevent.curmsg) # get message from buttonevent.py and set for window. Fisrst clicking will get initalized curmsg value. if you want get value after click write buttonevent.do_event() above this codes. 
     self.textinfo.see(Tkinter.END) 
     self.textinfo.configure(state='disabled') 
     buttonevent.do_event() # calling buttonevent's do_event function so it means global message will be changed. next click you will see new value for message. 
     buttonevent.do_stuff() 

if __name__ == '__main__': 
    root = Tkinter.Tk() 
    curwin=Root(root) 
    root.mainloop() 

buttonevent.ру

# ~/buttonevent.py 

from itertools import cycle 
import main 

do_msg = ['do_msg1\n', 'do_msg2\n', 'do_msg3\n', 'do_msg4\n'] 
msg = cycle(do_msg) 
curmsg=msg.next() # Add this variable to call main.py to first click event 

def do_event(): 
    # do something 
    global curmsg #to edit variable value you must call it as global 
    curmsg=msg.next() #Changing variable value for each click 
    #Removed text_info function from main.py it is not necessary. 
def do_stuff(): 
    # do something 
    print 'doing stuff' 
+0

ваш ответ будет намного лучше, если вы объясните, что изменили. В противном случае мы вынуждены читать ваш код за строкой, сравнивая каждую строку с оригиналом. –

+0

Функция text_info не нужна, вы можете удалить эту функцию. – redratear

+0

Ваша проблема в переменной передаче. Я добавил переменную curmsg в скрипт buttonevent.py. и назовите его в функции «ok» класса Root как «buttonevent.curmsg». и удалите любой вызов функции из функции do_event в скрипте buttonevent.py, поскольку вы определили событие click как «Ok» в инициализации класса Root. Поэтому при нажатии кнопки «ok» функция вызывает currentmsg из сценария buttonevent. – redratear

Смежные вопросы