需要のないページ

プログラミングや趣味や。

Condaを使ってTensorFlowの野良ビルドを導入する

前書き

前回の記事の続きっちゃ続き。環境は、Windows10の64bit機だ。

ただし、この記事ではCPU版のインストールだけ実践する。

 

TensorFlowは、深層学習によく用いられるフレームワークである。

公式サイトは、次のように説明している。

TensorFlow™ is an open source software library for numerical computation using data flow graphs.

使いづらいと揶揄されるが、あくまで本質は計算ライブラリのようだ。

 

TensorFlowのインストール (公式による)

公式サイトが簡潔なインフォメーションを出している。

適当にまとめてみる。(稚拙な和訳/強引な意訳)

  • CPUのみをサポートするものと、GPUも利用するものとの二種類がある
  • GPUが利用できる環境は次の通り
    • CUDA Toolkit 8.0が入っていて、パスが通っている
    • 上記CUDAに対応するNVIDIAドライバが搭載されている
    • cuDNN v5.1が入っていて、パスが通っている
    • GPUのCompute Capabilityが3.0以上である
  • GPUが利用できる場合も、まずはCPU版を試してみることを勧める

 

  • インストールの際は、次の二通りの方法がある
    • "native" pipを利用するもの (推奨)
      • pip3 install --upgrade tensorflow
      • pip3 install --upgrade tensorflow-gpu
    • Anacondaを利用するもの (公式のサポート外)
      • pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/windows/cpu/tensorflow-1.1.0-cp35-cp35m-win_amd64.whl
      • pip install --ignore-installed --upgrade https://storage.googleapis.com/tensorflow/windows/gpu/tensorflow_gpu-1.1.0-cp35-cp35m-win_amd64.whl

 

このインフォは親切だが、condaを用いたインストールは出来ないのだろうか?

 

TensorFlowのインストール (condaを用いる)

予め確認しておくが、この方法は公式に保証されたものではない。

こだわりなくインストールしたいのなら、native pipを用いるのが確実だ。

 

野良ビルドリポジトリは、Anaconda Cloudで検索できる*1

適合する条件をちょいちょい入力すると、次の結果が表示された。

f:id:LouiS:20170606164033p:plain

投稿現在(2017/06)、4件のリポジトリが表示される。リンクはこちら

 

この中で最もダウンロード数の多い、一番上の候補を選んだ。

緑色のリンクをクリックすると、インストールコマンドが表示される。

conda install -c conda-forge tensorflow=1.1.0

こいつをAnacondaプロンプトに叩き込んでやればよい。

 

以下、実際のプロンプト画面。

前もって、Python3.5の仮想環境をactivateしていることに注意されたい。

f:id:LouiS:20170606165401p:plain

 

PyCharmで試してみる

公式インフォQiitaの投稿を参考に、次のテストコードを実行してみた。

 

ほぼほぼパクリだが、先頭二行のコードで警告レベルを変更した。

当初この二行を除いて実行した結果、怒涛のWarningに襲われたからである。

C:\Users\[UserName]\AppData\Local\conda\conda\envs\python35\python.exe C:/Users/[UserName]/temp/py35test/test.py
2017-06-06 17:18:42.845745: W c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE instructions, but these are available on your machine and could speed up CPU computations.
2017-06-06 17:18:42.863110: W c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE2 instructions, but these are available on your machine and could speed up CPU computations.
2017-06-06 17:18:42.863465: W c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE3 instructions, but these are available on your machine and could speed up CPU computations.
2017-06-06 17:18:42.863802: W c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations.
2017-06-06 17:18:42.864145: W c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.
2017-06-06 17:18:42.864488: W c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations.
2017-06-06 17:18:42.864843: W c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX2 instructions, but these are available on your machine and could speed up CPU computations.
2017-06-06 17:18:42.865197: W c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\platform\cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use FMA instructions, but these are available on your machine and could speed up CPU computations.
b'Hello, TensorFlow!'
32
Process finished with exit code 0

適切に実行されているようであるが、警告がなんにせようざったい。

 

