質問: 先日Qtの日本営業店に尋ねましたら、 Qt等では、縦書きの実装などはかなり難しい(できない?) と言われました。 一太郎とか、Wordソフトとかって何のプログラミング言語で かかれているのでしょうか?という質問を検索すると、 やはり企業秘密みたいで、C++とか、そこらへん?みたいな ようです。例えばQtはC++なので、ならばQtでもできるはず ですが、私もできそうな気がしません。(→この質問は 確かに変でした。) 自分で拡張していくしかないのか、先日からお尋ねしている サブクラス化が成功すれば、それなりに融通の利くレイアウトを 実装できるのか、正直わかりません。ただこの辺のドキュメントは 無いと言っていいくらい少なく、正直絶望的です。 この際にお聞きしたいのですが、こういう質問はいいのかわからない のですが、テキストエディタ作成に強いプログラミング言語って ご存知ですか? **追記** 詳しい解説有難うございます。[組版文字について:QTextEdit関連、ルビの表記、組立文字等は何とか`Qt`でも実装出来ました。こういうテキスト処理系の話は`Qt`から始めたため、`Qt`の中だけでもがいてきた感じです。今回は、`Qt`以外の方向へ眼を向けようとしたための質問でした。sayuriさんのご指摘の通り、組版処理の要件という無料公開の文書をネットで見て、その厳密さに驚いたことがありますが、Qtで何か方法はないかと手探りしてきました。自分はPythonに手を付ける前にPyQtの本を買ってしまったというぐらいの経歴を持っていて、(しかも英語のMarkSummerfield氏のやつです。)GUIというのも知りませんでした。そこからPythonスタートブックから地道にやってきたのですが、正直PyQtって何?という始まりでつまずいている可能性のある存在でした。まだQtでも触った事のないメソッドやクラスもあるため、組み合わせ次第ではできる可能性もあるのではないかという希望を持ちつつ色々やってきました。今の自分のスキルでは皆さんのご助力とともに、ルビや組立文字等、「組版が少しでも増やせた。」というところでも満足するものだと思うんですが、上でも述べたように、Qtでは縦書やらは難しいということだったので、(こう、Qt側から、初めてそれは無理です。と言われた感じなので、)じゃあ別の?という程度の切り替えを意識した質問でした。意図がわかりにくかったようで申し訳ありません。確かにエディタではなくて、ワードプロセッサの方が私の意図通りです。抽象的にテキストを扱うソフトっていうのかどういうべきなのかはわかりませんが、Qtを始めるまえは縦書に難があるとかいう限界自体を知らずに突き進んできたため、こんな質問になりました。Qt以外のライブラリだったらできるか?という感じです。少なくともテキスト処理系に強いプログラミング言語は?ライブラリは?という質問にすべきだったかどうかわかりませんが、とりあえずこの質問はいけないようだったので消そうかなと考えています。 皆さんの意見を自分なりに考えてみると、つまり、Qtは既にC++で書かれたライブラリなので、Qtで無理なら、C++でQtに変わる別のライブラリを構成し、リファレンス公開するレベルにならないといけないということですね。Qtを使ってどうこう言ってるんじゃなくて、Qtを作れるレベルには最低限なってないとだめだと。 Lispですというお答えもいただきましたが、私が一番欲しい解答はこのようなものでした。でも何となくわかったことですが、言語自体を自分で作り、ライブラリを自分で生み出し、ほかの人が作ったライブラリに頼らずに、一から自分で作りなさいと、そういうことなのでしょうか。出来上がった結果としてのライブラリに頼ってたら、確かに根っこは変えられないですね。確かにこういう構造関係を知らないようではそんな事やったこともないため、スキル不足は否めません。 ひょっとすると、Qtで公開されているライブラリのように、誰かが作ってくれたライブラリの中で、テキスト処理系に強いライブラリはありますか?と尋ねるべきだったでしょうか。ほんとこの辺の知識が曖昧なまま進んできたもので、お騒がせして申し訳ありませんでした。 (クローズされるか、この質問は近日中に消そうと思います。)
回答: C++とQtで縦書きワープロを作るという方針で検討してみます。 まず、現時点において、Qtはテキストの縦書き描画をサポートしていなかったはずです。 サポートされていないなら自前でやる必要があります。 まずは基本のテキスト描画から。これは横書きです。 ``` void MyWidget::paintEvent(QPaintEvent *event) { QPainter pr(this); QString text = "\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a"; // あいうえお pr.drawText(5, 15, text); } ``` テキスト描画の進行方向を縦にするには、QTransformクラスを使います。 ``` void MyWidget::paintEvent(QPaintEvent *event) { QTransform tr; tr.translate(5, 5); tr.rotate(90); QPainter pr(this); pr.setTransform(tr); QString text = "\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a"; // あいうえお pr.drawText(0, 0, text); } ``` rotateを指定して90度回転して描画しています。しかしこれでは、文字まで横倒しになってしまうので使えません。 QTransformはあきらめて、1文字ずつ描画してみます。 ``` void MyWidget::paintEvent(QPaintEvent *event) { QPainter pr(this); QFontMetrics fm = pr.fontMetrics(); // フォント情報を取得 int line_height = fm.height(); // 文字の高さ int x = 5; int y = 5; y += line_height; pr.drawText(x, y, "\xe3\x81\x82"); // あ y += line_height; pr.drawText(x, y, "\xe3\x81\x84"); // い y += line_height; pr.drawText(x, y, "\xe3\x81\x86"); // う y += line_height; pr.drawText(x, y, "\xe3\x81\x88"); // え y += line_height; pr.drawText(x, y, "\xe3\x81\x8a"); // お } ``` 縦書き成功です。 ここから検討しなければいけないことがたくさんあります。 文字毎に幅が異なる可能性があります。多くのフォントでは、全角文字に限れば全て同じ幅かもしれませんし、文字毎に微調整が施されていて、文字幅が全部異なるかもしれません。 日本語の文と欧文が混在する場合どうするか。半角文字を描画する場合、水平方向に中央寄せして縦書きにするのか、英文として読めるように、横書きを回転した(上に挙げた2番目の例の)様にに描画したいのか、文字毎に座標と回転を自分で計算して描画することになるでしょう。日欧混在テキストの描画では、カーニングや合字をどう処理するかなど、悩ましい課題がたくさん出てきます。 長いテキストをひとつの関数で一度で描画するなら高速ですが、一文字一文字描画すると、パフォーマンスの低下が懸念されます。実際に作ってみないとわかりませんが、遅すぎて実用にならないとなったときに、バックグラウンドで遅延描画するとか、レンダリングのキャッシュを実装するとか、かなり面倒くさいことを行う必要が出てくるかもしれません。 <追記> 日本語入力の対応も結構面倒です。IMEはQtでサポートされていますが、その扱いは自前実装になります。IME入力を受け付けたいウィジェットに対して`setAttribute`を呼んでIMEを有効にし、`inputMethodQuery`と`inputMethodEvent`をオーバーライドして、変換候補ウィンドウの表示位置を設定したり、変換文字列を取得したりする必要があります。イベントで渡される文字列には、preedit(変換中文字列)とcommit(確定文字列)があります。on-the-spot方式(ワープロソフトの編集中文書内で変換中文字列をインライン的に描画する)か、over-the-spot方式(ポップアップウィンドウを作ってその中で変換中文字列を描画する)か、アプリケーションの要件に応じて、どちらを採用するか決めます。いずれにしても、一連のIME対応を自分で実装する必要があります。変換中文字列を縦書きで表示するアプリを私は見たことがありませんが、もし実現できれば、結構レアなアプリということになるので、意外と需要があるかもしれません。 </追記> やってできなくはないはずですが、相当の覚悟がないと、途中で挫折すること必至です。 p.s. 記事タイトルは、「縦書きワープロアプリの実装に適した言語や手法は何か?」といったものがいいと思います。記事を削除したりクローズする必要はないと考えます。