QtとWindowsと流川ガールズと

Qtと沙織さんのお話。

Creatorも含めてQtでコードを書くと言うのは基本的にプラットフォーム依存を少なく出来る、と言う利点があると思うのだけど、実際は書いてると結構出てくる。別件で書いてるOpenGL周りのコードもQt+Creatorを使っているけど、そりゃあもうね。

なのだけど、saoriに関しては当初から「できるだけQtに依存して同一コードを以って特定環境で動かないところを無くしてみよう」と考えて書いております。まあ、いつまでこれ続けられるかは謎ですけどねえ。
結果、実は現状同じコードでWindows上でも動きます。


素敵ですねえ。
まあandroidは素晴らしいクライアントが存在するから試す気も無いし、アポー系は宗教上の理由で試す環境が無いのでWindowsしか試してませんが、Windwos10のノートPCで出先で思いついた修正をさくっと出来て試せるのはそれだけでも素晴らしいし便利ですねえ。

とは言え、既に問題は見つかっていて、例えばWindowsでQNetworkReply::readAll()が空な場合がある、とかね。色々調べた結果どうも一定データ量を超えるとダメっぽくて、最終的に落ち着いたのが「タイムラインの取得量(limit=で指定するんですが)を若干小さくすることで回避」だったりします。内部バッファ量の違いかなーと思ったりもするんですが、このへんはQtのコード見てみないとなんとも。Windowsの場合OpenSSL周りも別個用意してたりするわけだったりするのでこの辺の差もあるのかも。

もうひとつはまりかけたのが、変数長の違い。
statusのidを保存するのに最初longを使ってたのだけど、どうもWindowsだとおかしくなる、結局qlonglongに落ち着いたのだけど、後で気になってlimit.h見てみたら、linux(64)だとlong=longlong、Windows(64)だとint=long、うおおおい!って感じ。難しい。

まあどこまで頑張れるかは分かりませんが、一応Windowsでもコンパイルして動かしてみてますよと言うお話。

Qtとmastodonと糞コードと流川ガールズと

お久しぶりどころか、あけましておめでとうですが、すっかり春めいてといいますかやや暑い日もあったりする梅雨前のひととき、皆様いかがお過ごしでしょうか。

えーとりあえずmastodonクライアントを昨年から作ってて本当は年末には見せびらかす予定だったんですけど、色々バタバタしまして気がつけばゴールデンウィークですよ。まあいいんですけど。
と言うわけで、機能足らなすぎで作りかけ感満載ですが、

沙織さんです。見ての通りマルチアカウント対応のMDIクライアント。名前の由来は特にありませんが、俺は流川ガールズが大好きです。

現状できることと言うのは本当に少なく、インスタンスに接続して一部タイムラインや通知を読み出すくらいです。Tootもまだ出来ませんし画面には機能しないボタンが並んでいたりしますが、まあmastodonにおけるごくごく基本的な「認証してアクセストークンをゲットしてJSONデータを得る」は実装されております。

コード化結構簡単ですので是非皆さんも手作りmastodonクライアント挑戦して欲しい感じですかねえ。まあ色々勉強になったところもあるので、何回かに分けてこのへん日記にまとめようかな。

以下、認証まわりのコード的な話。

twitterクライアントもそうなんだけど、ぶっちゃけアクセストークンを取得してAPIに正しくアクセスできれば後はデータをいじるだけ、mastodonはJSONでデータくれるのでQtのQJsonDocument他をごっそり使うことで手軽に得たデータを利用できます。素晴らしいですねえ。

ポイントはどうやって認証するのって話ですが、saoriでは

  1. Saoridonクラスでクライアント登録。
  2. SaoriAddAccountDialogで認証、アクセストークン取得。
  3. SaoriAccountに情報を保存、アクセス時もここからAPIにアクセス。

こんな感じの流れになってます。

相変わらずコードにコメントを書かない糞コード書きなのでわかりにくいですが、Saoridon::clientRedistration()でクライアントをインスタンスに登録します。
若干ずるのようなイメージもありますがQEventLoopを回してQNetworkAccessManagerからのQNetworkReplyをその場でもらうと言うテク、これ便利で結構使ってしまいますがさておき。

