Запуск формы Tkinter в отдельном потоке

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

Вот мой модуль:

<code>import Image, ImageTk
import Tkinter


class Viewer(Tkinter.Tk):
    def __init__(self,parent):
        Tkinter.Tk.__init__(self,parent)
        self.parent = parent
        self.initialize()

    def initialize(self):
        self.grid()

    def show(self,img):
        self.to_display = ImageTk.PhotoImage(img)
        self.label_image = Tkinter.Label(self,image=self.to_display)
        self.label_image.grid(column = 0, row = 0, sticky = "NSEW")
        self.mainloop()
</code>

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

<code>import Image
from viewer import Viewer
import threading

def showimage(im):
    view = Viewer(None)
    view.show(im)

if __name__ == "__main__":
    im = Image.open("gaben.jpg")
    t = threading.Thread(showimage(im))
    t.start()
    print "Program keeps going..."
</code>

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

В любом случае, заранее спасибо за любую помощь.

редактировать: для ясности, я просто пытаюсь создать модуль, который будет отображать изображение в окне Tkinter, чтобы я мог использовать этот модуль в любое время, когда я хочу отобразить изображение. Проблема, с которой я сталкиваюсь, заключается в том, что когда программа использует этот модуль, она не может возобновить работу, пока окно Tkinter не закроется.

 SleepProgger21 окт. 2018 г., 09:57
Просто напишем о следующем посетителе или, возможно, OP через 6 лет: Основная проблема, кроме tkInter и threads, заключается в том, что & quot; threading.Thread (showimage (im)) & quot; не выполняет "showimage" в потоке, но вызывает "showimage (im)" и предоставляет return (None) в качестве аргумента конструктору Thread. & quot; Тема (target = частичная (showimage, im)) & quot; будет правильным создание потока мудрым.

Ответы на вопрос(4)

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

Главное предостережение в том, что рабочие не могут взаимодействовать с виджетами Tkinter. Они должны будут записывать данные в очередь, и ваш основной поток графического интерфейса должен будет опросить эту очередь.

Если все, что вы делаете, это показывает изображения, то вам, вероятно, вообще не нужна многопоточность. Потоки полезны только тогда, когда у вас есть длительный процесс, который в противном случае заблокировал бы графический интерфейс. Tkinter может легко обрабатывать сотни изображений и окон без единого пота.

 derricw12 мая 2012 г., 01:23
Большое спасибо за помощь с этим. Я знаю, что выглядишь глупо, но думаю, что ты упускаешь мою фундаментальную проблему Я не хочу, чтобы графический интерфейс вообще что-либо делал. Он делает именно то, что я хочу сделать, это просто отображать изображение. Я хочу, чтобы программа (второй блок выше) позволяла зрителю продолжать работу во время его работы (как я хочу каким-то образом добраться до строки оператора печати, не закрывая графический интерфейс).
 12 мая 2012 г., 00:59
@ballsdotballs: вам нужно позвонитьmainloop если вы намерены создать интерактивный графический интерфейс. По своей природе, поскольку вы запускаете цикл обработки событий, вам, скорее всего, не нужны потоки. Это правда, что после вызоваmainloop «Это никогда не будет продолжаться с [вашей] реальной программой», но именно так оно и рассчитано на работу. Вы устанавливаете цикл, тогда ваша программа просто реагирует на события.mainloop почти всегда самая последняя строка кода в логике запуска вашего приложения.
 derricw12 мая 2012 г., 00:50
Большое спасибо за совет. Я заметил, что если я запускаю self.mainloop () в модуле просмотра, как в приведенном выше примере, он никогда не продолжит работу с моей реальной программой до тех пор, пока окно не будет закрыто. Это делает то же самое, если я помещаю эту строку в программу (например, view.mainloop ()). Я думал, что размещение этой строки в отдельном потоке может решить проблему. Вы говорите, что я должен быть в состоянии сделать это без потоков, вы имеете в виду, что есть способ отобразить окно без mainloop ()?
 derricw12 мая 2012 г., 01:04
Я думаю, что проблема в том, что я просто хочу написать модуль, который отображает изображение. Мне нужен способ, чтобы моя программа продолжала работать после того, как она использует этот модуль, вместо того, чтобы ждать, пока пользователь закроет изображение. Ты имеешь в виду, что для этого нельзя использовать Tkinter?
 12 мая 2012 г., 01:13
@ballsdotballs: вообще ни один инструментарий GUI не работает так. Наборы инструментов GUI имеют циклы событий и отвечают на события. Тем не менее, вы можете запустить другой код после запуска цикла обработки событий, но пока этот код работает, ваш GUI зависнет. Не зная, что вы пытаетесь действительно достичь, трудно быть более конкретным. Я не знаю, поможет ли это, но поищу примеры использования tkinter.after метод. С его помощью вы можете попросить цикл обработки событий выполнить что-то в будущем, чтобы вы могли создать функцию с вашим дополнительным кодом, а затем запустить ее через несколько миллисекунд после вызова.mainloop

Из того, что я могу сказать, Tkinter не нравится играть в других темах. Смотрите этот пост ...Мне нужна небольшая помощь с Python, Tkinter и Threading

Обходной путь - создать (возможно скрытый) верхний уровень в вашем основном потоке, создать отдельный поток для открытия изображений и т. Д. - и использовать общую очередь для отправки сообщений обратно в поток Tk.

Требуется ли использовать Tkinter для вашего проекта? Мне нравится Ткинтер. Он "быстрый и грязный". - но есть (много) случаев, когда другие наборы GUI - путь.

 11 мая 2012 г., 20:29
Первая часть вашего ответа хороша, но я не могу поддержать, потому что советую попробовать другие наборы инструментов. Tkinter идеально подходит для того, о чем идет речь.
Решение Вопроса

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

На большинстве систем должна быть возможность запустить средство просмотра по умолчанию, используя что-то вроде этого:

import subprocess 

subprocess.Popen("yourimage.png")

Я попытался запустить tkinter из отдельного потока, не очень хорошая идея, он зависает. Есть одно решение, которое сработало. Запустите графический интерфейс в главном потоке и отправьте события в основной интерфейс. Это похожий пример, он просто показывает метку.

import Tkinter as t
global root;
root = t.Tk()
root.title("Control center")
root.mainloop()

def new_window(*args):
    global root
    print "new window"
    window = t.Toplevel(root)
    label = t.Label(window, text="my new window")
    label.pack(side="top", fill="both", padx=10, pady=10)
    window.mainloop()

root.bind("<<newwin>>",new_window)

#this can be run in another thread
root.event_generate("<<newwin>>",when="tail")

Ваш ответ на вопрос