適宜検索検討して、これらの警告をにぎりつぶすことに決めた。

  1. これらの警告は、CPUの拡張命令をフルに活かせていないことを指摘するもので、自前でビルドしなおすことで解消される。

  2.  ビルドしなおすと確かに速くなるが、その効果は限定的で、それだったらGPUを使える環境を整える方が圧倒的に理にかなっている。

  3. 頑張ってCPUの実行速度を最適化しても、GPUの実行速度には影響しない。(GPUの方が圧倒的に貢献度が高い状況だと、CPUに合わせてチューニングしても意味が薄い)

 

警告レベルを変えれば、(当たり前だが)表面上はすっきり実行される。

C:\Users\[UserName]\AppData\Local\conda\conda\envs\python35\python.exe C:/Users/[UserName]/temp/py35test/test.py
b'Hello, TensorFlow!'
32

Process finished with exit code 0

 

せっかくなので

せっかくなのでKerasも叩き込んだ。

conda install -c conda-forge keras=2.0.2

f:id:LouiS:20170607162451p:plain

まだ試していないが。

 

後書き

上記の例では、TensowFlowの機能の1%も使えていないだろう。

GitHubからTensorFlowを活用したリポジトリを落として、解析しなければ。

なお、ボトムアップ的(?)な学習には、以下の公式ページが参考になりそうだ。

あと、GPU試す。これ大事。

*1:サインインしなくても普通に使える

Python食わず嫌いな人間が環境を作ってみた [Miniconda + PyCharm]

前書き

C++畑で育った人間として、Pythonはとても気持ち悪く思える。

動的型付けなんて黒魔術みたいだ/バイナリファイルを作りたい/etc.

しかし、『使えない』のと『使わない』のとは全く違う。

最低限は試してみようと、環境を構築してみることにした。

なお、使用OSはWindows10の64bit機。

 

導入の方針

次のサイトが非常に参考になる。

qiita.com

他にもいろいろなサイトを巡ってみて、次のような方針を決めた。

  • ディストリビューションとしてMinicondaを使用
  • 基本的に仮想環境上でPythonの実行を行う
    • 諸般の事情により、2.7と3.5、3.6を同居させたい
    • 環境それぞれに必要なパッケージを導入するつもり
  • pipやwheelにはできる限り頼らない
  • IDEとしてはJetBrains社のPyCharmを用いる

こんな感じ。さっそく始める。

 

Minicondaのインストー

公式サイトからMinicondaインストーラを入手できる。

最新バージョンを落とせば古いPythonの環境も作れる。

特に理由がなければ、一番新しいバージョンをダウンロードするのがよい。

インストールも、嫌らしいデフォルト設定などないのでポチポチでOK。

 

インストールすると、スタートメニューにプロンプトが追加されている筈だ。

f:id:LouiS:20170604192206p:plain

素晴らしいMiniconda。非常にシンプルな構成である。

 

プロンプトを開き、現在インストールされているパッケージを見てみる。

conda list -n root

f:id:LouiS:20170604203237p:plain

-n rootは不要だが、ルート設定であるということを明示するために入れてみた。

この結果を見ても、NumPyなどがプリインストールされていないことがわかる。

 

仮想環境の構築

さて、仮想環境の構築とカスタマイズをしてみよう。

仮想環境を作るためには、プロンプトに次のように打ち込めばよい。

conda create -n [環境名] python=[バージョン]

 

実際の画面は次のようである。

f:id:LouiS:20170604205542p:plain

『次のパッケージを入れるけど、いい?』と聞いてくれたり、

具体的な使い方を指南してくれるあたり、非常に親切である。(若干感動した)

ただ、案外時間がかかる印象はあった。

 

Pythonインタプリタ本体は、赤線部のディレクトリに入っている。

後でPyCharmのセッティングをするときに使うので、確認しておこう。

 

パッケージのインストー

仮想環境に必要なパッケージをインストールしていこう。

ここでは、プログラマに(おそらく)必須であろう、NumPySciPyを入れてみる。

 