登録が済んだらclient_secretとclient_idがJSONで帰ってきますので、今度はSaoriAddAccountDialogでアクセストークンを取ります。実際は上のクライアント登録もこのダイアログでやるんだけどね。
Saoridon::getAuthorizedUrl()でURLを作りWebブラウザで開いて認証、コードをコピーしてそれをSaoridon::getAccessToken()で渡すとアクセストークンが返ってくる、と言う手順ですねえ(grant_typeはauthorization_codeです)。SaoriAddAccountDialog自体はボタンを押せなくしたり複雑に組んでありますが、実際に必要なコードはSaoridonの方にほぼほぼまとめられています。

で、client_idとclient_secretからaccess_tokenとれたらそれをSaoriAccountに保存し、実際のAPIアクセスはこのクラスからアクセス、と言う感じです。
アクセストークンはヘッダにぶち込むだけでいいのでSaoriAccount::createHeader()を見てもらえば簡単かと。あとは、mastodonのAPIとにらめっこどぞー、って感じですね。

ここまでくればQNetworkReplyでJSON取れますからあとは煮るなり焼くなり。QJsonObjectで取得してHTMLに整形してQTextBrowserに流しこむ、と言うことをsaoriではやってますが、この辺はまた今度。

QtとC++でモダンなOpenGLプログラムを書いてみる

shaderを基本としたモッダーンなOpenGLプログラムをQtとC++で書こうって話。Qt5.9を使ってますが5.7あたりでもいけるんじゃないでしょうか。compute shaderがサポートされたのは5.9からのような気もしますが、別にQOpenGLFunctions_4_3_Coreとか使えばそれ以前からも使えないことはない…まあ、そのへんはいいか。

QtでOpenGLを使うと良い点と言えば、とりあえず色んな環境で動くようにコンパイルできることとか、ウィンドウ操作周りやらマウス入力系等をQt一式に任せられるとか、おなじみsignal/slotでのコードが書けるとか、まあ色々ありますが、個人的にQt大好きっ子ですので「かっこいい」が一番ですかねえ。
と言うことで、QtっぽくOpenGLのコードを書くぜーと言う感じでGo。

続きを読む

Qt5.5開発環境をWindows10にぶちこむよ

前置きはいりません、はいぶち込みましょう。

コンパイラはVS2013Expressにします。2015はいけるんでしょうか。分かりません。

Qtぶちこみます。VS2013の32/64bit版でいきましょうか。

QtCreator立ち上がるぜ。

早速サンプルをコンパイル。簡単なものですねえ…。

以上。簡単ですねえ。

