Как очистить python tkinter windows/pygame windows?

У меня возникают проблемы при запуске кода в консоли Spyder3 IPython. Теперь я немного покопался в этом и пришел к выводу, что либо у меня проблемы с графикой, связанные с драйверами, либо с переадресацией X11, либо с чем-то еще.

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

Я надеюсь, что правильной очистки будет достаточно, потому что работа с любой из этих ошибок XCB или предупреждений GTK слишком сложна.

Мой вопрос: Как мне правильно очистить объекты окна tkinter, поверхности pygame и многопоточность? Ожидание: удалить все после закрытия окна, потому что это, безусловно, больше не требуется в этот момент или просто вызовет ошибки, если это сохраняется.

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

Вот пример сообщения об ошибке, которое я получаю при втором выполнении моей программы (первое выполнение работает правильно)

An error ocurred while starting the kernel
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi‑threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python3: ../../src/xcb_io.c:259: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
X Error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 2 (X_ChangeWindowAttributes)
Resource id in failed request: 0xe00008
Serial number of failed request: 75
Current serial number in output stream: 76
X Error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 2 (X_ChangeWindowAttributes)
Resource id in failed request: 0xe00008
Serial number of failed request: 75
Current serial number in output stream: 76
X Error of failed request: BadWindow (invalid Window parameter)
Major opcode of failed request: 2 (X_ChangeWindowAttributes)
Resource id in failed request: 0xe00008
Serial number of failed request: 75
Current serial number in output stream: 76

И вот код, который я тестирую:

import pygame as pg
import pygame.camera
import os
import threading as th

class Capture():
    def __init__(self, parent):
        os.environ['SDL_WINDOWID'] = parent
        pg.display.init()
        pg.camera.init()

        self.size = (640,480)
        self.display = pg.display.set_mode(self.size)
        self.display.fill(pg.Color(255,255,255))

        pg.display.update()

        self.clist = pg.camera.list_cameras()

        if not self.clist:
            raise ValueError('Sorry, no cameras detected.')
        print('Cameras: ', self.clist)    

        self.snapshot = pg.surface.Surface(self.size, 0, self.display)
    def feed(self, number):
        try:
            self.cam = pg.camera.Camera(self.clist[number], self.size)
        except IndexError:
            print('Provided Camera not available.')
        self.cam.start()
        self.thread = True
        self.t = th.Thread(name='Livefeed', target=self.live)
        self.t.start()
    def live(self):
        while self.thread:
            if self.cam.query_image():
                self.cam.get_image(self.snapshot)
            self.display.blit(self.snapshot, self.snapshot.get_rect())
            pg.display.update()
    def stop(self):
        self.thread = False
        self.t.join()
        self.cam.stop()

#for Camera DEBUG
if __name__ == '__main__':
    import tkinter as tk
    root = tk.Tk()
    embed = tk.LabelFrame(root, width=650, height=490)
    embed.grid(row=0, column=0)
    root.update()
    setup = Capture(str(embed.winfo_id()))
    buttons = tk.LabelFrame(root, width=100)
    buttons.grid(row=0, column=1)
    cam1 = tk.Button(buttons, text='Cam 1',
                     command=lambda: setup.feed(0), width=25)
    cam2 = tk.Button(buttons, text='Cam 2',
                     command=lambda: setup.feed(1), width=25)
    cam3 = tk.Button(buttons, text='Cam 3',
                     command=lambda: setup.feed(2), width=25)
    cam4 = tk.Button(buttons, text='Cam 4',
                     command=lambda: setup.feed(3), width=25)
    cam1.grid(row=0, columnspan=2)
    cam2.grid(row=1, columnspan=2)
    cam3.grid(row=2, columnspan=2)
    cam4.grid(row=3, columnspan=2)
    camStop = tk.Button(buttons, width=50, text='Feed Off',
                    command=lambda: setup.stop())
    camStop.grid(row=4, columnspan=2)
    root.mainloop()

