dimanche 4 janvier 2009, par Nicolas
Pour permettre de saisir du japonais [1] sous un dialogue Qt [2], j’ai trouvé une solution à base de QInputContextFactory, classe donnant accès aux méthodes d’entrée [3] disponibles.
Et tant qu’à faire j’ai mis un menu contextuel dans la zone de saisie pour changer de méthode de saisie.
Conventions :
widget est la zone de saisie sur laquelle on veut permettre la saisie en japonais
MyDialog est la classe de dialogue qui contient widget
Le dialogue doit avoir les slots suivants :
class MyDialog : public QDialog
{
...
protected slots:
void onWidgetContextMenu(const QPoint& pos);
void onInputContextChange(QAction* action);
}
Quand on construit le dialogue et ses zones de saisie, il faut rajouter les lignes suivantes (dans une fonction de MyDialog :
widget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(widget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onWidgetContextMenu(const QPoint&)));
L’implémentation du menu contextuel, affichant la liste des méthodes d’entrée, est assez simple :
void MyDialog::onWidgetContextMenu(const QPoint& pos)
{
QWidget* edit = getMyCurrentWidget(); /** à nous de savoir quelle zone est concernée */
QMenu popup(tr("Propriétés"));
QMenu* context = popup.addMenu(tr("Méthode d'entrée"));
QAction* def = context->addAction(tr("(défaut: %1)").arg(QInputContextFactory::displayName(qApp->inputContext()->identifierName())));
def->setCheckable(true);
if (edit->inputContext()->identifierName() == qApp->inputContext()->identifierName())
{
def->setChecked(true);
}
foreach(QString key, QInputContextFactory::keys())
{
if (key == qApp->inputContext()->identifierName())
continue;
QAction* action = context->addAction(QInputContextFactory::displayName(key));
action->setCheckable(true);
action->setData(key);
if (edit->inputContext()->identifierName() == key)
{
action->setChecked(true);
}
}
connect(&popup, SIGNAL(triggered(QAction*)), this, SLOT(onInputContextChange(QAction*)));
popup.exec(edit->mapToGlobal(pos));
}
Et enfin la gestion du changement de méthode d’entrée n’a plus grand-chose à faire :
void MyDialog::onInputContextChange(QAction* action)
{
QString input = action->data().toString();
QWidget* edit = getMyCurrentWidget();
if (edit->inputContext()->identifierName() == input || (input.isEmpty() && edit->inputContext()->identifierName() == qApp->inputContext()->identifierName()))
// pas la peine de changer pour rien
return;
if (input.isEmpty())
{
edit->setInputContext(QInputContextFactory::create(qApp->inputContext()->identifierName(), edit));
}
else
{
QInputContext* context = QInputContextFactory::create(input, edit);
if (context)
edit->setInputContext(context);
}
// pour une raison inconnue, il y a des problèmes de saisie, en solution de contournement on joue avec le focus
edit->nextInFocusChain()->setFocus();
edit->setFocus();
}
Et voici le résultat :

[1] En pratique, cette solution permettra de saisir n’importe quelle langue pourvu que le support soit disponible sur le système.
[2] J’utilise la version 4.4.2 sous Linux, mais j’imagine que ce n’est pas trop différent pour les autres versions.
[3] Sous Linux, une « méthode d’entrée » est une façon d’entrer du texte. Pour de l’alphabet romain, il n’y a rien de spécial à faire, mais pour entrer des kanjis, il faut pouvoir par exemple entrer la phonétique et choisir les caractères voulus.