trac+gitolite

 最近のQtはWindowsのMetroUIにも対応しててすげえなあと思うTAMです。ちょっと凄いですよねえ。手持ちの自作プログラムをコンパイルしてWindowsタブレットにぶちこんで持ち歩きたい気分になります。まあこの話は追々。

 
 rcs→cvs→svn→そしてgit。「ぼっち開発にRCSなんていらんのですよ」とか考えちゃったりもするかも知れませんが、これらの仕組みに共通して言えるのはぼっち開発でもとても便利と言うこと。ごっそりコード書き換えて「おい動かねえ…」とかなってもすぐrevertできると言うだけで気分楽ですものねえ。
 とは言え、色々と変わりすぎじゃないかしらねえ、ってのはあるかなあ。cvsを必死でお勉強してやっと使える感じになったと思ったらsvn出てきて、svn便利っすねー!とか思ってたらgitが流行りだして…と。まあでも、流行に乗っておくと色々とお得と言えばお得です。情報ももりもり出てくるし、なにより、もしかしたらいずれぼっち開発じゃなくなった時にリポジトリをさくっと公開できる…、できる…。
 まあ、個人でバックアップ目的で、なんて言うのなら俺的にはsvnローカルリポジトリをおすすめするのですがね。簡単だし。
 
 で、世の中にはtracと言う素晴らしいものがありまして。元々svnとセットで使う仕組みだったような気がしますが、Wiki、チケット、マイルストーンなんかをリポジトリとセットで管理できるWebツール。これがもうすごぶる便利。TAMも以前からずっと愛用しておりましたが、手元の環境を見たところtrac0.11.7+GitConnector+gitosisってな感じでやや化石。こいつをちょっと、ナウでヤングでモダンな環境にしようじゃないですか、と言う感じです。
 
 と言うわけで、ubuntu14.04にこいつらセットでぶち込みましょう!、と言う感じなのですが、とりあえず過去の環境においてのgitosisが頂けません。何が頂けないのかと言いますと、ubuntuではgitoliteに置き換わってんですよねえ。
 ただまあ、考え方は同じと言うか近いので、gitosis使ってたよーって方は比較的簡単に移行できるんじゃないですかねえ。
 追々のため、gitoliteユーザのホームディレクトリにある”.gitolite.rc”ってファイルの$REPO_UMASKのところを022に修正しておきます。あまりよろしく無い修正とも思いますが、あくまで個人用と考えるとこれしとくと後で結構楽になります。
 
 本命のtrac。
 バージョンは1.0.1なんだそう。ubuntu14.04で入れるんだったらtrac周り一式になりますかねえ。GitConnectorは本体に含まれてるようなので何故かあるtrac-gitパッケージはいらないような気がします。いや、いるのかも知れないけど設定で無効化してんだよねえ。
 TracAccountManagerは便利。あくまで個人用として使うならまあ、お母ちゃんにいたずらされない程度の権限管理は欲しいところですから、これでさくっとユーザを作ってしまうのがいいのではないでしょうか。外で使うならこれにSSLクライアント認証もぶち込んで…とかね。
 余談なのですが、OpenSSLの証明書発行周りで便利なGUIないかなーと思って色々試したのですけど、YaSTのCA管理メニューがよく出来てるように思えました。完全に余談ですが。
 
 で、ここまできたらもうtracすげえできるわけなんですが、最終的にgitリポジトリと連動させるってことになります。これがもうやばくてですね、色つきdiff画面とか、wikiやチケットでリビジョンへのリンクが簡単に貼れたりとか、コミットログにチケットへのリンクを埋め込めたりとか、便利なんですよ本当に。
 んで、リポジトリを指定してやるわけですが、正直全力でおすすめできる形ではありませんが、gitoliteの設定でumaskを調整しておりますので、ここでgitoliteのリポジトリをそのまま指定してやることができたりします。そうしないのであれば、どこかにリポジトリのミラーを作ってフックかけて…的なことになるように思えますが、個人用でいくならこれが楽なんじゃないでしょうか。
 
 とまあ、ここまでいきますと、むちゃくちゃ便利でございます。wikiにさくっとメモって、忘れそうなことはチケットに、期日を切りたければマイルストーンを設定し、リポジトリの修正箇所も色付きでみやすく!。
 まあ本来複数人で作業するのによろしいものなのですが、個人で使うにしてもかなり便利です。最近のtracは1つのtracで複数のリポジトリを関連付けることもできるようなので、リポジトリ増えたからtracも増殖…なんてこともなさげ。是非皆様もご家庭に1台trac。
 最近はgitと連動できるこの手のものはtrac以外にもあるみたいですが、「迷ったらtrac、覚えておくといいわ…」とマールーさんも言っておりました、俺の脳内で。

QNetworkAccessManagerでtwitterに凸

ネットワーク上から何かしらデータを持ってくる作業と言うのは時々出てくるわけだ。twitterクライアントにしてもQOAuthでOAuthはパスできたにせよ、そのURLからデータを持ってこないとAPIアクセスはできないわけで。

と言うわけでさくっとwgetのような感じでURLからもってこいやあ!ってな実装。

  1. QNetworkAccessManagerを用意します。
  2. QNetworkAccessManager::finished(QNetworkReply*)と言うシグナルと適当なスロットをconnect。
  3. QNetworkRequestを作ってQNetworkAccessManager::get()を叩く。
  4. スロットでQNetworkReply*をあされ!。

以上。

やることはQNetworkRequestを作って読み込み開始してあとはシグナル待ちだけで済むって言う。シンプルやなー。素敵。

QNetworkReply::readAll()でもってきたデータをQByteArrayで拾えたりします。QNetworkRequestにQOAuthで作ったtwitterのAPIに渡すURLを指定してやればあっさりAPIにアクセスできるのよ。

んで拾ってきたXMLを解析してprofile_image_urlを同じようにQNetworkAccessManager経由で取得してやると、

あっさりアイコン付きに。

余談。

profile_image_urlの表示にQGraphicsWebViewを使ったらどうなるのかな?、とか思ってやってみたのだけど、普通に表示されました。が、rotateしたときに画像は回転しているものの枠が残っちゃうのよね。なのでQImageで取得した上でQGraphicsPixmapItemに。

QGraphicsItemはQObjectじゃないよなー、どうやってQImageのやりとりしよっかなーとか考えたり。アイコン一つ表示させるためにわざわざ取得用クラスを作ったり、地味に手間かかったやんよー。