他のページを見てみると、-nオプションで環境指定してインストー*1している。

しかしここでは、環境をactivateしてからインストールする方法を取りたい。

なぜか?―私がしばしばオプションを付け忘れるからである!(仮想環境作った意味)

 

具体的には、次のように命令を打ち込む。

activate [環境名]

conda install numpy scipy

パッケージは同時に複数インストールでき、バージョンも指定できる。

実際の画面は次のようである。

f:id:LouiS:20170604215052p:plain

プロンプトの左側に、activateな環境が書かれている。つくづく親切である。

 

Anacondaプロンプトを使った操作は、基本の基本は以上でおしまい。

ググれば他にもたくさん命令が出てくるので、見てみるとよいだろう。

なお、公式のチートシートが公開されている。

 

PyCharmを使ってみる

Intellij IDEAを使ってからJetBrainsに惚れているので、PyCharmを採用した。

インストーラ公式サイトからダウンロードできる。

 

インストールにあたり、いじったオプションは一か所だけ。

f:id:LouiS:20170604231403p:plain

今までVSCodeで見ていたpyファイルを、PyCharmに結び付けることにした。

 

インストール後、とりあえず起動し、Look and Feelを好みに合わせる。

ここら辺はこだわりがないのならデフォルトで一切問題がない。

 

プロジェクトをつくる際、インタプリタを指定する必要がある。

f:id:LouiS:20170604231938p:plain

Interpreter右端にある歯車のボタン→Add Localで、環境を指定する。

私の環境の場合、次を指定した。

C:\Users\[ユーザ名]\AppData\Local\conda\conda\envs\python35\python.exe

 

目当てのインタプリタが見つからない場合、次のようにすればわかる。

f:id:LouiS:20170604234739p:plain

さりげなくAnacondaプロンプト再登場である。

なお、おそらくそのディレクトリにはpythonw.exeも存在する。

直下のページが検討しているとおり、あまり気にしなくてよいようだ。

blog.shibayan.jp

 

プロジェクトを作れたら、次のコードを打ち込んでみる。

f:id:LouiS:20170604235907p:plain

実行すると、リストが出力されるはずだ。

 

なお、File→Settings→Project: [name]→Project Interpreterを見ると、

いま使われているインタプリタと、導入できるパッケージが見られる。

f:id:LouiS:20170605002657p:plain

また、同じ画面からインタプリタの変更もできる。

試しにPython2系に変更してみると、エラーが出てくるだろう。

 

Anacondaだけで対応できないとき

Anacondaは便利だが、入手できないパッケージもしばしばあるらしい。

以下のページに、その解決法が書いてあった。

ど素人なので今見ても全然わからないが、そのうちお世話になりそう。

 

後書き

冒頭で述べたようにPythonの気味の悪さのようなものを感じている。

また、以前にpipでハマったこともあり、苦手意識はかなりあった。

しかし、Anacondaを使いこなせれば、ストレスも減るのかと思う。

 

実は、PythonはTensorFlowを利用するために導入してみた。

*1:conda install -n [環境名] [パッケージ名]

定数M_PIが使えない

能書き

かなり間があいたので、小ネタ。

毎度ながら、知ってる人にとっては当たり前の内容を有難そうに書く。

 

遭遇したエラー

例えば、次のようなコードを書いたとする。

まあ、半径から円の面積を計算するだけの、よく見るコードだ。

 

ただし、円周率を自前で定義しているあたり、このコードはモダンでない。

_USE_MATH_DEFINESフラグを立ててcmathをインクルードしたほうがよい。

上記のコードのdefine文を単に置き換えると次のようになる。

しかし、このコードをコンパイルすると... 次のようなエラーが出る。

error C2065: 'M_PI': 定義されていない識別子です。
error C2065: 'M_PI': undeclared identifier

 

原因と対策

実はこれ、ヘッダファイルを読み込む順序が問題なのである。

エラーが出たコードでは、フラグを立てる前にiostreamを読み込んでいた。

 

