Извлечение переменной из другого класса - PullRequest
0 голосов
/ 01 октября 2018

Я программирую графический интерфейс с использованием Tkinter.В одном из классов я определил переменную (entry_filename) и хотел бы использовать ее в другом классе.Часть кода выглядит следующим образом:

class Loginpage(tk.Frame,Search):


    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        self.controller=controller
        self.label_user=tk.Label(self, text="Username")
        self.label_user.grid(row=0, column=0)
        self.label_pass=tk.Label(self, text="Password")
        self.label_pass.grid(row=1, column=0)

        self.entry_user=tk.Entry(self)
        self.entry_user.focus_set()
        self.entry_user.grid(row=0, column=1)

        self.entry_pass=tk.Entry(self,show="*")
        self.entry_pass.grid(row=1, column=1)


        self.button=ttk.Button(self, text="Login",command= self.Logincheck)
        self.button.grid(columnspan=2)

    def Logincheck(self):
        global username
        global password
        try:
            username=self.entry_user.get()
            password=self.entry_pass.get()

            self.ssh = paramiko.SSHClient()
            self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

            self.ssh.connect(server, username=username, password=password)#input your username&password
            button1 = ttk.Button(self, text="Click to Continue",command= lambda: self.controller.show_frame(Inputpage))
            button1.grid(columnspan=2)
        except:
            tm.showerror("Login error", "Incorrect username/password")


class Inputpage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller=controller

        self.filein_label=tk.Label(self,text="Input file name")
        self.filein_label.grid(row=0,column=0)

        self.entry_filename=tk.Entry(self)
        self.entry_filename.focus_set()
        self.entry_filename.grid(row=0,column=1)

        self.button1 = ttk.Button(self, text="Click to Continue",command= lambda: self.controller.show_frame(Graphpage))
        self.button1.grid(columnspan=2)


class Graphpage(tk.Frame,Inputpage):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller=controller
        self.label = tk.Label(self, text="Graph Page!", font=LARGE_FONT)
        self.label.pack(pady=10,padx=10)

        button1 = ttk.Button(self, text="Back to Input Page",command=lambda: self.controller.show_frame(Inputpage))
        button1.pack()

        filename=Inputpage.entry_filename.get()

Graphpage вызывает имя файла переменной, которое позже используется для создания графика (эта часть кода здесь опущена).При выполнении кода возвращается следующая ошибка:
Ошибка типа: не удается создать согласованный порядок разрешения методов (MRO) для баз Frame, Inputpage

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

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

Виноват в том, что вы не должны совместно использовать переменные-члены класса.

Если разные классы совместно используют некоторые общие данные, эти данные, вероятно, являются другим классом, и они могут наследовать его.

class CommonData():
    client = 100


class A(CommonData):
    def __init__(self):
        print(A.client)

class B(CommonData):
    def __init__(self):
        print(B.client)

a = A()
b = B()

CommonData.client = 300

print(a.client)
print(b.client)

В приведенном выше случае каждый экземпляр A и каждый экземпляр B совместно используют все переменные класса CommonData, например client.

CommonData.client = 400

class C():
    pass

Вы также можете использовать множественное наследование.определите все общие данные как атрибуты CommonData и используйте CommonData как класс для хранения данных, как в примере выше, не создавайте экземпляры из него:

class D(C, CommonData):
    def __init__(self):
        print(D.client)

c = C()
d = D()

Более простой вариант - просто определить переменную CommonDataво внешней области и используйте его из любого места:

common_data = 500

class A():
    def __init__(self):
        global common_data
        print(common_data)
        common_data = 200
        # ... 

Но глобальные переменные, как правило, считаются плохой вещью в программе, поскольку их использование может стать проблемой по нескольким причинам.

ПокаДругой способ - передать переменную инициализатору объекта.Это заставляет экземпляр сохранять свое собственное значение, скопированное из значения создания:

common_data = 600

class A():
    def __init__(self, data):
        self.common = data
        print(self.common)

a = A(common_data)
common_data = 0
print(a.common)

Если вы запустите весь приведенный выше код, он напечатает

100
100
300
300
400
600
600

Редактировать:

