Как починить криво отражающийся текст в QPlainTextEdit в PyQt?
Немного контекста:
Приложение разбито на классы интерфейса, управления и внутренней логики. Они соединены с помощью паттерна "наблюдатель". Логика запускается в отдельном потоке через QThreadPool в классе управления. Периодически класс логики посылает сообщения интерфейсу, которые отображаются в QLineEdit и QPlainTextEdit, совсем не так, как надо. Так же, параллельно запущен поток, в котором происходит отслеживание нажатия сочетания клавиш. Если изменить размер интерфейса (потянув за край) - текст приходит в норму.
Подозреваю, что проблема может быть в работе потоков, но не могу понять, в чём именно. Буду очень признателен за помощь.
Реализация "наблюдателя":
class Observer(metaclass=ABCMeta):
@abstractmethod
def event_happened(self, text: str) -> None:
pass
class Observable(metaclass=ABCMeta):
def __init__(self):
self._list_observers: List[Observer] = []
def copy_list(self, list_observers: List[Observer]):
self._list_observers = list_observers
def get_list(self):
return self._list_observers
def attach(self, observer: Observer) -> None:
self._list_observers.append(observer)
def detach(self, observer: Observer) -> None:
if observer in self._list_observers:
self._list_observers.remove(observer)
def notify_event_happened(self, text: str) -> None:
for observer in self._list_observers:
observer.event_happened(text)
В дальнейшем Observer наследуется и метод event_happened определяется в каждом конкретном классе.
Ввод текст в QPlainTextEdit:
class View(QtWidgets.QMainWindow, view.Ui_MainWindow, Observer, metaclass=Meta):
...
def update_log(self, event: str) -> None:
self.text_log.appendPlainText(event)
self.text_log.update()
Запуск логики и отслеживания нажатия сочетания в отдельных потоках:
class Controller:
def __init__(self, model: Model):
...
self._threadpoll = PyQt5.QtCore.QThreadPool()
def start_request(self) -> None:
self.update_model()
self._threadpoll.start(self._model.start)
self._threadpoll.start(self._model.wait_signal_about_escape)
Ответы (1 шт):
С виджетами нельзя работать на прямую из потоков, отличных от потока UI.
Для обхода этого ограничения нужно использовать очереди событий.
Попробуйте так:
class View(QtWidgets.QMainWindow, view.Ui_MainWindow, Observer, metaclass=Meta):
update_log = Signal(str)
def _init__(self, ...):
# ....
self.update_log.connect(self.do_update_log)
#...
def event_happened(self, text: str) -> None:
self.update_log.emit(text)
@Slot(str)
def do_update_log(self, event: str) -> None:
self.text_log.appendPlainText(event)
self.text_log.update()
"Синтаксис" сигналов/слотов из PySide2: для PyQt5 нужно будет объявить псевдонимы:
from PyQt5.QtCore import \
pyqtSlot as Slot, pyqtSignal as Signal