iostreamヘッダのインクルードを追ってみると:

  • iostreamは、istreamをインクルードしている。
  • istreamは、ostreamをインクルードしている。
  • ostreamは、iosをインクルードしている。
  • iosは、xlocnumをインクルードしている。
  • xlocnumは、cmathをインクルードしている。

巡り巡って、iostreamをインクルードすると、cmathが読み込まれる。

もちろんその時点では_USE_MATH_DEFINESフラグは立っていない。

 

解決策は、次のとおり。

マクロの順序を変更しただけ。

ヘッダファイルに関するフラグは、include文より前に定義しよう。

 

雑記:前もって定義されている数学定数

#define _USE_MATH_DEFINES

フラグを立ててcmathをインクルードすると、次の数学定数を利用できる。

f:id:LouiS:20170506160658j:plain

ネイピア数含め対数周りの定数と、円周率に関する定数。

一番下の定数を、M_1_SQRT2と改名すべきと思うのは私だけだろうか?

 

雑記:ぼやき

iostreamに、cstdlibやcmathがインクルードされてるっていったい何なんだ。

いわゆる神モジュールになっている気が...

 

 

Qtでソケット通信を試してみた(UDP)

能書き

トランスポート層プロトコルは主に二種類ある。

  • 確実だけどめんどくさいTCP
  • 不確実だけど楽チンなUDP

今回はQtのQUdpSocketを用いたUDPのソケット通信を試してみた。

ネットワーク通信については詳述できないしないが、次のページが参考になる。

f:id:LouiS:20170324171137g:plain

 

また、QtのGUIの使い方は、以下のページで紹介したとおり。環境も同様。


ただし、モジュールの『Network』を有効にすること。

f:id:LouiS:20170324175701p:plain

 

サンプルコードの挙動

f:id:LouiS:20170324203640p:plain

Senderのエディットに文字列を入れてボタンを押すと、Recieverに反映される。

ただし、それぞれ別のアプリケーションとして起動する。それだけ。

 

このコードを実行するとき、このような警告が出ることがある。

両方のチェックボックスにチェックを入れて、アクセスを許可すること。

f:id:LouiS:20170324213759p:plain

 

サンプルコード―送信

送信用のウィジェットとして、次のようなものを用意する。

f:id:LouiS:20170324182843p:plain

clicked()シグナルと、ダイアログのsendDatagram()スロットを連結する。

 

まずヘッダファイル。

先のスロットと並んで、ソケットとポート番号を宣言している。

ポート番号は、ウェルノウン*1でなければ、適当に選んで大丈夫(だと思う)。 

ポート番号に関する解説は、このページが詳しい。

 

次に、ソースファイル。

23行目のwriteDatagram()第二引数には、通信先のIPアドレスを指定する。

  • QHostAddress::LocalHost
     自分自身と通信する、ループバックアドレス。実験段階で特に有用だろう。
  • QHostAddress::Broadcast
     同一ネットワーク上の全てのノードに送信するアドレス。ただし、ブロックするルータもある。
  • QHostAddress::QHostAddress( "xxx.xxx.xxx.xxx" )
     コンストラクタを用いて、IPv4アドレスを指定する方法。

 

18-21行目は、送信用のバイト列をうまく扱うための方便。

とりあえずは盲目に真似して、C++のストリームの恩恵に預かってよいだろう。

 

このように、送信側はただ『データを成形して』『送信する』だけで実装できる。

 

サンプルコード―受信側

受信側のウィジェットは単純で、ラベルが一つだけあるダイアログだ。

コードは次のとおり。

ヘッダファイルは送信側と酷似している。

ソースファイルに関しても、結局は『受信して』『データを解析して』いるだけ。

21行目から24行目は、このままでいろいろなニーズに使いまわせる。

 

受信側特有の処理は二つある。第一は、cppファイル9行目のbind()だ。

どのデータを受け取るか選ぶために、前もってポート番号を知らせる必要がある。

 

第二の特有の処理は、readyRead()シグナルと処理スロットを接続することだ。

サンプルコード10,11行目の処理にあたる。

