PerlQt移植ヒストリ(第9回)

PerlQt/Embeddedを2.105-p0.04に更新した。

ダウンロード

Perlライブラリ:lib-perl-qte_2.105-p0.04_arm.ipk
ソースファイル:perlqt-2.105-p0.04-src.tar.gz

更新内容

  • 以下のソースコードにおいて、QStringをPerlの文字列に変換/逆変換する場合はUTF-8を使用するようにすることで、Qt::MultiLineEdit(複数行エディットクラス)やQt::Labelなどの日本語対応を行った(詳細は後述)。
  • C++では定義されていない(メソッドではなく)仮想関数のinsertCharをQt::MultiLineEditから削除した。
  • 引き数の型をcharからintに変更することで、Qt::MultiLineEditのinsertCharメソッドの日本語対応を行った。引き数の文字コードは2バイトのUNICODEUTF-16)である。
  • ASCII文字列として受け取っていたPerlの文字列を、QStringで受け取るようにすることで、後述の関数の日本語対応を行った。

詳細説明

Qt::MultiLineEditの日本語対応

Qt::MultiLineEditに対して日本語を入力をしたときの内部処理を以下に説明する(と言っても、自分用のメモだが)。
なお、「A ⇒ B」は「Aクラスの親のBクラス」を意味する。
また、C++のクラス、メソッドに相当するものをPerl上ではパッケージ、サブルーチンと表現する。

  • keyPressEventの呼び出し
    1. QMultiLineEditクラスを継承したpig_enhanced_QMultiLineEditクラスのkeyPressEventメソッドがQtから呼び出される。入力された日本語は、メソッドの引き数であるQKeyEventオブジェクトにより伝搬される。
    2. pig_enhanced_QMultiLineEdit ⇒ pig_virtual_QMultiLineEdit ⇒ pig_virtual_QTableView ⇒ pig_virtual_QFrame ⇒ pig_virtual_QWidgetクラスのpig_virtual_keyPressEventメソッドを呼び出す。
    3. pig_import_Qt.hで定義されているインポートテーブル(各パッケージのC++による実装で定義されたエクスポートテーブルで初期化、詳細は後日)により間接的にpig_virtual_QWidget__keyPressEvent関数を呼び出す。
    4. Qt::MultiLineEditパッケージ(または、それを継承したパッケージ)のkeyPressEventサブルーチンを呼び出す。PerlQtでは同様の方法により全ての仮想関数をPerl上で実現している。
    5. keyPressEventサブルーチンが上書きされていなければ、そのサブルーチンにマッピングされているPIG_QMultiLineEdit_keyPressEvent関数が呼び出される。
    6. QMultiLineEditクラスのprotectedメソッドを外部から呼び出すために、継承して中継関数を定義したpig_alias_QMultiLineEditクラスのpig_alias_keyPressEventメソッドを呼び出す。
    7. QMultiLineEditクラスのkeyPressEventを呼び出す。パッケージの継承とサブルーチンの仮想化を実現するためなのだが、C++では(継承されていなければ)ここがスタート地点なので、Perl上では随分と複雑な処理を経ていると言える。
    8. ここまでは、QKeyEventオブジェクトによって入力された日本語が正しく伝搬されている。問題点は次の処理にある。入力された日本語は、QKeyEventクラスのtextメソッドにより、UTF-16のQStringオブジェクトとして得ることができる。
  • insertの呼び出し
    1. QMultiLineEditクラスを継承したpig_enhanced_QMultiLineEditクラスのinsertメソッドが呼び出される。入力された日本語は、メソッドの引き数であるUTF-16のQStringオブジェクトにより伝搬される。
    2. pig_enhanced_QMultiLineEdit ⇒ pig_virtual_QMultiLineEditクラスのpig_virtual_insertメソッドを呼び出す。
    3. 前述のインポートテーブルにより間接的にpig_virtual_QMultiLineEdit__insert関数を呼び出す。
    4. Qt::MultiLineEditパッケージ(または、それを継承したパッケージ)のinsertサブルーチンを呼び出す。そのサブルーチンに渡すために、QStringオブジェクトで渡された日本語をPerlの文字列に変換する。しかし、変換元をQStringクラスのdataメソッド(結果的にlatin1メソッド)から得ているため、日本語は破棄されてしまうことが問題だった。この問題を解決するために、utf8メソッドでUTF-8に変換したQStringオブジェクトからPerlの文字列を作成するように修正した。
    5. insertサブルーチンが上書きされていなければ、そのサブルーチンにマッピングされているPIG_QMultiLineEdit_insert関数が呼び出される。
    6. QMultiLineEditクラスのinsertを呼び出す。
  • insertAtの呼び出し
    1. QMultiLineEditクラスを継承したpig_enhanced_QMultiLineEditクラスのinsertAtメソッドが呼び出される。以降は前述の「insertの呼び出し」と同様なので、「insert」を「insertAt」に読み替えて欲しい。
日本語をQStringで受け取るようにした関数
ソース 関数
pig_QBitmap.c PIG_QBitmap_new
pig_QLabel.c PIG_QLabel_setText
PIG_QLabel_text
pig_virtual_QLabel__setText
pig_enhanced_QLabel::setText
pig_QLabel_v.h pig_virtual_QLabel::pig_virtual_setText
pig_QLineEdit.c PIG_QLineEdit_validateAndSet
pig_QListView.c PIG_QListView_columnText
pig_QPainter.c PIG_QPainter_boundingRect
pig_QPicture.c PIG_QPicture_load
PIG_QPicture_save
pig_QSpinBox.c PIG_QSpinBox_valueChange
pig_QTab.c PIG_QTab_setLabel
pig_QToolButton.c PIG_QToolButton_setTextLabel
pig_virtual_QToolButton__setTextLabel
pig_enhanced_QToolButton::setTextLabel
pig_QToolButton_v.h pig_virtual_QToolButton::pig_virtual_setTextLabel
pig_QToolTipGroup.c PIG_QToolTipGroup_showTip
pig_QWidget.c PIG_QWidget_caption
PIG_QWidget_drawText
PIG_QWidget_iconText