Смотрите мой комментарий к вашему ответу и простой пример здесь.Здесь я выбираю две глобальные ссылки на tkinter StringVars.Строковые переменные сами существуют в пространстве имен Tk (), как виджеты;кроме того, они являются глобальными именами Python.

import tkinter as tk
from tkinter import ttk



class Page1(tk.Toplevel):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.title('Page1')
        self.label1 = ttk.Label(self, text='Filename:')
        self.entry1 = ttk.Entry(self, textvariable=input_file1)
        self.label1.pack(side=tk.LEFT)
        self.entry1.pack()


class Page2(tk.Toplevel):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.title('Page2')
        self.label1 = ttk.Label(self, text='Filename:')
        self.entry1 = ttk.Entry(self, textvariable=input_file2)
        self.button1 = ttk.Button(self, text='Copy Here', command=copy_filename)
        self.label1.pack(side=tk.LEFT)
        self.entry1.pack(side=tk.LEFT)
        self.button1.pack()

def copy_filename():
    input_file2.set(input_file1.get())

root = tk.Tk() # has to exist for the StringVars to be created
root.iconify()
input_file1 = tk.StringVar()
input_file2 = tk.StringVar()

page1 = Page1(root)
page2 = Page2(root)
root.mainloop()

Теперь в следующем примере показано, как я превращаю строковые переменные в переменные экземпляров Page1 и Page2 (не классов), делая их локальными, а не глобальными.Затем я вынужден передать ссылку на объект виджета page1 в объект виджета page2.

Это выглядит ближе к тому, что вы спрашиваете.

О проблеме MRO, если вы избежите множественного наследования, этого не произойдет.

Или вы обычно справляетесь с этимиспользование super()

В вашем случае ошибка заключается в том, что вы сохраняете виджет в объекте / экземпляре (в self.somename), а затем пытаетесь вызвать метод виджета, соответствующий названию класса.В классе нет виджета, чтобы вы могли использовать метод.

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

Обратите внимание, что я не использовал множественное наследование, поэтому я мог бы просто написать tk.Frame. вместо вызова super.Мне нравится super, потому что в тексте ясно, что я вызываю родительский класс, но super действительно нужен только тогда, когда есть несколько родителей и различные уровни подклассов (обычно образующие ромбовидную форму).

Теперь пример:

import tkinter as tk
from tkinter import ttk


class Page1(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)

        self.input_file1 = tk.StringVar()

        self.label1 = ttk.Label(self, text='Filename:')
        self.entry1 = ttk.Entry(self, textvariable=self.input_file1)
        self.label1.pack(side=tk.LEFT)
        self.entry1.pack()


class Page2(tk.Frame):
    # note the page1 reference being
    # passed to initializer and stored in a var
    # local to this instance:
    def __init__(self, parent, page1, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)

        self.page1 = page1

        self.input_file2 = tk.StringVar()

        self.label1 = ttk.Label(self, text='Filename:')
        self.entry1 = ttk.Entry(self, textvariable=self.input_file2)
        self.button1 = ttk.Button(self, text='Copy Here',
            command=self.copy_filename)
        self.label1.pack(side=tk.LEFT)
        self.entry1.pack(side=tk.LEFT)
        self.button1.pack()

    def copy_filename(self):
        # see how the page1 refernce is used to acess
        # the Page1 instance
        self.input_file2.set(page1.input_file1.get())

root = tk.Tk() # has to exist for the StringVars to be created

page1 = Page1(root)
page2 = Page2(root, page1) # pass a reference to page1 instance
page1.pack(side=tk.LEFT)
page2.pack(side=tk.LEFT)
root.mainloop()
0 голосов
/ 01 октября 2018

ssh является локальной переменной внутри функции LoginCheck, поэтому вы не можете получить ее из другого класса.Единственное, что можно сделать, это определить ssh как self.ssh, чтобы он был доступен через instance_of_Loginpage.ssh.Он будет работать только тогда, когда вы передадите экземпляр Loginpage в экземпляр Graphpage.Если вам нужен доступ к ssh-подключению из многих мест, я предлагаю создать еще один класс для обработки ssh (вы можете использовать Borg patter для его достижения).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...