Поясню ответ выше: насколько я знаю, графические интерфейсы строго однопоточны. Как минимум под Windows это так, а потому ни один графический фреймворк не поддерживает обращение к окнам и их элементам из других потоков.
Как следствие, если ты хочешь организовать фоновый поток с "обратной связью" в GUI, обычно требуется использовать очередь, например,
queue.Queue. В эту очередь фоновый поток должен класть сообщения, объясняющие, что надо сделать - например, сведения о прогрессе операции, или команды на смену состояния, или ещё что. Это зависит от твоей задачи.
Тогда основной поток программы, который и отвечает за GUI, должен использовать средства фреймворка для периодической проверки очереди на предмет сообщений. Например, в обычном tkinter это будет реализовано через метод after().
Если в очереди есть сообщения, основной поток читает их и выполняет соответствующие действия - например, меняет положение прогресс-бара, включает/выключает кнопки, и т.д.
Если фоновый (рабочий) поток живёт долго, то может иметь смысл организовать вторую очередь для передачи команд из GUI-потока в рабочий. Идея та же самая: рабочий поток ждёт появления команды в своей входной очереди, и выполняет её, а потом сбрасывает уведомления в исходящую очередь.