QComboBox редактировать LineEdit, когда PopUp активен
У меня есть QComboBox, заполненный некоторыми данными. Я хочу отредактировать lineEdit comboBox, и когда я делаю это, чтобы comboBox отображал его всплывающее окно во время редактирования. Проблема в том, что я потерял фокус на редактировании строки, и я могу написать только одно письмо за раз.
Это то, что я делаю на тривиальном уровне:
ui->comboBox->addItem("This");
ui->comboBox->addItem("is");
ui->comboBox->addItem("a");
ui->comboBox->addItem("comboBox");
ui->comboBox->setEditable(true);
connect(ui->comboBox, SIGNAL(currentTextChanged(QString)), this, SLOT(PrintTextLineEdit(QString)));
void MainWindow::PrintTextLineEdit(QString str)
{
ui->comboBox->showPopup();
ui->comboBox->lineEdit()->setFocus();
}
Также, если я использую blockSignal на lineEdit, пока я показываю, всплывающее окно бесполезно. Какие-либо предложения?
РЕДАКТИРОВАТЬ
Кажется, мне нужно предоставить некоторые дополнительные детали. Я должен быть в состоянии написать целое слово за раз, не теряя фокус, когда я использую ui->comboBox->showPopUp()
в currentTextChanged
сигнал.
Или, проще говоря: курсор не должен исчезать из QLineEdit после того, как сигнал испущен и всплывающее окно отображается.
5 ответов
Вы должны получить свой собственный класс поля со списком из QComboBox
и переопределить showPopup()
виртуальный метод, чтобы вернуть фокус обратно на строку редактирования.
void CMyComboBox::showPopup()
{
QComboBox::showPopup();
// Put the focus back later, after all pending events are processed.
QTimer::singleShot(0, [this](){ lineEdit()->setFocus(); });
}
В особом случае время QTimer с таймаутом 0 истечет, как только будут обработаны все события в очереди событий оконной системы.
РЕДАКТИРОВАТЬ:
Это работает (хотя можно считать это взломом):
class CMyComboBox : public QComboBox
{
public:
CMyComboBox(QWidget* parent)
: QComboBox(parent)
{
view()->installEventFilter(this);
}
// Event filter forwards view key events to the line edit.
bool eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
QKeyEvent* newEvent = new QKeyEvent(keyEvent->type(), keyEvent->key(), keyEvent->modifiers(),
keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count());
QFocusEvent* focusEvent = new QFocusEvent(QEvent::FocusIn, Qt::OtherFocusReason);
QCoreApplication::postEvent(lineEdit(), focusEvent);
QCoreApplication::postEvent(lineEdit(), newEvent);
}
return false;
}
};
Но лично я бы, наверное, использовал отдельный QMenu
для отображения списка слов, а не всплывающее меню со списком.
Каждый комбинированный список имеет значение по умолчанию QCompleter
это может показать варианты завершения во всплывающем окне. Я думаю, что вы можете достичь того, что вы хотите, установив этот режим завершения PopupCompletion
,
ui->comboBox->completer()->setCompletionMode(QCompleter::PopupCompletion);
В этом случае в поле со списком будут отображаться соответствующие варианты при вводе. Если вы хотите, чтобы он перечислял все элементы комбинированного списка, я думаю, что вы должны реализовать собственный QCompleter, который соответствует всем элементам независимо от того, какие пользовательские типы.
Ваша проблема вызвана
grabKeyboard
. Клавиатура захватывается всплывающими окнами, поэтому решение простое, просто установите редактирование для повторного захвата клавиатуры, используя
grabKeyBoard()
Когда я смотрю в коде QCombobox, я вижу следующее внутри кода showPopup:
container->show();
container->updateScrollers();
view()->setFocus(); // <<-- focus command here
view()->scrollTo(view()->currentIndex(),
style->styleHint(QStyle::SH_ComboBox_Popup, &opt, this)
? QAbstractItemView::PositionAtCenter
: QAbstractItemView::EnsureVisible);
Так что, возможно, если вы выполните следующее (здесь не тестировалось), вы можете получить желаемый результат:
ui->comboBox->addItem("This");
ui->comboBox->addItem("is");
ui->comboBox->addItem("a");
ui->comboBox->addItem("comboBox");
ui->comboBox->setEditable(true);
ui->comboBox->view()->setFocusPolicy(Qt::FocusPolicy::NoFocus); // don't allow focusing of the view of the popup
connect(ui->comboBox, SIGNAL(currentTextChanged(QString)), this, SLOT(PrintTextLineEdit(QString)));
void MainWindow::PrintTextLineEdit(QString str)
{
ui->comboBox->showPopup();
ui->comboBox->lineEdit()->setFocus();
}
Стоит попробовать.
С использованиемQCompleter
особенностьQLineEdit
может быть лучшим/менее хакерским решением:
QStringListModel *model; // or another QAbstractItemModel
model->setStringList({"This", "is", "a", "combobox"});
QLineEdit *lineEdit;
lineEdit->setCompleter(new QCompleter(model, lineEdit));
lineEdit->completer()->setFilterMode(Qt::MatchContains); // set filter mode as desired
Всплывающее окно будет показано, как только пользователь начнет редактировать строку редактирования. Единственным недостатком этого подхода является отсутствие раскрывающегося значка для отображения всех возможных (нефильтрованных) элементов.