Связывание графического интерфейса tkinter с функциями в другом модуле

#python #python-3.x #tkinter

#python #python-3.x #tkinter

Вопрос:

Я хочу связать графический интерфейс (1. modul) с функциями, которые находятся в другом модуле. В основном мне нужно связать графический интерфейс с программой.

Я создал очень простой пример:

модуль1:

 from modul2 import *
from tkinter import *


window = Tk()
window.title('Program')
window.geometry("300x300")

text_input= StringVar()

#result
result=Entry(window, textvariable=text_input)
result.place(x=6,y=15)

#Button
button=Button(window, text='X')
button.config(width=5, height=2, command=lambda: test())
button.place(x=10,y=70)

window.mainloop()
  

модуль2:

 import modul1

def test():
    global text_input
    text_input.set('hello')

  

ОЖИДАЕМЫЙ:
Эта программа должна написать «привет» в окне ввода после нажатия на кнопку.

РЕЗУЛЬТАТ: ОШИБКА:

 Exception in Tkinter callback
Traceback (most recent call last):
  File "C:UsersOndrejAppDataLocalProgramsPythonPython37-32libtkinter__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:/Users/Ondrej/Desktop/VUT FIT/IVSmodul1.py", line 17, in <lambda>
    button.config(width=5, height=2, command=lambda: test())
NameError: name 'test' is not defined
  

Кто-нибудь знает, в чем проблема?
Заранее благодарю вас за помощь.

Комментарии:

1. Вы можете поместить общие объекты в отдельный модуль, а import его — в любой другой модуль, которому требуется доступ к одному или нескольким из них. Импорт кэшируется в sys.modules , так что последующие import операции в другом модуле вернут кэшированный модуль.

Ответ №1:

Да, проблема, с которой вы на самом деле сталкиваетесь, связана с циклическим импортом. Modul1 импортирует Modul2, а Modul2 импортирует Modul1. способ, которым вы могли бы решить эту проблему, — предоставить textinput в качестве параметра тестовой функции в modul2 следующим образом:

modul1.py:

 import modul2
from tkinter import *


window = Tk()
window.title('Program')
window.geometry("300x300")

text_input = StringVar()

# result
result = Entry(window, textvariable=text_input)
result.place(x=6, y=15)

# Button
button = Button(window, text='X')
button.config(width=5, height=2, command=lambda: modul2.test(text_input))
button.place(x=10, y=70)

window.mainloop()

  

modul2.py:

 def test(text_input):
    text_input.set('hello')
  

К сожалению, python действительно не любит, когда вы выполняете циклический импорт, и это хорошо, поскольку это фактически означало бы бесконечный цикл. Когда это прекратит импорт другого файла?

Редактировать: был бы очень сложный способ создать класс в третьем модуле и установить для него атрибуты, а затем импортировать этот третий модуль как в modul1, так и в modul2 для совместного использования переменных между ними, но, пожалуйста, не делайте этого…

Edit2: пример этого:

Modul1.py:

 
from shared import SharedClass
import modul2
from tkinter import *


window = Tk()
window.title('Program')
window.geometry("300x300")

SharedClass.text_input = StringVar()

# result
result = Entry(window, textvariable=SharedClass.text_input)
result.place(x=6, y=15)

# Button
button = Button(window, text='X')
button.config(width=5, height=2, command=lambda: modul2.test())
button.place(x=10, y=70)

window.mainloop()
  

Modul2.py:

 from shared import SharedClass


def test():
    SharedClass.text_input.set('hello')

  

shared.py

 class SharedClass:
    pass
  

Это работает благодаря тому, как python загружает импортированные классы. Все они одинаковы. Это делает так, что если вы задаете свойства для класса (а не для его экземпляров), вы можете поделиться свойствами.

Комментарии:

1. Но как я должен использовать функцию без аргумента? Возможно ли это? Или если я хочу использовать эту функцию? Это работает только в том случае, если он находится в одном модуле def btnclick (numbers): global operator operator=operator str(numbers) text_input.set(operator) оператор определен в modul1 в данном случае как: operator=»»

2. вам нужно будет добавить этот оператор в качестве аргумента. Но я напишу небольшую реализацию того запутанного способа, о котором я упоминал. Это не очень по-питоновски, но, я думаю, это дополнит то, что вы хотите. Но в целом ответ таков: python не может делать такие вещи по-питоновски

3. Я отредактировал его, чтобы включить версию общего класса, которая является решением, аналогичным тому, что предлагает мартино, но без sys.modules

4. но, в конце концов, самый питонический способ — просто предоставить функции некоторые параметры. возможно, больше 1 для оператора

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