readyRead()シグナルは、送信されたデータを読む準備が出来ると発呼される。 

 

まとめ

  • QUdpSocketクラスは、低信頼/高速の通信プロトコルを提供する。
  • 送信側/受信側が、共通のポート番号を知っておく必要がある。
  • 送受信にはQByteArrayクラスのバイト列を用いる。
    QDataStreamクラスを利用すると便利。
  • 受信側は、前もってbind処理を行っておくこと。
  • データが受信されると、readyRead()シグナルが発呼される。

案外単純である。

 

ストリームの取扱いに関しても、そのうち書く...かもしれない。

書かないかもしれない。 

 

ただし

ただし、このコードでは、短時間に連続して送られるデータには対応できない。

処理に手間取っているうちに送信されたデータは無視される。

全てのデータを扱う必要があるのなら、

hasPendingDatagrams()を用いたループ内に処理命令を書くこと。

リファレンスのサンプルコード片が参考になる。

 

これについてはそのうち書く。

*1:0~1023 予約されているポート

マルチスレッドQtアプリケーション(まとめ)

能書き

Qtでマルチスレッドを実現する方法にはいくつかある。

それらの方法や参考となるページをまとめる。

 

『マルチスレッドとは何か?』

これについては、検索すればいくらでも情報がヒットするので、特筆しない。

個人的には、『処理の流れが複数ある状態』と説明している。

 

継承を用いて実現する方法

以下のページに詳細を示した。

この方法は、おそらく最も素直な実装スタイルだと思うし、

私が参照したオライリーの入門書でもこれが紹介されていた。

 

しかし、いくつかの問題点を含むため、次の方法が現在では主流のようだ。

 

委譲を用いて実装する方法

以下のページに詳細を示した。

 

参考となるページ

QThread Class | Qt Core 5.8 | DetailsQObject Class | Qt Core 5.8 | moveToThread()

まずは公式リファレンス×2。

それぞれのページで、Qtのスレッドの扱いについて知見を深められる。

また、継承による方法、委譲による方法の両方のコードが紹介されている。

Qtでスレッドを使う前に知っておこう - Qiita

この中で唯一日本語のページ。

なぜ継承による実装が避けられるのか、その問題点を列挙している。

また、connect関数の第5引数に関しても詳説があり、非常に参考になる。

How To Really, Truly Use QThreads; The Full Explanation | Maya's Programming & Electronics Blog

委譲による方法を提言し、Qt公式リファレンスに強い影響を与えたエントリー。

従来の方法を批判する要点は次のとおり(稚拙な和訳/強引な意訳)。

  • 継承による従来の方法は、必要以上に複雑で不適当。
  • QThreadは、『スレッド』そのものではない。スレッド周辺を覆うラッパークラスだ。したがって、サブクラスがスレッドのように扱われるのは不適当。

具体的に実装する際の主な注意点は次のとおり(稚拙な和訳/強引な意訳)。

  • 別スレッドで動かすQObjectのコンストラクタでヒープ領域を確保しないこと。QObjectをインスタンス化したときは、まだ旧スレッド上にある。
  • deleteLater()スロットを適切に用いれば、クラッシュを回避できる。

マルチスレッドQtアプリケーション(2)

能書き

前回の記事の続きとして見てもよいだろうし、そうでなくてもよいだろう。

 

マルチスレッドをQtで再現する方法はいくつかあるが、

その中で、QThreadにタスクを委譲するものを紹介する。

 

簡単な例

まず、特に簡単なコードを示す。

異なるスレッド間で直接関数を呼び出すことは危険だが、ここでは無視する。

その他もいろいろいい加減なコードであるが、許してもらいたい。

 

実行結果は次のとおり。

Main: QThread(0x24230a65230)
Func: QThread(0x24230a68820)

マルチスレッドが実現されていることがわかる。

 

必要な手順