「そもそもなんでお前はそんなに回したいんだ?」って感じですが、なんでだろう。でもなんかQGraphicsViewを折角使ってるんだし拡縮したり回したりしたいじゃんよ!。

QGraphicsViewでtwitterに凸

と言うわけで前にも言ったけどQOAuth使ってtwitterからXML取れてQDomDocument使ってtweetをクラスに放り込めたのであとはお好みのUI組み込むだけで俺仕様のtwitterクライアントのできあがりとなっちゃう。tweet自体をメモリに取り込んでるわけだからそこから検索するなりスコアリングするなり好きにできるのでもうつぶやきに埋もれて窒息することもないぜ!、とまではいかないけども。

で、UIの話。

普通にdesignerなんかでUI作ってもいいんだけど、折角ですからQGraphicsView使おうぜ!と言う方向でちと遊んでみる。

QGraphicsViewのいいところは通常のレイアウトを使ったWidgetの配置と違ってその自由度の高さってことになると思います。逆に言うと自由であるが故にぐちゃぐちゃにもなるって感じ。

線やテキストなんかをシーンに配置して、そのシーン(QGraphicsSceneかな)をQGraphicsViewに結びつけて表示、表示するオブジェクトに関してはQGraphicsItemと言う形でアクセスする、って感じなのですが、これがQWidgetも置くことができるわけで。アクセス方法がQGraphicsProxyWidgetってのになりますが。

ざっくりと表示例を上げると、

どーん。QLabelを使ったWidgetがscaleとrotateされてならんだりとか。

で、こいつらWidgetなので当然ボタンとかを配置して押すこともできたり。楽しいですよね。

ただ、回転なんかをかけ始めるとどうも動作が重く。そりゃそうだわなーと言う感じですが、assistantなんかを参照していただければ分かるのですが、QGLWidgetを使うこともできて、そっち使うと結構早いです。しかもQGraphicsView::setViewport()でQGLWidgetをnewして渡すだけ。

くるくる回したりズームさせたり。UI作りって楽しいですよねー。まあ、ほんと一歩間違えればぐっちゃぐちゃになるけどね!。

QDomDocumentでtwitterに凸

QDomDocumentのサンプルコードはQDomNode→QDomElementと変換してってコードになっとおけど、QDomElement::firstChild()じゃなくてもQDomElement::firstChildElement()なんて言うそのまんまの名前のものもあったりして。こりゃ使うっきゃない。どうしてもだらだらしがちだしね。

以前のQOAuth周りでゲットできたXMLをざざざーっと適当な構造体配列に突っ込む感じで。

ぶっちゃけOAuth経由でアクセスできて、XMLが取得さえできてしまえばあとは正直どうとでもなる。適当にメモリ上に格納できてしまえばあとは煮るなり焼くなり好きにした上でUIでもつけりゃtwitterクライアントのできあがり。まあ、投稿部分スルーしてるけどね。

以前上げたQOAuthのんと組み合わせれば簡単なコマンドライン型クライアントとかならさくっと作れるんじゃないでしょうか。俺は作りませんけどね。

しかしtwitterの吐くXML、status毎にuser情報持ってたりとかしていやに長い。できるだけ一回のアクセスで情報を流すって工夫だとは思うんだけど、RT元とRT自体の情報を1つのstatusが持ってたりとかするのね。いいのか悪いのかは分からんなあ。まあ取り込んで解析さえしてしまえば同じっちゃあそうだけど。

さて。

例によってかいつまむよー。ちょっとだらだら長いよー。

続きを読む

QOAuthでtwitterに凸その2

例によってぬっぽりかいつまむ。

 

 

 

    QOAuth::Interface qoauth;
    qoauth.setConsumerKey(NOPTTER_CONSUMER_KEY);
    qoauth.setConsumerSecret(NOPTTER_CONSUMER_SECRET);
    QOAuth::ParamMap map;
    QByteArray url = "http://api.twitter.com/1/statuses/home_timeline.xml";
    QByteArray attr = qoauth.createParametersString(url,
                                                      QOAuth::GET,
                                                      config.value("token").toByteArray(),
                                                      config.value("secret").toByteArray(),
                                                      QOAuth::HMAC_SHA1,
                                                      map,QOAuth::ParseForInlineQuery);
    qDebug() << url.append(attr);

 

 

urlをwgetでもするとごにょごにょ…。