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

Я пробовал label.destroy(), но, поскольку у меня уже есть метка, которая вызывает эту функцию, функция label.destroy() не работает.

from tkinter import *

root = Tk()

def testing(event):
    print("You have pressed a key.")
    root.unbind_all('<Key>')
    label.destroy() # There are two of these.


def countdown(count, label):
    label['text'] = count
    if count > -1:
        root.after(1000, countdown, count-1, label)
    elif count == 0:
        label['text'] = 'Time \nExpired'
    elif count < 0:
        label.destroy() # The second "label.destroy()"

# any_key = root.create_text(250, 400, anchor=CENTER, font=('Calibri', 20), text='Press any key to start.')
# I commented the previous line out because that was my previous code.

any_key = Label(root, anchor=CENTER, font=('Calibri', 20), text='Press any key to start.')
any_key.place(250, 400) # Error 2

root.bind('<Key>', testing)
label = Label(root, anchor=CENTER, font=('Calibri', 48))
label.place(x=50, y=100)
countdown(10, label)

root.bind_all('<Key>', testing)

root.pack()
root.mainloop()

Я надеялся, что эта программа удалит метку с именем any_key, но она даже не появилась до того, как я нажал клавишу. Кроме того, Tkinter показывает ошибку, которая отображает TypeError: place_configure() takes from 1 to 2 positional arguments but 3 were given, хотя я дал только 2 аргумента для размещения метки any_key. Если вы закомментируете any_key.place(), появится еще одна ошибка: Исключение в обратном вызове Tkinter

Traceback (most recent call last):
  File "C:\Users\kevin\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:\Users\kevin\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 749, in callit
    func(*args)
  File "C:\Users\kevin\AppData\Local\Programs\Python\Python37\Programs\Tests\test 8.py", line 22, in countdown
    label['text'] = count
  File "C:\Users\kevin\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1492, in __setitem__
    self.configure({key: value})
  File "C:\Users\kevin\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1485, in configure
    return self._configure('configure', cnf, kw)
  File "C:\Users\kevin\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1476, in _configure
    self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".!canvas.!label2"

Как мне исправить эти ошибки?

0
fasterthanlight 14 Апр 2019 в 16:51

2 ответа

Лучший ответ

После изменений, которые я описал в комментариях, я получаю рабочий код

place нужны аргументы с именами place(x=..., y=...)

root.pack() не будет работать - root не имеет метода pack(). Вы не можете поместить окно root в окно root.

Я также использую count > 0 вместо count > -1, и теперь он может проверять count == 0

from tkinter import *

def testing(event):
    print("You have pressed a key.")
    root.unbind_all('<Key>')
    label.destroy() # There are two of these.

def countdown(count, label):
    label['text'] = count
    if count > 0: # not -1
        root.after(1000, countdown, count-1, label)
    elif count == 0:
        label['text'] = 'Time \nExpired'
        # to destroy after 1s
        root.after(1000, countdown, count-1, label)
    elif count < 0:
        label.destroy() # The second "label.destroy()"

root = Tk()

any_key = Label(root, anchor=CENTER, font=('Calibri', 20), text='Press any key to start.')
any_key.place(x=250, y=400) # need x=, y=

label = Label(root, anchor=CENTER, font=('Calibri', 48))
label.place(x=50, y=100)
countdown(10, label)

root.bind_all('<Key>', testing)
#root.pack() # you try to put window `root` inside window `root`

root.mainloop()

Потому что вы можете уничтожить метку в testing() до окончания обратного отсчета, поэтому было бы неплохо сообщить countdown, что виджет не существует. Я буду использовать label = None для этого

def testing(event):
    global label

    print("You have pressed a key.")

    root.unbind_all('<Key>')

    if label is not None:
         label.destroy() # There are two of these.
         label = None


def countdown(count, label):
    global label

    if label is not None:
        label['text'] = count
        if count > 0: # not -1
            root.after(1000, countdown, count-1, label)
        elif count == 0:
            label['text'] = 'Time \nExpired'
            # to destroy after 1s
            root.after(1000, countdown, count-1, label)
        elif count < 0:
            label.destroy() # The second "label.destroy()"
            label = None
2
furas 14 Апр 2019 в 14:20

Для решения ERROR 2 вы должны сделать это:

any_key.place(x=250, y=400) # SOLVE ERROR

У меня также есть ошибка на это: "root.pack ()", потому что должно быть "label.pack ()"

Уничтожить два раза, потому что в двух строках «root.bind (', testing)» и «root.bind_all (' ', testing)» остается только одна.

Ошибка в консоли происходит из-за того, что два метода «тестирование» и «обратный отсчет» являются асинхронными, и поэтому обратный отсчет начинается перед тестированием и пытается что-то сделать на этикетке после его уничтожения. Поэтому вам нужно синхронизировать этот метод и поделиться состоянием метки (также с меткой == null)

from tkinter import *
import threading
import functools

root = Tk()
state = True

def synchronized(wrapped):
    lock = threading.Lock()
    @functools.wraps(wrapped)
    def _wrap(*args, **kwargs):
        print("Calling '%s' with Lock %s" % (wrapped.__name__, id(lock)))
        with lock:
            return wrapped(*args, **kwargs)
    return _wrap

@synchronized
def testing(event):
    global state
    print(event)
    print("You have pressed a key.")
    root.unbind_all('<Key>')
    state = False
    label.destroy() # There are two of these.

@synchronized
def countdown(count, label):
    global state
    print(count)
    print(state)
    if state: 
        label['text'] = count
        if count > 0:
            root.after(1000, countdown, count-1, label)
        elif count == 0:
            label['text'] = 'Time \nExpired'
        elif count < 0:
            label.destroy() # The second "label.destroy()"

# any_key = root.create_text(250, 400, anchor=CENTER, font=('Calibri', 20), text='Press any key to start.')
# I commented the previous line out because that was my previous code.

any_key = Label(root, anchor=CENTER, font=('Calibri', 20), text='Press any key to start.')
any_key.place(x=250, y=400) # SOLVE ERROR

root.bind('<Key>', testing)
label = Label(root, anchor=CENTER, font=('Calibri', 48))
label.place(x=50, y=100)
countdown(10, label)



label.pack() # SOLVE ERROR
root.mainloop()
-1
Nicola Landro 14 Апр 2019 в 14:49