委譲を用いてマルチスレッドを実現するために必要な手順は以下のとおり。

  1. 別スレッドで実行したい処理を担うクラスを、QObjectを継承して作る。
  2. そのインスタンス(subObject)をヒープ領域に生成する。
     SubObject *subObject = new SubObject();
  3. QThreadのインスタンス(subThread)をヒープ領域に生成する。
     QThread *subThread = new QThread();
  4. subObjectの所有権をsubThreadに移す。
     subObject->moveToThread( subThread );
  5. subThreadの処理を開始する。
     subThread->start();

上記の処理は、source.cppの17-19行目に実装されている。

 

4番目の手順、5番目の手順を抜かしても、ビルドエラーは生じない。

予期通りの動作をしないときは、このようなミスをしている恐れがある。

 

異なるスレッド間で直接関数を呼び出してはいけない理由

例えば、先のコードを一部改造して、次のようなコードを書いたとする。

subThreadのstart()をコメントアウトし、シグナル/スロットを追加している。

 

実行結果は次のとおりである。

Main: QThread(0x1b9868d5300)
Func: QThread(0x1b9868d89b0)
emit complete

結果を見てわかるように、スロットが呼び出されていない!

 

これはなぜか。

実はスロットは、シグナルが発呼された直後に呼び出されるのではない。

スロットが所属するスレッドのキューに組み込まれるだけだ。

スレッドが開始されなければ、もちろんキューは処理されない。

それために、先の実行結果が出たのである。

 

直接関数を呼び出してしまっては、スレッドが開始していようがいまいが、

関係なしに即時実行してしまうこととなる。

マルチスレッドQtアプリケーション(1)

能書き

マルチスレッドをQtで再現する方法はいくつかあるが、

その中で、QThreadの継承を利用するものを紹介する。

 

コード:特にシンプルな例

まずはシンプルな例として、次のコードを書いてみた。

ヒープ領域を解放していなかったり、プログラムの終了条件がなかったり、

いろいろといい加減だが許してもらおう。

 

Q_DECL_OVERRIDEは、C++11以降ではoverrideに置換される。

このキーワードはもし無くてもエラーは生じない。

しかし、明記することで予期せぬ人的バグを回避できる。

 

QThreadのインスタンスをstart()すると、run()が内部的に呼び出される。

 

実行結果は次のとおりである。

Main: QThread(0x1881fe16160)
Sub: SubThread(0x1881fe17100)

実行結果は毎回異なるが、マルチスレッドが達成されていることは確認できる。

 

しかし、この方法には思わぬ落とし穴がある。

 

コード:うまくいかない例

直前の例に、一部を追加しただけのものだ。

マルチスレッドに親しんだ人から見れば、奇ッ怪なコードに見えることだろう。

しかし、直感的には実現できそうに写る。

コンストラクタ、メンバ関数、スロットとその呼び出しを追加した。  

 

実行結果は、次のとおりである。

Main: QThread(0x1b755747c70)
Constructor: QThread(0x1b755747c70)
Func: QThread(0x1b755747c70)
Sub: SubThread(0x1b755749ad0)
Slot: QThread(0x1b755747c70)

この実行結果の意味がわかるだろうか?

五つの出力のうち、下四つはSubThreadのメンバ関数によるものである。

しかし、スレッドのIDを見てみると、『Sub』以外はすべて同一である。

 

内的に呼び出される『run』関数以外、マルチスレッドの恩恵を受けられない。

 

原因と解決策

『原因』などと書いたが、これはQtの仕様通りの動作である。

 

『うまくいかない例』のようなインターフェースのまま、どう設計すればよいか?

継承ではなく、委譲を用いることでその要求を達成できる。

louis-needless.hatenablog.com

 

留意点

異なるスレッド間の関数呼び出しは本当は危険らしい。

面倒でもシグナル/スロットを用いると安全に実装できる。

既存のVisual StudioプロジェクトをQt用に変換する方法:オマージュ

前書き

この記事は、次のページを尋常じゃなく参考にしている。

参考というより、実行環境が違うだけだ。

 

同時に、先日の私の記事の解決編でもある。


環境

  • Windows10
  • Visual Studio 2015 Community
  • Qt 5.6.0
  • Add-in 2.0.0 for Qt5