person HackXIt    schedule 30.11.2017    source источник
comment
всегда указывайте ошибку текстом, а не скриншотом - никто не может скопировать текст со скриншота, чтобы использовать его.   -  person furas    schedule 30.11.2017
comment
Я не знаю, почему вы запускаете его в Spyder3 IPython. Естественный метод - запустить в системном терминале/консоли как python scriptname.py   -  person furas    schedule 30.11.2017
comment
проблемные швы могут быть thread - tkinter и pygame не являются потокобезопасными, поэтому не используйте их в двух потоках одновременно. Я вижу, вы начинаете pygame в основном потоке, но позже используете его в новом потоке. Возможно запустить все в новом потоке - начиная с pg.display.init()   -  person furas    schedule 30.11.2017
comment
@furas Отредактировано. Я запускаю его в Spyder3 IPython, потому что это хорошая среда разработки для разработки, так почему бы мне не использовать встроенную консоль Ipython? Я не считаю естественным запуск системного терминала во время разработки, что зависит от предпочтительной области разработки. Я постараюсь поместить pygame в отдельный поток. Однако почему это работает при первом выполнении? Разве первое выполнение не должно также вызывать ошибки, если это так?   -  person HackXIt    schedule 30.11.2017
comment
Кстати: код работает правильно в Linux, но я бы добавил код для кнопки закрытия, потому что теперь вы не останавливаете поток в конце. Как обработать событие закрытия окна в Tkinter?< /а>   -  person furas    schedule 30.11.2017
comment
что касается Spyder - попробуйте код в системной консоли, чтобы увидеть, проблема в коде или в Spyder.   -  person furas    schedule 30.11.2017
comment
Хорошо, да, выполнение в терминале выполняется правильно, за исключением уже известных ошибок, которые я пытаюсь исправить. Меня все еще интересует, как я могу убедиться, что когда выполнение в IPython заканчивается, это более или менее свежий IPython для повторного запуска кода.   -  person HackXIt    schedule 30.11.2017


Ответы (1)


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

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

def on_closing():
    print("stoping")
    setup.stop()
    print('destroy')
    root.destroy()

root.protocol("WM_DELETE_WINDOW", on_closing)  

root.mainloop()

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

def stop(self):
    if self.thread:
        self.thread = False
        self.t.join()
        self.cam.stop()

Требуется __init__

self.thread = False

Полный код

import pygame as pg
import pygame.camera
import os
import threading as th

class Capture():

    def __init__(self, parent):
        os.environ['SDL_WINDOWID'] = parent
        pg.display.init()
        pg.camera.init()

        self.size = (640,480)
        self.display = pg.display.set_mode(self.size)

        self.display.fill(pg.Color(255,255,255))
        pg.display.update()

        self.clist = pg.camera.list_cameras()

        if not self.clist:
            raise ValueError('Sorry, no cameras detected.')
        print('Cameras: ', self.clist)    

        self.snapshot = pg.surface.Surface(self.size, 0, self.display)

        self.thread = False

    def feed(self, number):
        try:
            self.cam = pg.camera.Camera(self.clist[number], self.size)
        except IndexError:
            print('Provided Camera not available.')

        self.cam.start()
        self.thread = True
        self.t = th.Thread(name='Livefeed', target=self.live)
        self.t.start()

    def live(self):
        while self.thread:
            if self.cam.query_image():
                self.cam.get_image(self.snapshot)
            self.display.blit(self.snapshot, self.snapshot.get_rect())
            pg.display.update()

    def stop(self):
        if self.thread:
            self.thread = False
            self.t.join()
            self.cam.stop()

#for Camera DEBUG
if __name__ == '__main__':
    import tkinter as tk

    root = tk.Tk()

    embed = tk.LabelFrame(root, width=650, height=490)
    embed.grid(row=0, column=0)
    root.update()
    setup = Capture(str(embed.winfo_id()))

    buttons = tk.LabelFrame(root, width=100)
    buttons.grid(row=0, column=1)

    cam1 = tk.Button(buttons, text='Cam 1',
                     command=lambda: setup.feed(0), width=25)
    cam2 = tk.Button(buttons, text='Cam 2',
                     command=lambda: setup.feed(1), width=25)
    cam3 = tk.Button(buttons, text='Cam 3',
                     command=lambda: setup.feed(2), width=25)
    cam4 = tk.Button(buttons, text='Cam 4',
                     command=lambda: setup.feed(3), width=25)
    cam1.grid(row=0, columnspan=2)
    cam2.grid(row=1, columnspan=2)
    cam3.grid(row=2, columnspan=2)
    cam4.grid(row=3, columnspan=2)
    camStop = tk.Button(buttons, width=50, text='Feed Off',
                    command=setup.stop)
    camStop.grid(row=4, columnspan=2)

    def on_closing():
        print('stoping')
        setup.stop()
        print('destroy')
        root.destroy()

    root.protocol("WM_DELETE_WINDOW", on_closing)  

    root.mainloop()

Кстати: вместо command=lambda:self.stop() вы можете сделать command=self.stop

person furas    schedule 30.11.2017
comment
Ах. Пропустил эту лямбду, исправлю. Я посмотрю полный код. - person HackXIt; 30.11.2017
comment
Я добавил/изменил операторы if для запуска, подачи и остановки. Итак, теперь он проверяет, запущен ли уже поток при запуске, подаче и остановке, что должно свести к минимуму ошибки при повторном нажатии кнопок. Мне все еще нужно проверить это внутри spyder3, но пока спасибо за вашу помощь. - person HackXIt; 30.11.2017
comment
Проблема все еще сохраняется в spyder3. X Error of failed request: BadWindow (invalid Window parameter) Major opcode of failed request: 2 (X_ChangeWindowAttributes) Resource id in failed request: 0xe00008 Serial number of failed request: 75 Current serial number in output stream: 76 - person HackXIt; 30.11.2017