国際化対応 [Qt]
歩みが遅い上に寄り道ばかりしていて、全く進まないんですが、Qtの国際化対応について学習します。国際化に関するページを読んでいたら、Qt Linguistのマニュアルも読めとのこと。そう言えば、Qt関連の開発環境をインストールした時に、「Qt 4リンギスト」と言うのも入ってました。
とりあえず、立ち上げてみましょう。
どうすりゃいいのでしょうか?
マニュアルが作業する対象によって分かれている様ですが、まずプログラマ向けのマニュアルを見てみようと思います。・・・なんか、遠回りな書き方をされている様な気がしますが、書かれている順にまとめてみましょう。
●.tsファイルの作成
このファイルには「ユーザに見えるテキスト」、「アプリケーション上でのCtrlキーアクセラレータ」、「翻訳語」が含まれているようです。「lupdate」と言うツール(コマンドラインツール?)が肝な様で、.tsファイルの作成、Qt Linguistで追加した翻訳と元のテキストのシンクロを行うようです。また、「lrelase」と言う通るで、.tsファイルから.qmファイルを作成し、アプリは.qmファイルを実行時に利用するとのこと。作成したファイルの設定と文字コードの設定のため、.proファイルも編集する必要があるようです(lupdateがやってくれそうな雰囲気もありますが、不明)。
「lupdate」「lrelease」の使い方はこちらとのこと。
●翻訳の読み込み
翻訳を利用する際は、main()関数に下記の記述を入れるとのこと。ラストの行は、文字コードの設定です。
なお、翻訳ファイルが見つからなければ、ソースコードのテキストがそのまま利用されるとのこと。
●「ユーザに見える文字列」の翻訳
翻訳対象の文字列を指定する際、普通の文字列リテラルを「tr()」で囲えばいい様です。例えば、こんな感じ。
後、色々書かれていますが、今は「tr()」を使えばいいと言うのが分かれば、それでオッケーの様な気もしますね。実際の翻訳作業はまた最後の方でと言う事で・・。でも、「&Quit」の様にショートカットキーの指定をこの時点で行う様なので、デフォルトの言語は英語にしとかないといけない感じですねぇ・・。
分かった様な、分からん様な感じ(と言うか、たぶん分かってない)ですが、つづく。
【参考】
・Internationalization with Qt - Qt Reference Documentation 4.5.3
・Qt Linguist Manual - Qt Reference Documentation 4.5.3
とりあえず、立ち上げてみましょう。
どうすりゃいいのでしょうか?
マニュアルが作業する対象によって分かれている様ですが、まずプログラマ向けのマニュアルを見てみようと思います。・・・なんか、遠回りな書き方をされている様な気がしますが、書かれている順にまとめてみましょう。
●.tsファイルの作成
このファイルには「ユーザに見えるテキスト」、「アプリケーション上でのCtrlキーアクセラレータ」、「翻訳語」が含まれているようです。「lupdate」と言うツール(コマンドラインツール?)が肝な様で、.tsファイルの作成、Qt Linguistで追加した翻訳と元のテキストのシンクロを行うようです。また、「lrelase」と言う通るで、.tsファイルから.qmファイルを作成し、アプリは.qmファイルを実行時に利用するとのこと。作成したファイルの設定と文字コードの設定のため、.proファイルも編集する必要があるようです(lupdateがやってくれそうな雰囲気もありますが、不明)。
「lupdate」「lrelease」の使い方はこちらとのこと。
●翻訳の読み込み
翻訳を利用する際は、main()関数に下記の記述を入れるとのこと。ラストの行は、文字コードの設定です。
QApplication app(argc, argv); QTranslator translator; translator.load("hellotr_la"); app.installTranslator(&translator); QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8")); |
なお、翻訳ファイルが見つからなければ、ソースコードのテキストがそのまま利用されるとのこと。
●「ユーザに見える文字列」の翻訳
翻訳対象の文字列を指定する際、普通の文字列リテラルを「tr()」で囲えばいい様です。例えば、こんな感じ。
button = new QPushButton(tr("&Quit"), this); |
後、色々書かれていますが、今は「tr()」を使えばいいと言うのが分かれば、それでオッケーの様な気もしますね。実際の翻訳作業はまた最後の方でと言う事で・・。でも、「&Quit」の様にショートカットキーの指定をこの時点で行う様なので、デフォルトの言語は英語にしとかないといけない感じですねぇ・・。
分かった様な、分からん様な感じ(と言うか、たぶん分かってない)ですが、つづく。
【参考】
・Internationalization with Qt - Qt Reference Documentation 4.5.3
・Qt Linguist Manual - Qt Reference Documentation 4.5.3
レイアウトの追加 [Qt]
前回、思いつきでバックアップツールの開発を開始しましたが、適当に部品を配置し始めたため、レイアウトを使うのを忘れていました・・・。まだ特にコードを追加してたりするわけではないので、最初からやり直してもいいんですが、後学のため、このままレイアウトを追加してみようと思います。
で、前回アップしてたラフな絵に従って部品を配置したのですが、その配置先のMainWindowClassに直接verticalLayoutを追加したところ次の様になってしまいました。
まあ、こうなるわな・・
分かりにくいかもしれませんが、一応、前回描いた画面案と見比べていただけるとありがたく思います。
ここから、前回の画面案の「コピー元」とその追加(+)、削除(-)ボタンを横に並べようと、右横の「Object」ウィンドウでそれら3つの部品を選択して、右クリック→「Layout」を選択したところ・・、「Break Layout」しか選択できません・・。レイアウトの中に入っている部品にレイアウトをつけるのはできないようですね。
仕方がないので、先程追加したレイアウトを解除し、末端から順にレイアウトしていきました。完了後はこちら・・・。画面が狭くて、全体がよくわかりませんね。
大体想定通り
全体が見にくいですが、だいたい思い通りにレイアウトできました。一点、「コピー元」の横のボタンの並びが気に入らないので、そこのレイアウトにQLabelをスペーサとして入れときました。
ここまでで実行してみた感じがこちらです。
見た目完了
まあ、見た目はおおむね完了でしょうか。
続いて、ボタンのテキストを変更しようと思いましたが、せっかくなので、英語と日本語の両方のリソースを用意してみようかと思い立ちました。いわゆる国際化対応ですね。って、また余計な時間がかかりますね・・。
つづく。
で、前回アップしてたラフな絵に従って部品を配置したのですが、その配置先のMainWindowClassに直接verticalLayoutを追加したところ次の様になってしまいました。
まあ、こうなるわな・・
分かりにくいかもしれませんが、一応、前回描いた画面案と見比べていただけるとありがたく思います。
ここから、前回の画面案の「コピー元」とその追加(+)、削除(-)ボタンを横に並べようと、右横の「Object」ウィンドウでそれら3つの部品を選択して、右クリック→「Layout」を選択したところ・・、「Break Layout」しか選択できません・・。レイアウトの中に入っている部品にレイアウトをつけるのはできないようですね。
仕方がないので、先程追加したレイアウトを解除し、末端から順にレイアウトしていきました。完了後はこちら・・・。画面が狭くて、全体がよくわかりませんね。
大体想定通り
全体が見にくいですが、だいたい思い通りにレイアウトできました。一点、「コピー元」の横のボタンの並びが気に入らないので、そこのレイアウトにQLabelをスペーサとして入れときました。
ここまでで実行してみた感じがこちらです。
見た目完了
まあ、見た目はおおむね完了でしょうか。
続いて、ボタンのテキストを変更しようと思いましたが、せっかくなので、英語と日本語の両方のリソースを用意してみようかと思い立ちました。いわゆる国際化対応ですね。って、また余計な時間がかかりますね・・。
つづく。
SVGから内部形式データへの変換4 [Qt]
さて、前回で準備はできたんですが、改めてログを確認したところ、QPaintEngine::drawPolygon()で渡されている引数は線が分断されてますね・・。
ま、こんな感じですね。
これは、最初に描画する際にQPainter::drawLine()を利用していることに起因するような気がしますね。これをQPainter::drawPolyline()でも使えば、思い通りに一本の線と言う扱いになるのかもしれませんが、ここでは気にしないでいましょう。
*
一通り、実装して実行したところ、「QPainter::setPen: Painter not active」など、QPainterがアクティブでないと言うエラーメッセージがバンバン出てきました・・。何か、初期化動作が足らないようです・・。QPaintEngineの説明をもう一度読み直しますか・・。
・・・見てたら、QPaintEngine::begin()で、trueを返していないのに気がつきました。bool型の関数なのに、何も返してませんね。でも、これを直しても、関係ありませんでした。
ログをよく見てみたら「QPainter::begin: Paint device returend engine == 0, type: 0」と言うメッセージが出てますね。一応、QPaintdevice::paintEngine()は実装していて、ちゃんとpaintEngineを返す実装はしているつもりなんですが、うまく動いていないんでしょうか・・?
・・・うまく動いていない様ですね・・。ログを出してみたら、NULLを返してました・・。なんででしょう・・。
って、QtlSvgConvEngineと言うクラスがQPaintEngineを継承したクラスなんですが、QtlSvgConvertorのコンストラクタでこれのインスタンスを生成していながら、それを記憶していませんでした・・・。ちゃんと記憶させたところ・・。
こう書いたのが・・・、
保存は前試した
ちゃんとこう復元されました。
読み出し成功!
とりあえず、保存・読み込みは完了です。って、私はソースを見ながらここにメモ書きしてるんですが、ここにソースを載せないと読んでる人には意味不明ですね・・。どうしようかな。
つづく。
★書店売上No.1ビジネス週刊誌!!★【週刊ダイヤモンド】定期購読は最大45%OFF!!★送料無料
ま、こんな感じですね。
これは、最初に描画する際にQPainter::drawLine()を利用していることに起因するような気がしますね。これをQPainter::drawPolyline()でも使えば、思い通りに一本の線と言う扱いになるのかもしれませんが、ここでは気にしないでいましょう。
*
一通り、実装して実行したところ、「QPainter::setPen: Painter not active」など、QPainterがアクティブでないと言うエラーメッセージがバンバン出てきました・・。何か、初期化動作が足らないようです・・。QPaintEngineの説明をもう一度読み直しますか・・。
・・・見てたら、QPaintEngine::begin()で、trueを返していないのに気がつきました。bool型の関数なのに、何も返してませんね。でも、これを直しても、関係ありませんでした。
ログをよく見てみたら「QPainter::begin: Paint device returend engine == 0, type: 0」と言うメッセージが出てますね。一応、QPaintdevice::paintEngine()は実装していて、ちゃんとpaintEngineを返す実装はしているつもりなんですが、うまく動いていないんでしょうか・・?
・・・うまく動いていない様ですね・・。ログを出してみたら、NULLを返してました・・。なんででしょう・・。
って、QtlSvgConvEngineと言うクラスがQPaintEngineを継承したクラスなんですが、QtlSvgConvertorのコンストラクタでこれのインスタンスを生成していながら、それを記憶していませんでした・・・。ちゃんと記憶させたところ・・。
こう書いたのが・・・、
保存は前試した
ちゃんとこう復元されました。
読み出し成功!
とりあえず、保存・読み込みは完了です。って、私はソースを見ながらここにメモ書きしてるんですが、ここにソースを載せないと読んでる人には意味不明ですね・・。どうしようかな。
つづく。
★書店売上No.1ビジネス週刊誌!!★【週刊ダイヤモンド】定期購読は最大45%OFF!!★送料無料
SVGから内部形式データへの変換3 [Qt]
先週はばたばたしていて、飛ばしてしまいました。さて、前回、描画先のサイズの違いによる座標系の変換について悩んだんですが、実際どのように通知されているのかと、次の手順で、試してみました。
・起動後、ウィンドウサイズを拡大
・メモを書き込み
・終了 ←ここで、データを保存
・起動 ←ここで、データを読み込みログ出力
以上で出力された際のログを見たところ、以前出力されたログとは異なり、QPaintEngine::drawPath()やQPaintEngine::drawPolygon()は呼ばれていません。代わりにQPaintEngine::drawImage()が呼ばれています。ちなみに、QPaintEngine::updateState()の値も以前とは異なるようです。
詳しく見ていませんが、どうやらdrawImage()は全体の画像を細切れにして呼ばれている様です。また、SVGデータの中身とdrawImage()の引数を比べると、どうも座標系の変換は行われた上で、drawImage()が呼ばれているように感じます。今回は読み込み時は画像の縮小になるため、出力する位置も重複してしまっているようですね。ま、細かい動きはいいでしょう。データの保存時と読み込み時の画像のサイズを合わせないと筆跡の座標が取れないことがわかりました。ちゃんとやるには、今の実装に色々と手を加えなければいけない気がしたので、とりあえず今のところはウィンドウのサイズは変更しない前提で進めていきます。
さて、内部データへの変換です。変換エンジンのところで、データの変換を行って、最後に返せばいいかと思ってたんですが、内部データ生成の部分を二重に書くことになってしまいますね・・。実際に描画する際のルーチンをそのまま使いたい気がしたので、ちょっと、構造を変えて、QtlSvgConvertorで、QtlDrawDataを持っておき、直接そこに書き込む動作に変えます。・・・、って自分用のメモなので、記事を読んでる人には何のことやらわからないことが時々出てくると思いますが、気にしないで下されば幸いです・・。で、変えた図はこんな感じ。
やや無理やり気味
で、シーケンス上で渡していたQPaintDeviceの代わりにQtlDataを渡すことにします・・・。ついでにQtlSvgConvEngine側でQtlSvgConvertorが持っているQtlDrawData内のQPaintDeviceを取りだす為にQtlSvgConvertorに関数の追加が必要です。また、それに加えて、QtlSvgConvertorをQtlSvgConvEngine側に渡す必要も出てきますね・・。う〜ん、もうぐちゃぐちゃですね。やっぱり、QtlSvgConvertorとQtlSvgConvEngineは一つにした方が良さげです。今はしませんが・・。
変更後のシーケンス
上記を前提に下記の関数を追加しました。
さて、かなり無理やり感がありますが、これで一応実現は可能でしょうか・・。
引っ張ってなんですが、つづく。
・起動後、ウィンドウサイズを拡大
・メモを書き込み
・終了 ←ここで、データを保存
・起動 ←ここで、データを読み込みログ出力
以上で出力された際のログを見たところ、以前出力されたログとは異なり、QPaintEngine::drawPath()やQPaintEngine::drawPolygon()は呼ばれていません。代わりにQPaintEngine::drawImage()が呼ばれています。ちなみに、QPaintEngine::updateState()の値も以前とは異なるようです。
詳しく見ていませんが、どうやらdrawImage()は全体の画像を細切れにして呼ばれている様です。また、SVGデータの中身とdrawImage()の引数を比べると、どうも座標系の変換は行われた上で、drawImage()が呼ばれているように感じます。今回は読み込み時は画像の縮小になるため、出力する位置も重複してしまっているようですね。ま、細かい動きはいいでしょう。データの保存時と読み込み時の画像のサイズを合わせないと筆跡の座標が取れないことがわかりました。ちゃんとやるには、今の実装に色々と手を加えなければいけない気がしたので、とりあえず今のところはウィンドウのサイズは変更しない前提で進めていきます。
さて、内部データへの変換です。変換エンジンのところで、データの変換を行って、最後に返せばいいかと思ってたんですが、内部データ生成の部分を二重に書くことになってしまいますね・・。実際に描画する際のルーチンをそのまま使いたい気がしたので、ちょっと、構造を変えて、QtlSvgConvertorで、QtlDrawDataを持っておき、直接そこに書き込む動作に変えます。・・・、って自分用のメモなので、記事を読んでる人には何のことやらわからないことが時々出てくると思いますが、気にしないで下されば幸いです・・。で、変えた図はこんな感じ。
やや無理やり気味
で、シーケンス上で渡していたQPaintDeviceの代わりにQtlDataを渡すことにします・・・。ついでにQtlSvgConvEngine側でQtlSvgConvertorが持っているQtlDrawData内のQPaintDeviceを取りだす為にQtlSvgConvertorに関数の追加が必要です。また、それに加えて、QtlSvgConvertorをQtlSvgConvEngine側に渡す必要も出てきますね・・。う〜ん、もうぐちゃぐちゃですね。やっぱり、QtlSvgConvertorとQtlSvgConvEngineは一つにした方が良さげです。今はしませんが・・。
変更後のシーケンス
上記を前提に下記の関数を追加しました。
QtlDrawData *QtlSvgConvertor::getData() | QtlSvgConvertor内に保存しているQtlDrawDataを取得する。 |
さて、かなり無理やり感がありますが、これで一応実現は可能でしょうか・・。
引っ張ってなんですが、つづく。
SVGから内部形式のデータへの変換2 [Qt]
実装に取り掛かりたいと思いますが、データの変換の部分は下記の様な構造で実装を行おうと考えています。
この2つのクラスはまとめられますかね?
一応、Qtの考え方(と私が理解している・・)に合わせて、QPaintDeviceのサブクラスとQPaintEngineのサブクラスに分けていますが、データの変換という目的のためなら、何となく一つにした方がいい様な気がしてますが、まあ最初はこのままで行きます。このクラスをQtlDrawDataから利用する形にしようと思っています。
データ変換のシーケンスは下記の様な感じでしょうか。
さて、肝心の「描画の処理」の所をブラックボックスにしていますが、処理を考えて行きましょう。呼び出される関数と必要そうな処理は前回の表の通りなので、実際に実装して行こうと思います。
シーケンス中、QtlSvgConvertor::setDevice()と言う関数がQtlSvgConvertorから呼び出されています。これは、下記の通り、データの書き込み先のデバイス(今のところ、QtlDrawData内で保持しているQPixmapを想定)を登録する関数となっています。書き込み先のパラメータが必要な時は、全てこの関数で登録されたデバイスから引き出す事にします。コンストラクタで指定できた方がいいですかね・・。まあ、ええか。
metric()は、要求されたものを返しますが、このデータの元が、先程の関数で設定されたQPaintDeviceから値を引き出す事になります。
で、updateState()ですね。前回の記事では、パラメータを保存する旨を書いていましたが、よく考えてみると、今のところは書き込む時にペンの設定を変えたりしていないので、必要ないんですよね・・。今は無視する事にします。
次はdrawPath()ですが、今のところ、終点の処理をデータとして保存する必要は無いので、前回記載のとおり、何もしません。
そして、drawPolygon()です。これは、線の描画として処理が必要です。が、だいぶ前に書いたとおり、ターゲットのサイズが違う場合が気になります。一応、アプリの動作としては、書いたものをウィンドウのサイズに合わせて、拡大・縮小させたいと考えています。もう、いつ始めたのかも分からないくらいになってますが、作ろうとしてるのはメモですからね。どのようなウィンドウサイズでもメモが読めるようにしたいと思います。
・・・データの精度が気になりますね。現状は、最初にメモを取った時の画面のサイズが元になってしまっていますが、最初に小さいサイズのウィンドウで書いたデータに大きい画面で書き足した時に点が荒くなってしまうのは避けたいですね・・。データの元サイズは標準のサイズとして決め打ちしとく必要がありそうですが、その場合は、最初にデータを書き込むときから、座標変換をかます必要がありますねぇ・・・。
ちょっと悩むので続く。
この2つのクラスはまとめられますかね?
一応、Qtの考え方(と私が理解している・・)に合わせて、QPaintDeviceのサブクラスとQPaintEngineのサブクラスに分けていますが、データの変換という目的のためなら、何となく一つにした方がいい様な気がしてますが、まあ最初はこのままで行きます。このクラスをQtlDrawDataから利用する形にしようと思っています。
データ変換のシーケンスは下記の様な感じでしょうか。
さて、肝心の「描画の処理」の所をブラックボックスにしていますが、処理を考えて行きましょう。呼び出される関数と必要そうな処理は前回の表の通りなので、実際に実装して行こうと思います。
シーケンス中、QtlSvgConvertor::setDevice()と言う関数がQtlSvgConvertorから呼び出されています。これは、下記の通り、データの書き込み先のデバイス(今のところ、QtlDrawData内で保持しているQPixmapを想定)を登録する関数となっています。書き込み先のパラメータが必要な時は、全てこの関数で登録されたデバイスから引き出す事にします。コンストラクタで指定できた方がいいですかね・・。まあ、ええか。
QtlSvgConvertor::setDevice() | ||
引数 | QPaintDevice | データの描画先 |
戻り値 | void | |
処理 | 引数のQPaintDeviceを記憶する |
metric()は、要求されたものを返しますが、このデータの元が、先程の関数で設定されたQPaintDeviceから値を引き出す事になります。
で、updateState()ですね。前回の記事では、パラメータを保存する旨を書いていましたが、よく考えてみると、今のところは書き込む時にペンの設定を変えたりしていないので、必要ないんですよね・・。今は無視する事にします。
次はdrawPath()ですが、今のところ、終点の処理をデータとして保存する必要は無いので、前回記載のとおり、何もしません。
そして、drawPolygon()です。これは、線の描画として処理が必要です。が、だいぶ前に書いたとおり、ターゲットのサイズが違う場合が気になります。一応、アプリの動作としては、書いたものをウィンドウのサイズに合わせて、拡大・縮小させたいと考えています。もう、いつ始めたのかも分からないくらいになってますが、作ろうとしてるのはメモですからね。どのようなウィンドウサイズでもメモが読めるようにしたいと思います。
・・・データの精度が気になりますね。現状は、最初にメモを取った時の画面のサイズが元になってしまっていますが、最初に小さいサイズのウィンドウで書いたデータに大きい画面で書き足した時に点が荒くなってしまうのは避けたいですね・・。データの元サイズは標準のサイズとして決め打ちしとく必要がありそうですが、その場合は、最初にデータを書き込むときから、座標変換をかます必要がありますねぇ・・・。
ちょっと悩むので続く。
SVGから内部形式のデータへの変換 [Qt]
さて、SVGの要素の大体の意味がわかったところで、呼び出された関数の処理を考えていきたいと思います。「metric()」以外は、QPaintEngineのメンバ関数となっています。
これを参考に、起動時にデータを読み込む実装をしたいと思います。
細切れでなんなんですが、つづく。
begin() | ||
引数 | QPaintDevice * | データ変換用のクラス(QPaintDeviceのサブクラス)が来る予定 |
戻り値 | bool | 成功時true、失敗時false。 |
処理 | 書き込み先のサイズなど、後の処理に必要なデータを取得。 |
metric() | ||
引数 | PaintDeviceMetric | 要求パラメータ |
戻り値 | int | 要求されたパラメータの値 |
処理 | QPaintDeviceの仮想関数。要求されているパラメータの値をbegin()で登録されたQPaintDeviceから引きだして返す。 |
updateState() | ||
引数 | QPaintEngineState | 変更のあったパラメータ |
戻り値 | void | |
処理 | 描画に使うパラメータをQPaintEngineStateから取得し、保存しておく。それぞれのパラメータに対する呼び出し関数は、詳細説明に記載されている。現状で保存が必要と思われるパラメータは、QPainter::RenderHints、QBrush、QPen、QFont。QPainter::RenderHintsはenum型、QBrushは、通常用と背景用の2種類のインスタンスが必要な様子。 |
drawPath() | ||
引数 | QPainterPath | 描画終了位置周辺の座標が入っている様子 |
戻り値 | void | |
処理 | 終点周辺の点が含まれているため、線の終端の描画を行っている様子。現状、内部データには不要と思われる。ただし、終端のみかどうか注意しておく必要はあると思われる。 |
drawPolygon() | ||
引数 | QPointF * | 線を描画するための点の配列。 |
int | 上記に含まれている点の数 | |
PolygonDrawMode | 描画モード。線の書き方、今、実装している範囲では、気にする必要は無さげ。 | |
戻り値 | void | |
処理 | 含まれている点を取り出して、線を引いて行く。 |
end() | ||
引数 | なし | |
戻り値 | bool | 終了の成否(true/false)を返す。 |
処理 | 保存していたデータを破棄して終了。正常な場合はtrueを返す。異常な場合はfalseを返す。 |
これを参考に、起動時にデータを読み込む実装をしたいと思います。
細切れでなんなんですが、つづく。
QPaintEngineの呼ばれ方の詳細の確認 [Qt]
前回で大体何が来ているのかが見えてきたので、今回はちゃんとSVGのデータと呼ばれた関数を精査していきます。回りくどい気がしますが・・。
さて、テストに使うのは次のデータ。
ま、何でもいいんですが・・。
で、SVGファイルの中身を見ていきます。・・・ソースをそのまま見ると見にくいので、XMLのデータとして、ツリー上に表示させたいんですが、なんか、いいツールはないんですかね・・。そのままFirefoxで表示させると画像として解釈してくれるので、拡張子を「.xml」に変更してみましたが、ちゃんとSVGと判断してくれてしまったりします・・。
仕方が無いので、Mac上で表示できないものか探してみましたところ、たくさんある様ですが、どれがいいのか探すのが面倒ですね・・。他のサイトで調べてみたところ、AquaPathと言うソフトが良さげですので、試してみました。最初は使い方が良くわかりませんでしたが、何とかツリー表示できました。
*
さて、どういうふうにまとめましょうかね・・。SVG自体をよく(と言うか全然)知らないので、入っているものを全部挙げて行ってみます。
以下、pathがあるパターンと、polylineがあるパターンと、何も無いパターンの繰り返しですね。「path」→「空」→「path」→「polyline」→「path」と言う感じでしょうか。
ログと見比べてみると、gに入るところで、metric()、updateState()が呼ばれ、pathでdrawPath()、polylineでdrawPolygon()が呼ばれてる感じですかね・・。metric()、updateState()の呼ばれ方がもう少し知りたい気がしますね・・。
drawPath()とdrawPolygon()の違いもよくわかりませんしねぇ・・。
う~ん、つづく。
さて、テストに使うのは次のデータ。
ま、何でもいいんですが・・。
で、SVGファイルの中身を見ていきます。・・・ソースをそのまま見ると見にくいので、XMLのデータとして、ツリー上に表示させたいんですが、なんか、いいツールはないんですかね・・。そのままFirefoxで表示させると画像として解釈してくれるので、拡張子を「.xml」に変更してみましたが、ちゃんとSVGと判断してくれてしまったりします・・。
仕方が無いので、Mac上で表示できないものか探してみましたところ、たくさんある様ですが、どれがいいのか探すのが面倒ですね・・。他のサイトで調べてみたところ、AquaPathと言うソフトが良さげですので、試してみました。最初は使い方が良くわかりませんでしたが、何とかツリー表示できました。
*
さて、どういうふうにまとめましょうかね・・。SVG自体をよく(と言うか全然)知らないので、入っているものを全部挙げて行ってみます。
svg | アトリビュートとして、width, height, vieBox, version, baseProfile等が設定されている。 | |||
tilte | タイトル? | |||
desc | 説明? | |||
defs | 何か定義がある場合に記述?データには何も記載なし。 | |||
g | アトリビュートとして、fill(none), stroke(black), vector-effect(non-scaling-stroke), stroke-width(1), fill-rule(evenodd), stroke-linecap(square), stroke-linejoin(bevel)が設定されている。 | |||
g | アトリビュートとしてfill(#000000), fill-opacity(1), stroke(none), transform(matrix(1,0,0,1,0,0)), font-famiy, font-size(10), font-weight(400), font-style(normal)が設定されている。 | |||
path | アトリビュートとしてfill-rule(evenodd), d(M56.5,100.5 L57.5,100.5 L57.5,101.5 L56.5,101.5 L56.5,100.5)が設定されている。 | |||
g | アトリビュートとして、fill(none), stroke(#000000), stroke-opacity(1), vector-effect(non-scaling-stroke), stroke-width(1), stroke-linecap(square), stroke-linejoin(bevel), transform(matrix(1,0,0,1,0,0), font-family, font-size(10), font-weight(400), font-style(normal)が設定されている。 | |||
g | アトリビュートとしてfill, fill-opacity, stroke, transform, font-famiy, font-size, font-weight, font-styleが設定されている。 | |||
path | アトリビュートとしてfill-rule, dが設定されている。 | |||
g | アトリビュートとして、fill(none), stroke(#000000), stroke-opacity(1), vector-effect(non-scaling-stroke), stroke-width(1), stroke-linecap(square), stroke-linejoin(bevel), transform(matrix(1,0,0,1,0,0), font-family, font-size(10), font-weight(400), font-style(normal)が設定されている。 | |||
polyline | アトリビュートとしてfill, pointsが設定されている。pointsは2点を設定しているように見える。これが、後5個つづいている | |||
g | アトリビュートとしてfill, fill-opacity, stroke, transform, font-famiy, font-size, font-weight, font-styleが設定されている。 | |||
path | アトリビュートとしてfill-rule, dが設定されている。 | |||
g | アトリビュートとして、fill, stroke, stroke-opacity, vector-effect, stroke-width, stroke-width, stroke-linecap, stroke-linejoin, transform, font-family, font-size, font-weight, font-styleが設定されている。 | |||
polyline | アトリビュートとしてfill, pointsが設定されている。pointsは2点を設定しているように見える。これが後11個つづいている。 | |||
g | アトリビュートとしてfill, fill-opacity, stroke, transform, font-famiy, font-size, font-weight, font-styleが設定されている。 | |||
path | アトリビュートとしてfill-rule, dが設定されている。 | |||
g | アトリビュートとしてfill, fill-opacity, stroke, transform, font-famiy, font-size, font-weight, font-styleが設定されている。中身は空。 | |||
g | アトリビュートとしてfill, fill-opacity, stroke, transform, font-famiy, font-size, font-weight, font-styleが設定されている。 | |||
path | アトリビュートとしてfill-rule, dが設定されている。 | |||
g | アトリビュートとして、fill, stroke, stroke-opacity, vector-effect, stroke-width, stroke-width, stroke-linecap, stroke-linejoin, transform, font-family, font-size, font-weight, font-styleが設定されている。 | |||
polyline | アトリビュートとしてfill, pointsが設定されている。pointsは2点を設定しているように見える。これが後3個つづいている。 |
以下、pathがあるパターンと、polylineがあるパターンと、何も無いパターンの繰り返しですね。「path」→「空」→「path」→「polyline」→「path」と言う感じでしょうか。
ログと見比べてみると、gに入るところで、metric()、updateState()が呼ばれ、pathでdrawPath()、polylineでdrawPolygon()が呼ばれてる感じですかね・・。metric()、updateState()の呼ばれ方がもう少し知りたい気がしますね・・。
drawPath()とdrawPolygon()の違いもよくわかりませんしねぇ・・。
う~ん、つづく。
QPaintEngineの呼ばれ方の確認 [Qt]
前回、試した中で、呼ばれている関数について、どのような実装が必要か確認しておきます。
これらを踏まえて、どういう値で呼ばれているのかを調べたところ、metric()は上述の通り。
updateState()がQPaintEngineState::state()の値が、0x203、0x011、0x002、0x011、以下0x002と0x011の繰り返しで、最後に0x20bで終わってます。これはQPaintEngine::DirtyFlagとして定義されている値で、表にするとこんな感じですか・・。
描画の際は特にPenなどの変更はしていないはずですが、頻繁に変わっているようですね・・。実装の際にはこの辺も注意していく必要があるかもしれません。
続いて、drawPath()。解析のため、保存する画像を横線一本にしているのですが、その場合で、要素が5個。最初の要素のQPainterPath::ElementTypeが0(MoveToElement)で、以降が1(LineToElement)となっています。同時にこれらのコンポーネントの座標が取得できるのですが、5つの座標がそれぞれ、(410.5, 175.5) (411.5, 175.5) (411.5, 176.5) (410.5, 176.5) (410.5, 175.5) となっています。これらは、線の終点の周辺の様な気がしていますが、正確にはよくわかりません・・。SVGデータと比較する必要がありますね・・。
最後に drawPolygon()。2点づつ数回呼ばれています。modeは「PolylineMode」ですね。drawPath()の内容が(458.5, 174.5) (459.5, 174.5) (459.5, 175.5) (458.5, 175.5) (458.5, 174.5)の場合の内容は下記の通り。
drawPath() の点は終点なんですかねぇ・・。整数と浮動小数点数で多少の誤差が出ていると言う感じでしょうか。
ま、何となく drawPolygon() から抜き取ることで何とかなりそうな気もしますが、ちゃんと動作を確かめたいので、SVGのファイルと見比べながら解析することにしますか・・。特に updateState() の通知内容がなぜ発生しているのかも見る必要がありますしね・・。
つづく。
begin | 書き込み先のQPaintDevice(ここではQtlDrawDataで保持するQPixmapが来る予定)を受け取るので、保持しておく。metricでそのパラメータを使用。 |
metric | 1(width), 2(height), 8(縦方向の解像度DPI)が要求されている。 |
updateState | QPaintEngineの状態が変わった時に通知されるそうです。QPaintEngineStateに何が変わったかが含まれているそうで、QPaintEngineState::state()で何が変わったかを取得せよとのこと。 |
drawPath | QPainterPathが渡されます。QPainterPathは描画要素が含まれるコンテナだとのこと。QPainterPath::elementCount()で要素数を取得し、QPainterPath::elementAt()で要素を取りだすことができる様子。 |
drawPolygon | 線を引くために複数の点を指定して呼ばれる様子。引数の点にQPointFを利用しているものとQPointを利用しているものがありますが、QPointFの方が呼ばれていました。 |
end | 終了の関数ですね。ま、必要な処理をすることにしましょう。 |
これらを踏まえて、どういう値で呼ばれているのかを調べたところ、metric()は上述の通り。
updateState()がQPaintEngineState::state()の値が、0x203、0x011、0x002、0x011、以下0x002と0x011の繰り返しで、最後に0x20bで終わってます。これはQPaintEngine::DirtyFlagとして定義されている値で、表にするとこんな感じですか・・。
0x203 | Hints | Brush | Pen |
0x011 | Background | Pen |
0x002 | Brush |
0x20b | Hints | Font | Brush | Pen |
描画の際は特にPenなどの変更はしていないはずですが、頻繁に変わっているようですね・・。実装の際にはこの辺も注意していく必要があるかもしれません。
続いて、drawPath()。解析のため、保存する画像を横線一本にしているのですが、その場合で、要素が5個。最初の要素のQPainterPath::ElementTypeが0(MoveToElement)で、以降が1(LineToElement)となっています。同時にこれらのコンポーネントの座標が取得できるのですが、5つの座標がそれぞれ、(410.5, 175.5) (411.5, 175.5) (411.5, 176.5) (410.5, 176.5) (410.5, 175.5) となっています。これらは、線の終点の周辺の様な気がしていますが、正確にはよくわかりません・・。SVGデータと比較する必要がありますね・・。
最後に drawPolygon()。2点づつ数回呼ばれています。modeは「PolylineMode」ですね。drawPath()の内容が(458.5, 174.5) (459.5, 174.5) (459.5, 175.5) (458.5, 175.5) (458.5, 174.5)の場合の内容は下記の通り。
mode | points |
3 | (119, 164)-(133, 157) |
3 | (133, 157)-(141, 156) |
3 | (141, 156)-(149, 157) |
3 | (149, 157)-(164, 160) |
3 | (164, 160)-(178, 163) |
3 | (178, 163)-(226, 167) |
3 | (226, 176)-(248, 167) |
3 | (248, 167)-(269, 169) |
3 | (269, 169)-(295, 176) |
3 | (295, 176)-(319, 180) |
3 | (319, 180)-(342, 182) |
3 | (342, 182)-(359, 183) |
3 | (359, 183)-(375, 187) |
3 | (375, 187)-(393, 187) |
3 | (393, 187)-(411, 184) |
3 | (411, 184)-(424, 184) |
3 | (424, 184)-(441, 183) |
3 | (441, 183)-(451, 179) |
3 | (451, 179)-(459, 175) |
drawPath() の点は終点なんですかねぇ・・。整数と浮動小数点数で多少の誤差が出ていると言う感じでしょうか。
ま、何となく drawPolygon() から抜き取ることで何とかなりそうな気もしますが、ちゃんと動作を確かめたいので、SVGのファイルと見比べながら解析することにしますか・・。特に updateState() の通知内容がなぜ発生しているのかも見る必要がありますしね・・。
つづく。
QPaintEngineの利用 [Qt]
さて、QPainterの派生に行き詰って、どうしようかとQtのPaint Systemに関するドキュメントを読み直してみたところ、QPaintEngineと言うクラスがQPainterとQPaintDeviceの間にかんでます。
QPaintEngineを見たところ、ほぼ全てのメンバ関数が仮想関数となっています。これが使えるかなとより詳しく読んで行ったところ、どうやらQPainterはQPaintDevice::paintEngine()からQPaintEngineを取得してそれを利用する様子。実際に描画を行っているのはQPaintEngineみたいですね。QPaintEngineのメンバ関数はほとんどが仮想関数なため、派生したクラスを渡せば問題無く自作の関数が呼ばれそうです。と言うより、自前のQPaintDeviceを作成する際には、自前のQPaintEngineを作成して描画を実現するのが、まっとうなやり方の様です。よく見たら、QSvgGeneratorもまさにその方法を使っている様ですね。
*
と言うことで、QSvgRendererからの指示を内部データに変換するためにダイレクトにQPainterを派生しようとしていたのを、QPaintEngineの派生クラスと、その派生クラスを利用する変換用のQPaintDeviceの派生クラスを作成して実現することにします。一応、新たにクラスを作り直し、前のQPainterの派生クラスで流用できるところは流用していくことにしましょう。QPaintEngineはQPainterに比べて、メンバ関数が簡素になっています。QPainterでオーバーロードされていた便利関数が全て無くなっているようです。
さて、実装していてふと気になったのが、QPaintDeviceが返しているwidth()とかheight()など、QPaintDeviceの状態を返す関数です。すべて仮想関数になっていないため、これらをオーバーライドしても正しく応答できません・・。どうすんのかな〜と探していたら、metricと言う関数がprotectedな仮想関数として用意されていました。内部情報を返す関数だとか。これを実装すれば良さそうですね。
*
相変わらず、初歩的なエラーを出しながら、なんとかコードが完了して実行することができました。線を引いただけのSVGデータで、呼ばれた関数は「QtlSvgConvertor::metric()」「QtlSvgConvEngine::begin()」「QtlSvgConvEngine::updateState()」「QtlSvgConvEngine::drawPath()」「QtlSvgConvEngine::drawPolygon()」、そして「QtlSvgConvEngine::end()」の様です。
「QtlSvgConvertor::metric()」は一応、何が設定されて呼ばれるのかログを仕込んどいたのですが、width、heightとDpiYが設定されています。そして割と頻繁に呼ばれています。DpiがYだけなのが不思議ですね・・。後、「QtlSvgConvEngine::drawPath()」と「QtlSvgConvEngine::drawPolygon()」はどういう使い分けをされているのでしょうか?まあ、点の多さですかね。後、「QtlSvgConvEngine::updateState()」って、なんじゃ?という観点で調べていきたいと思います。
つづく。
QPaintEngineを見たところ、ほぼ全てのメンバ関数が仮想関数となっています。これが使えるかなとより詳しく読んで行ったところ、どうやらQPainterはQPaintDevice::paintEngine()からQPaintEngineを取得してそれを利用する様子。実際に描画を行っているのはQPaintEngineみたいですね。QPaintEngineのメンバ関数はほとんどが仮想関数なため、派生したクラスを渡せば問題無く自作の関数が呼ばれそうです。と言うより、自前のQPaintDeviceを作成する際には、自前のQPaintEngineを作成して描画を実現するのが、まっとうなやり方の様です。よく見たら、QSvgGeneratorもまさにその方法を使っている様ですね。
*
と言うことで、QSvgRendererからの指示を内部データに変換するためにダイレクトにQPainterを派生しようとしていたのを、QPaintEngineの派生クラスと、その派生クラスを利用する変換用のQPaintDeviceの派生クラスを作成して実現することにします。一応、新たにクラスを作り直し、前のQPainterの派生クラスで流用できるところは流用していくことにしましょう。QPaintEngineはQPainterに比べて、メンバ関数が簡素になっています。QPainterでオーバーロードされていた便利関数が全て無くなっているようです。
さて、実装していてふと気になったのが、QPaintDeviceが返しているwidth()とかheight()など、QPaintDeviceの状態を返す関数です。すべて仮想関数になっていないため、これらをオーバーライドしても正しく応答できません・・。どうすんのかな〜と探していたら、metricと言う関数がprotectedな仮想関数として用意されていました。内部情報を返す関数だとか。これを実装すれば良さそうですね。
*
相変わらず、初歩的なエラーを出しながら、なんとかコードが完了して実行することができました。線を引いただけのSVGデータで、呼ばれた関数は「QtlSvgConvertor::metric()」「QtlSvgConvEngine::begin()」「QtlSvgConvEngine::updateState()」「QtlSvgConvEngine::drawPath()」「QtlSvgConvEngine::drawPolygon()」、そして「QtlSvgConvEngine::end()」の様です。
「QtlSvgConvertor::metric()」は一応、何が設定されて呼ばれるのかログを仕込んどいたのですが、width、heightとDpiYが設定されています。そして割と頻繁に呼ばれています。DpiがYだけなのが不思議ですね・・。後、「QtlSvgConvEngine::drawPath()」と「QtlSvgConvEngine::drawPolygon()」はどういう使い分けをされているのでしょうか?まあ、点の多さですかね。後、「QtlSvgConvEngine::updateState()」って、なんじゃ?という観点で調べていきたいと思います。
つづく。
VYM [Qt]
今回ちょっと、休憩です。NetWalkerでアイデア出しにVYM(View Your Mind)と言うマインドマップのツールを使っているのですが、Macでも見れないのかなと探していたところ、なんとMac版も配布されていました。バージョンは1.12.6で、ソースのみですけどね。
よく見てみるとユーザインタフェースがQtだとのこと。Qtは開発環境をMacにも入れていますし、試しにビルドしてみたところ、たくさん警告が出てたものの、ビルドは完了し、問題なく動いたりしました。
何事も無く起動
せっかくなので、特にMac用とも書かれていませんが、最新バージョンの 1.12.7 のソースも試しに落としてみました。ビルドしたところ、こちらもたくさん警告は出たもののビルド完了。問題なく動きました。
これ、1.12.7は特にMacを意識せずにアップデートしたけど、Macでも問題がでないということなんですかね?たぶん、コンフィギュレーションなどはMac用の記述も含まれているんじゃないかと思いますが、これが、Qtのおかげならかなり魅力的に感じたりします。
早く、自由にかけるようになりたいですねぇ・・。
よく見てみるとユーザインタフェースがQtだとのこと。Qtは開発環境をMacにも入れていますし、試しにビルドしてみたところ、たくさん警告が出てたものの、ビルドは完了し、問題なく動いたりしました。
何事も無く起動
せっかくなので、特にMac用とも書かれていませんが、最新バージョンの 1.12.7 のソースも試しに落としてみました。ビルドしたところ、こちらもたくさん警告は出たもののビルド完了。問題なく動きました。
これ、1.12.7は特にMacを意識せずにアップデートしたけど、Macでも問題がでないということなんですかね?たぶん、コンフィギュレーションなどはMac用の記述も含まれているんじゃないかと思いますが、これが、Qtのおかげならかなり魅力的に感じたりします。
早く、自由にかけるようになりたいですねぇ・・。