アドインなどが正しくインストールされている前提。

 

VC++コード

例えば、次のようなコードを書いたとする。

本当は宣言と実装は分けるべきだが... ここでは許してもらおう。

このヘッダをどこかにインクルードすると、エラーが発生するはずだ。

(発生しない場合は、このページに辿り着かないと思う。)

 

解決策

ちょっと長い。

1. テキストエディタで『プロジェクト名.vcxproj』を編集。

赤線を引かれた要素を追加する。

f:id:LouiS:20170321175411j:plain

バージョンによって多少キーワードは異なると思う。

ウィザードで作成したQtプロジェクトの同要素を確認すると確実だ。

2. プロジェクトを64bit版にしておく。

プルダウンリストからx64を選んでおく。

f:id:LouiS:20170321183035p:plain

この設定をしていないと、ビルド時に次のようなエラーが出ることがある。

The following error occurred:
There's no Qt version assigned to this project for platform Win32. Please use the 'change Qt version' feature and choose a valid Qt version for this platform.

Qtのバージョンを変えるのもありっちゃあり。

3. Visual StudioでプロジェクトをQt用に変換。

メニューバーから、『Convert Project to Qt VS Tools Project』を選択。

警告が出るが、『はい』を選択すると、プロジェクトが変換される。

f:id:LouiS:20170321181331p:plain

左方のリストでソリューションを選択していると表示されない。注意。

4. 必要なモジュールを追加。

メニューバーから、『Qt Project Settings』を選択。

『Qt Modules』タブから、必要なモジュールにチェックを入れる。

f:id:LouiS:20170321182300p:plain

『Core』,『GUI』,『Widgets』があれば大体の簡単なアプリケーションは動く。

必要なモジュールを調べるには、リファレンスを参照のこと。

5. 完了!と思いきや

私の環境では、この状態でビルドするとエラーが多発する。

『追加のインクルードディレクトリ』『追加のライブラリディレクトリ』

この二つを、手動で書き直してやる必要があった。

6. それでもうまくいかないときは

MOCが適用されていない恐れがある。

ヘッダファイルを適当に編集したのちにリビルドすると上手くいくかもしれない。

それこそ、空白を入れて消すだけの編集でも構わない。

Visual Studio 2015でQt GUIプログラムを組んでみる(2)

前回の続き

louis-needless.hatenablog.com

このページの続き。

 

f:id:LouiS:20170306161515j:plain

このGUIは、QPushButtonQLineEditを使っている。

実際にはQHBoxLayoutも利用しているが、まあ無くても問題はない。

 

シグナルとスロット

せっかくボタンを付けたのだから、なにか応答がないと面白くない。

Qtでは、シグナル/スロットという独自の機構を用いてアクションを処理する。

 

アクションが検出されると、シグナルが送信され、スロットが呼び出される。

当面はスロットだけ設計ができれば問題ないだろう。

 

シグナルとスロットを実装してみる

ここでは、以下の簡単な応答を実装する。

『ボタンをクリックすると、ダイアログのタイトルを、エディタに入力された文字列に更新する』

 

シグナル/スロットは、QtDesigner上で設計することができる。

f:id:LouiS:20170314121539p:plain

ドックから上の項目を選択するか、F4キーを押せば、編集モードに移行できる。

 

次のようにして、ウィジェットどうしを接続する。

  1. 配置したPushButtonをクリック
  2. クリックした指を離さないまま
  3. 配置したダイアログ上でドロップ

そうすると、以下のようなウィンドウがポップアップするはずだ。

f:id:LouiS:20170314122210p:plain

この画面で、PushButtonとDialogを『接続』する―

実際に、CUIでコーディングする際は、『connect』というキーワードを用いる。

 

左側のリストがシグナルのリスト、右側はスロットのそれだ。

単純にクリック応答にしたいので、左側からは『clicked()』を選択する。

 

スロットはさきほど考えた、『ダイアログのタイトルを、エディタに入力された文字列に更新する』だけの要求を満たさなければならない。

