Вопрос или проблема
Я пытаюсь создать систему автозавершения кода, подобную IntelliSense, внутри QPlainTextEdit с использованием PySide2. Однако у меня возникают проблемы с управлением фокусом и скрытием QListWidget, когда он появляется. Цель состоит в том, чтобы всплывающее окно появлялось, когда пользователь вводит текст, позволяя ему продолжать ввод в текстовый редактор, пока всплывающее окно видно, и скрывать его по мере необходимости (например, при нажатии клавиши Escape или перемещении курсора).
Вот основные проблемы, с которыми я сталкиваюсь:
Проблема с фокусом: я использую self.completer_list.setFocusPolicy(Qt.NoFocus), чтобы предотвратить получение фокуса всплывающим окном, но при использовании Qt.Popup фокус все равно сдвигается на QListWidget, и остальная часть программы становится неответственной, пока я не взаимодействую с всплывающим окном.
Проблема скрытия всплывающего окна: я использую self.completer_list.hide(), чтобы скрыть всплывающее окно, но оно не всегда скрывается должным образом или не реагирует хорошо, когда щелкаешь вне или когда курсор перемещается.
Что может быть не так в моем коде?
Это часть моего кода:
self.temp_completer_list = ["for", "while", "if", "else", "elif", "def",
"class", "import", "from", "return", "try", "except", "finally"]
self.completer_list = QListWidget()
self.completer_list.addItems(self.temp_completer_list)
self.completer_list.setWindowFlag(Qt.Popup)
self.completer_list.hide()
self.textChanged.connect(self.show_completer_list)
def show_completer_list(self):
"""КУРСОР ДЛЯ ВСПЛЫВАЮЩЕГО ОКНА"""
cursor = self.textCursor()
pos = self.cursorRect(cursor).bottomRight()
global_pos = self.mapToGlobal(pos)
self.completer_list.move(global_pos)
self.completer_list.show()
self.completer_list.setFocusPolicy(Qt.NoFocus)
Ответ или решение
Ваша задача состоит в том, чтобы создать систему автозаполнения кода в QPlainTextEdit с использованием PySide2, но вы сталкиваетесь с проблемами управления фокусом и скрытия виджета QListWidget. Давайте рассмотрим, как можно исправить эти проблемы.
Проблема управления фокусом
Ваша проблема с управлением фокусом может быть связана с тем, как QWidget обрабатывает всплывающие окна (Popup). Установка setFocusPolicy(Qt.NoFocus)
не всегда предотвращает переход фокуса на виджет. Вместо этого, можно использовать метод setWindowFlags
с Qt.Tool
или Qt.Window | Qt.FramelessWindowHint
, чтобы избежать проблем с фокусом.
Проблема скрытия всплывающего окна
Для корректного скрытия списка можно использовать сигналы. Например, добавьте обработчики для событий фокуса и кликов мыши. Вот пример того, как можно доработать ваш код.
Полный код с решением
from PySide2.QtWidgets import QApplication, QPlainTextEdit, QListWidget
from PySide2.QtCore import Qt, QPoint
class Editor(QPlainTextEdit):
def __init__(self):
super().__init__()
self.temp_completer_list = ["for", "while", "if", "else", "elif", "def",
"class", "import", "from", "return", "try",
"except", "finally"]
self.completer_list = QListWidget()
self.completer_list.addItems(self.temp_completer_list)
self.completer_list.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint) # Используйте эти флаги
self.completer_list.hide()
self.textChanged.connect(self.show_completer_list)
# Обработчики событий
self.completer_list.installEventFilter(self)
self.completer_list.mousePressEvent = self.completer_mouse_press_event
self.completer_list.focusOutEvent = self.completer_focus_out_event
def show_completer_list(self):
"""Показать список автозаполнения."""
cursor = self.textCursor()
if cursor.hasSelection():
return
pos = self.cursorRect(cursor).bottomRight()
global_pos = self.mapToGlobal(pos)
if self.completer_list.isHidden():
self.completer_list.move(global_pos)
self.completer_list.show()
else:
self.completer_list.hide()
def completer_mouse_press_event(self, event):
"""Обработчик события нажатия мыши для списка автозаполнения."""
super().mousePressEvent(event)
self.completer_list.hide() # Скрыть список при клике на текстовое поле
def completer_focus_out_event(self, event):
"""Обработчик события потери фокуса для списка автозаполнения."""
self.completer_list.hide() # Скрыть список при потере фокуса
super().focusOutEvent(event)
def keyPressEvent(self, event):
"""Обработка нажатия клавиш для скрытия списка при Escape."""
if event.key() == Qt.Key_Escape:
self.completer_list.hide()
else:
super().keyPressEvent(event)
if __name__ == "__main__":
app = QApplication([])
editor = Editor()
editor.show()
app.exec_()
Объяснение изменений:
-
Флаги окна: Установка
Qt.Tool | Qt.FramelessWindowHint
позволяет избежать проблем с фокусом во время работы с всплывающим окном. -
Обработчики событий: Мы добавили обработчики для обработки кликов мышью и потери фокуса. Это позволяет скрывать popup, когда взаимодействие происходит вне него или когда он теряет фокус.
-
Скрытие при Escape: Добавлен обработчик
keyPressEvent
, который скрывает всплывающее окно при нажатии клавишиEscape
.
Теперь ваше приложение должно корректно отображать popup с автозаполнением и управлять им без проблем с фокусом или скрытием.