Пример кода Tkinter для нескольких окон, почему кнопки не будут загружаться правильно?

Я пишу программу, которая должна:

  1. Откройте окно нажатием кнопки.
  2. Закройте новое открытое окно нажатием другой кнопки.

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

import tkinter as tk

class Demo1(tk.Frame):
    def __init__(self):
        tk.Frame.__init__(self)
        self.pack()
        self.master.title("Demo 1")
        self.button1 = tk.Button(self, text = "Button 1", width = 25,
                               command = self.new_window)
        self.button1.grid(row = 0, column = 1, columnspan = 2, sticky = tk.W+tk.E+tk.N+tk.S)

    def new_window(self):
        self.newWindow = Demo2()

class Demo2(tk.Frame):
    def __init__(self):
        new = tk.Frame.__init__(self)
        new = tk.Toplevel(self)
        new.title("Demo 2")
        new.button = tk.Button(text = "Button 2", width = 25,
                               command = self.close_window)
        new.button.pack()

    def close_window(self):
        self.destroy()

def main():
    Demo1().mainloop()

if __name__ == '__main__':
    main()

Ответ 1

Я переписал ваш код более организованным, более практичным способом:

import tkinter as tk

class Demo1:
    def __init__(self, master):
        self.master = master
        self.frame = tk.Frame(self.master)
        self.button1 = tk.Button(self.frame, text = 'New Window', width = 25, command = self.new_window)
        self.button1.pack()
        self.frame.pack()

    def new_window(self):
        self.newWindow = tk.Toplevel(self.master)
        self.app = Demo2(self.newWindow)

class Demo2:
    def __init__(self, master):
        self.master = master
        self.frame = tk.Frame(self.master)
        self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
        self.quitButton.pack()
        self.frame.pack()

    def close_windows(self):
        self.master.destroy()

def main(): 
    root = tk.Tk()
    app = Demo1(root)
    root.mainloop()

if __name__ == '__main__':
    main()

Результат:

Demo1 window Demo2 window

Ответ 2

Вам нужно указать мастер для второй кнопки. В противном случае он будет упакован в первое окно. Это необходимо не только для Button, но также для других виджетов и объектов, отличных от gui, таких как StringVar.

Быстрое исправление: добавьте фрейм new в качестве первого аргумента для вашего Button в Demo2.

Возможно, лучше: В настоящее время у вас есть Demo2 наследующий от tk.Frame, но я думаю, что это имеет смысл, если вы измените Demo2 на что-то вроде этого,

class Demo2(tk.Toplevel):     
    def __init__(self):
        tk.Toplevel.__init__(self)
        self.title("Demo 2")
        self.button = tk.Button(self, text="Button 2", # specified self as master
                                width=25, command=self.close_window)
        self.button.pack()

    def close_window(self):
        self.destroy()

Так же, как предложение, вы должны импортировать только tkinter один раз. Выберите одно из первых двух операторов импорта.

Ответ 3

#!/usr/bin/env python
import Tkinter as tk

from Tkinter import *

class windowclass():

        def __init__(self,master):
                self.master = master
                self.frame = tk.Frame(master)
                self.lbl = Label(master , text = "Label")
                self.lbl.pack()
                self.btn = Button(master , text = "Button" , command = self.command )
                self.btn.pack()
                self.frame.pack()

        def command(self):
                print 'Button is pressed!'

                self.newWindow = tk.Toplevel(self.master)
                self.app = windowclass1(self.newWindow)

class windowclass1():

        def __init__(self , master):
                self.master = master
                self.frame = tk.Frame(master)
                master.title("a")
                self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25 , command = self.close_window)
                self.quitButton.pack()
                self.frame.pack()


        def close_window(self):
                self.master.destroy()


root = Tk()

root.title("window")

root.geometry("350x50")

cls = windowclass(root)

root.mainloop()

Ответ 4

Я попытался использовать более двух окон, используя приведенный выше пример Rushy Panchal. Намерение состояло в том, чтобы иметь возможность вызывать больше окон с различными виджетами в них. Функция butnew создает разные кнопки для открытия разных окон. Вы передаете в качестве аргумента имя класса, содержащего окно (второй аргумент не нужен, я поставил его там только для проверки возможного использования. Может быть интересно наследовать из другого окна общие виджеты.

import tkinter as tk

class Demo1:
    def __init__(self, master):
        self.master = master
        self.master.geometry("400x400")
        self.frame = tk.Frame(self.master)
        self.butnew("Window 1", "ONE", Demo2)
        self.butnew("Window 2", "TWO", Demo3)
        self.frame.pack()

    def butnew(self, text, number, _class):
        tk.Button(self.frame, text = text, width = 25, command = lambda: self.new_window(number, _class)).pack()

    def new_window(self, number, _class):
        self.newWindow = tk.Toplevel(self.master)
        _class(self.newWindow, number)


class Demo2:
    def __init__(self, master, number):
        self.master = master
        self.master.geometry("400x400+400+400")
        self.frame = tk.Frame(self.master)
        self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
        self.label = tk.Label(master, text=f"this is window number {number}")
        self.label.pack()
        self.quitButton.pack()
        self.frame.pack()

    def close_windows(self):
        self.master.destroy()

class Demo3:
    def __init__(self, master, number):
        self.master = master
        self.master.geometry("400x400+400+400")
        self.frame = tk.Frame(self.master)
        self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
        self.label = tk.Label(master, text=f"this is window number {number}")
        self.label.pack()
        self.label2 = tk.Label(master, text="THIS IS HERE TO DIFFERENTIATE THIS WINDOW")
        self.label2.pack()
        self.quitButton.pack()
        self.frame.pack()

    def close_windows(self):
        self.master.destroy()




def main(): 
    root = tk.Tk()
    app = Demo1(root)
    root.mainloop()

if __name__ == '__main__':
    main()

Открывайте новое окно только один раз

Чтобы избежать возможности многократного нажатия кнопки с несколькими окнами..., которые являются одним и тем же окном, я создал этот скрипт (посмотрите эту страницу тоже)

import tkinter as tk


def new_window1():
    global win1
    try:
        if win1.state() == "normal": win1.focus()
    except:
        win1 = tk.Toplevel()
        win1.geometry("300x300+500+200")
        win1["bg"] = "navy"
        lb = tk.Label(win1, text="Hello")
        lb.pack()


win = tk.Tk()
win.geometry("200x200+200+100")
button = tk.Button(win, text="Open new Window")
button['command'] = new_window1
button.pack()
win.mainloop()

Ответ 5

Что вы можете сделать, это скопировать код из tkinter.py в файл с именем mytkinter.py, а затем сделать этот код:

import tkinter, mytkinter
root = tkinter.Tk()
window = mytkinter.Tk()
button = mytkinter.Button(window, text="Search", width = 7,
                               command=cmd)
button2 = tkinter.Button(root, text="Search", width = 7,
                               command=cmdtwo)

И у вас есть два окна, которые не сталкиваются!