しかし、そんなに都合のよいスロットは、デフォルトで存在しない。

作るのだ。

 

スロットを作る

次のようにして、先のシグナルとオリジナルのスロットを接続する。

  1. スロットリスト最下方の『編集』ボタンをクリック
  2. スロットの一覧が表示されるので、直下の『+』ボタンをクリック
  3. 『setTitleByInput()』と入力
  4. 『OK』をクリックし、ポップアップダイアログを閉じる
  5. スロットリストに追加された『setTitleByInput()』を選択
  6. 『OK』をクリックし、ダイアログを閉じる

以下のように、接続が青色になるはずだ。
(追記2017/03/21:接続が青色になるのはスロットが実装されているとき)

f:id:LouiS:20170314124344p:plain

 

スロットをコーディングする

残念ながら、ここで終わりではない。

ここまで、『clicked()』と『setTitleByInput()』を接続した。

しかし、肝心の処理内容はなにも書いていない。

 

まず、QtGuiSample.hppを、以下のように書き換える。

setTitleByInput()というメンバ関数をプロトタイプ宣言しただけだ。

しかし、スロットを明示するために、『private slots:』のラベルが必須となる。

 

次に、QtGuiSample.cppを、以下のように書き換える。

setTitleByInput()を実装する内容だ。

JavaGUI設計をしたことのある人なら、難なく理解できるだろう。

 

なお、『text()』は、オブジェクトlineEditのメンバ変数のgetterだ。

Qtは、『getXX()』という命名を慣習的にしない。

 

試してみる

以上で完成だ。プログラムを実行してみる。

f:id:LouiS:20170314132915p:plain

入力フォームに適当な文字列を入力して、ボタンをクリックする。

 

f:id:LouiS:20170314132914p:plain

要求通りの動作が確認できた。

Visual Studio 2015でQt GUIプログラムを組んでみる(1)

能書き

前にVS上でQtが動かないという記事を書いたが、結論から言うと動いた。

適当なこと言ってすみません。

 

環境

  • Windows10
  • Visual Studio 2015 Community
  • Qt Designer 5.6.0
  • Add-in 2.0.0 for Qt5

アドインなどが正しくインストールされている前提。

 

プロジェクトを作ってみる

ウィザードを活用してプロジェクトの骨組みを作る。

f:id:LouiS:20170306153513p:plain

『QtGUIApplication』を選択。

プロジェクト名とパスをちょいちょい決めて、次の画面へ。

 

f:id:LouiS:20170306154258p:plain

全ての項目が自動的に埋められる。

基底のクラス(Base Class)を、QDialogに変更しておく。

ヘッダファイルの拡張子がhからhppに変更されているのはただの好みだ。

 

f:id:LouiS:20170306154847p:plain

モジュールの選択を求められるが、とりあえずはデフォルトでよいだろう。

 

ケルトンコードがむにゃむにゃと生成される。

内容を人手で変更してよいのは、基本的に次の五つ。

  • Form Files
    • QtGuiSample.ui
  • Header Files
    • QtGuiSample.hpp
  • Resource Files
    • QtGuiSample.qrc
  • Source Files
    • main.cpp
    • QtGuiSample.cpp

Generated Filesフィルタに含まれるファイルは絶対にいじってはいけない。

また、ここではqrcファイルの編集はしないこととする。

 

GUIを作ってみる

ケルトンコードを実行すると、次のようなダイアログが表示される。

f:id:LouiS:20170306160656p:plain

ダイアログベースなので非常にシンプルだ。

 

このままではつまらないので、簡単なウィジェットを作ってみたいと思う。

Qt Designerがインストールされていれば、コードなしにGUIを設計できる。

  1. QtGUISample.uiを開く。Qt Designerが起動するはずだ。
  2. 左側のリストからパーツをドラッグ&ドロップして、下記のGUIを完成させる。
    いろいろ試してみてほしい。

f:id:LouiS:20170306161515j:plain

 

長くなったので、残りは別のページに貼る。

louis-needless.hatenablog.com

/* コードブロック */