qt自5.7.0版本后自带了qtvirtualkeyboard模块,在示例程序里面用过输入法demo,确实很赞,支持各国语言的输入法,中文输入法集成的google智能拼音,支持模糊拼音输入。很遗憾的是它只能在基于QML的应用平台上使用,在传统的Qt widgets应用上无法使用。
在Qt安装目录下qtvirtualkeyboard模块里面,可以找到google拼音源码,通过它来实现基于google拼音的中文输入法。把3rdparty目录下的pinyin文件夹拷贝到工程目录,并把里面的.h和.cpp文件添加到pinyin.pri模块中:
INCLUDEPATH += \
$$PWD/share \
$$PWD/include
SOURCES += \
$$PWD/share/dictbuilder.cpp \
$$PWD/share/dictlist.cpp \
$$PWD/share/dicttrie.cpp \
$$PWD/share/lpicache.cpp \
$$PWD/share/matrixsearch.cpp \
$$PWD/share/mystdlib.cpp \
$$PWD/share/ngram.cpp \
$$PWD/share/pinyinime.cpp \
$$PWD/share/searchutility.cpp \
$$PWD/share/spellingtable.cpp \
$$PWD/share/spellingtrie.cpp \
$$PWD/share/splparser.cpp \
$$PWD/share/sync.cpp \
$$PWD/share/userdict.cpp \
$$PWD/share/utf16char.cpp \
$$PWD/share/utf16reader.cpp \
$$PWD/googlepinyin.cpp
HEADERS += \
$$PWD/include/atomdictbase.h \
$$PWD/include/dictbuilder.h \
$$PWD/include/dictdef.h \
$$PWD/include/dictlist.h \
$$PWD/include/dicttrie.h \
$$PWD/include/lpicache.h \
$$PWD/include/matrixsearch.h \
$$PWD/include/mystdlib.h \
$$PWD/include/ngram.h \
$$PWD/include/pinyinime.h \
$$PWD/include/searchutility.h \
$$PWD/include/spellingtable.h \
$$PWD/include/spellingtrie.h \
$$PWD/include/splparser.h \
$$PWD/include/sync.h \
$$PWD/include/userdict.h \
$$PWD/include/utf16char.h \
$$PWD/include/utf16reader.h \
$$PWD/googlepinyin.h
在pinyin.pri模块添加新的文件googlepinyin.h,googlepinyin.cpp,用来封装google拼音调用接口,关键的接口函数如下:
using namespace ime_pinyin;
#define DICT_PATH "dict_pinyin.dat"
#define DICT_USER_PATH "dict_pinyin_user.dat"
// init dict database
bool pinyin_im::init(const QString &dir, int max_spell_len, int max_output_len)
{
bool ret;
QString app_dir = dir;
if (app_dir.isEmpty()) {
app_dir = qApp->applicationDirPath() + "/data";
}
ret = im_open_decoder(QString("%1/"DICT_PATH).arg(app_dir).toLocal8Bit().data(),
QString("%1/"DICT_USER_PATH).arg(app_dir).toLocal8Bit().data());
enable = ret;
if (ret == false) {
return ret;
}
im_set_max_lens(max_spell_len /* input pinyin max len */,
max_output_len /* max output Chinese character string len */);
reset_search();
spell_len = max_spell_len;
output_len = max_output_len;
return ret;
}
// add a char to search
unsigned pinyin_im::search(const QString &spell)
{
if (!enable)
{
return 0;
}
QByteArray bytearray;
char *pinyin;
bytearray = spell.toUtf8();
pinyin = bytearray.data();
bytearray.size();
size_t cand = im_search(pinyin, bytearray.size());
// if (im_get_fixed_len()) { // if fixed at least 1, candidate 0(whole line) is not display.
// cand--;
// }
cand = fix_cand_len(cand, output_len);
return (unsigned)cand;
}
init()是对google拼音字库文件进行初始化,在data文件下两个重要的文件
dict_pinyin.dat
dict_pinyin_user.dat
需要把包含这两个文件的的文件夹data放置在应用程序目录下。
程序主体实现部分代码:
bool PinYinInputMethod::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QMouseEvent::MouseButtonPress) {
if (watched->inherits("QPushButton")) {
QPushButton *btn = (QPushButton *)sender();
btn = (QPushButton *)watched;
QString objName = watched->objectName();
if (objName == "btn_Cn") {
//shift to En/Cn
}
else if (objName == "btn_ABC") {
//shift to ABC/123
}
else if (objName == "btn_Space") {
m_lineEdit->insert(" ");
}
else if (objName == "btn_<--") {
if (!inputLetters.isEmpty()) {
if (inputLetters.size() == 1) {
this->clearHistory();
}
else {
inputLetters = inputLetters.left(inputLetters.size() - 1);
if (!inputLetters.isEmpty()) {
this->searchBegin(inputLetters);
}
else {
m_lineEdit->backspace();
this->clearHistory();
}
}
}
else {
m_lineEdit->backspace();
this->clearHistory();
}
}
else if (objName == "btn_Enter") {
//shift to enter
}
else if (objName == "btn_Shift") {
//ABC to abc
}
else if (objName == "btn_down") {
if (mStackedWidget->currentWidget() == letterBtnWidget) {
if (!hQueryView->dataStrings.isEmpty()) {
vQueryView->dataStrings = hQueryView->dataStrings;
vQueryView->move(0, 0);
vQueryView->update();
mStackedWidget->setCurrentWidget(vDragWidget);
}
}
else {
mStackedWidget->setCurrentWidget(letterBtnWidget);
}
}
else {
inputLetters.append(btn->text());
this->searchBegin(inputLetters);
}
}
}
return QWidget::eventFilter(watched, event);
}
void PinYinInputMethod::searchBegin(const QString &keywords)
{
unsigned int candNum = googlePinyin->search(keywords.toLower());
hQueryView->dataStrings.clear();
for (unsigned i = 0; i < candNum; i++) {
QString str = googlePinyin->get_candidate(i);
hQueryView->dataStrings.append(str);
}
spellLabel->setText(keywords);
hQueryView->move(0, 0);
hQueryView->update();
}
功能做得很简单,主要通过searchBegin()函数调用google拼音,基本实现了中文拼音输入演示。