一个QLineEdit/QComboBox搜索忽略了变音符号



我有一个应用程序,人们可以在表单中输入地方的名称。这里是欧洲,我们必须处理的名字,包括变音标,如orl, Köln, li, ch teauroux。当人们输入名字时,我希望他们能够键入不带变音符号的字符,但仍然能够给出包含这些变音符号的名称列表,以便他们可以选择正确的重音名称。该程序有一个长但不详尽的名字列表(人们总是可以输入任何他们喜欢的名字)。

我已经有了一个基于非变音符匹配查找名称的函数。所以'orle'将返回' orl ', 'kol'将找到'Köln',等等。

我试了两件事:

1: A QLineEdit带有一个QCompleter,该QCompleter使用QStringListModel用匹配项填充补全器中的列表。不幸的是,这不起作用,因为列表将包含名称的重音版本,这与用户输入的值不匹配,因此QLineEdit不会在弹出框中显示名称(如果有的话)。

我还玩了一个QAbstractItemModel,直到我意识到QCompleter对模型返回的数据进行字符串匹配,所以再次'orle' != ' orl '。

2:一个可编辑的QComboBox,该列表根据到目前为止输入的文本动态填充。下面的代码是从QComboBox连接的::editTextChanged(QString):

void TripFormCargoHelper::fromEdited (const QString &str)
{
  if (str.length () >= 3)
  {
    QStringList flist = m_database->findLocationStrings (str);
    flist.push_front (str); // add the text we're editing first
    bool b = box->blockSignals (true); // prevent recursive signals
    box->clear ();
    box->addItems (flist);
    box->blockSignals (b);
    box->showPopup ();
  }
  else
  {
    box->clear ();
    box->hidePopup ();
  }

}

这有效,但只有一半…我希望弹出框出现时,一些字符已输入[1],但这将从行编辑的焦点。单击行编辑会关闭弹出窗口,所以我最终遇到了第22条军规(人们应该能够继续输入字符,缩小搜索范围)。

任何关于如何使这项工作的建议将不胜感激。我更喜欢QLineEdit的解决方案。版本为Qt 5.4

[1]应该是当我找到一些匹配,但是唉。

应该可以了:

QCompleter溶液。
创建继承QCompleter的类并重新实现QCompleter::splitPath:

DiacriticFreeCompleter::DiacriticFreeCompleter(QObject *parent)
    : QCompleter(parent)
{
}
QStringList DiacriticFreeCompleter::splitPath(const QString &path) const
{
    return QStringList() << ClearedFromDiacritic(path);
}
QString DiacriticFreeCompleter::pathFromIndex(const QModelIndex &index) const
{
    // needed to use original value when value is selected
    return index.data().toString();
}

现在crate数据模型包含所有城市(带有变音符号的单词),并在一些自定义角色编号下返回无变音符的字符串(子类QStringListModel可能是最简单的方法,只需重新实现data以专门处理此角色值):

DiactricFreeStringListModel::DiactricFreeStringListModel(QObject *parent)
    : QStringListModel(parent)
{
    setDiactricFreeRole(Qt::UserRole+10);
}
QVariant DiactricFreeStringListModel::data(const QModelIndex &index, int role) const
{
    if (role==diactricFreeRole()) {
        QString value = QStringListModel::data(index, Qt::DisplayRole).toString();
        return ClearedFromDiacritic(value);
    } else {
        return QStringListModel::data(index, role);
    }
}
void DiactricFreeStringListModel::setDiactricFreeRole(int role)
{
    mDiactricFreeRole = role;
}
int DiactricFreeStringListModel::diactricFreeRole() const
{
    return mDiactricFreeRole;
}

现在将这个模型与QCompleter连接,将这个特殊的角色值设置为completionRole,一切都应该完美地工作。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    DiacriticFreeCompleter *completer = new DiacriticFreeCompleter(this);
    DiactricFreeStringListModel *model = new DiactricFreeStringListModel(this);
    completer->setModel(model);
    completer->setCompletionRole(model->diactricFreeRole());
    model->setStringList(QStringList()
                         << "Kraków"
                         << "Łba"
                         << "Żarów"
                         << "Źródło"
                         << "Łęg"
                         << "London"
                         << "München"
                         << "Orléans"
                         << "Köln"
                         << "Liège"
                         << "Châteauroux");
    ui->lineEdit->setCompleter(completer);
}

我已经测试过了,效果很好。注意,在实践中,我粘贴了完整的代码(只是省略了一些明显的东西),所以解决方案非常简单。

谢谢Marek,我一直在拼命寻找这个,只有Python (PyQT5),所以我重写了这个,它像一个魅力。下面是代码:

import unicodedata
from PyQt5.QtCore import QStringListModel
from PyQt5.QtWidgets import QCompleter
from PyQt5.QtCore import Qt
def strip_accents(s):
    return ''.join(c for c in unicodedata.normalize('NFD', s)
        if unicodedata.category(c) != 'Mn')
class DiacriticFreeCompleter(QCompleter):
    def splitPath(self, path):
        return [strip_accents(path).lower()]
    def pathFromIndex(self, index):
        return index.data()

class DiactricFreeStringListModel(QStringListModel):
    def __init__(self, *args, **kwargs):
        super(DiactricFreeStringListModel, self).__init__(*args, **kwargs)
        self.setDiactricFreeRole(Qt.UserRole+10)
    def data(self, index, role):
        if role == self.diactricFreeRole():
            value = super(DiactricFreeStringListModel, self).data(index, Qt.DisplayRole)
            return strip_accents(value).lower()
        else:
            return super(DiactricFreeStringListModel, self).data(index, role)
    def setDiactricFreeRole(self, role):
        self.mDiactricFreeRole = role
    def diactricFreeRole(self):
        return self.mDiactricFreeRole;

相关内容

  • 没有找到相关文章

最新更新