R 3.1.0 にアップデートしたら Rstudio が起動しない問題の解決
Mac OS X Mavericks 環境で
Rstudio を起動すると以下の様なメッセージがでて起動できなくなった。
ERROR r error 4 (R code execution error) [errormsg=Error in identical(call1L, quote(doTryCatch)) : 7 arguments passed to .Internal(identical) which requires 5 , code=local(source("/Applications/RStudio.app/Contents/Resources/R/Tools.R", local=TRUE, echo=FALSE, verbose=FALSE, encoding='UTF-8'))]; OCCURRED AT: core::Error r::exec::::evaluateExpressions(SEXP, SEXP, SEXP *, sexp::Protect *) /Users/rstudio/rstudio/src/cpp/r/RExec.cpp:145
Rのサポートページに解決法があったのでメモ。
問題の原因は、Rの古いバージョンのフレームワークが残っていたことみたいです。
/Library/Frameworks/R.Framework/Versions/
の中にある古いバージョンのフォルダを削除したら正常に起動するようになりました。
QtでGUIアプリーション作成入門(3)
登録した連絡先の間をナビゲートする能力を加える。
しかし、その前にどんな種類のデータ構造が必要なのか決める必要がある。前のセクションでは QMap の鍵-値ペア、名前を鍵/住所を値、を用いた。我々の場合ではこれでいいが、各エントリーを表示しナビゲートするにはもう少し拡張する必要がある。
QMap を円環状に結合したリストを模したデータ構造にするため拡張する。下の図で示すようなイメージ。
※QtはSTLライクなイテレータとJavaライクなイテレータがある。QMap::iteratorはSTLライクだが(end()は最後の要素の一つ後の空要素である)、QMapIteratorはJavaライクなイテレータ。QMapのイテレータは、QMap::iteratorでも、直接、イテレータが指し示す要素のkeyとvalueにアクセスできる。
AddressBook クラスの定義
ナビゲーション関数を追加するために、AddressBookクラスに2つのスロット(next() と previous())を addressbook.h に加える。:
void next(); void previous();
また2つの QPushButton オブジェクトが必要なので nextButton と previousButton をプライベート変数に加える:
QPushButton *nextButton; QPushButton *previousButton;
AddressBook クラスの実装
addressbook.cppのAddressBookコンストラクタの中で、nextButton と previousButton をインスタンス化し、デフォルトでは無効にする。これはナビゲーションは複数の連絡先が登録された時だけに有効にするため。
nextButton = new QPushButton(tr("&Next")); nextButton->setEnabled(false); previousButton = new QPushButton(tr("&Previous")); previousButton->setEnabled(false);
その後、それらのpushボタンを対応するスロットに結合する。
connect(nextButton, SIGNAL(clicked()), this, SLOT(next()));
connect(previousButton, SIGNAL(clicked()), this, SLOT(previous()));
GUIのイメージは以下
基本的な慣例に従って nextButton を右 previousButton を左に配置する。この直感的なレイアウトのために QHBoxLayout を使う:
QHBoxLayout *buttonLayout2 = new QHBoxLayout;
buttonLayout2->addWidget(previousButton);
buttonLayout2->addWidget(nextButton);
この QHBoxLayout オブジェクトbuttonLayout2を、メインレイアウトの(2,1)要素に加える。
mainLayout->addLayout(buttonLayout2, 2, 1);
下の図はこのウィジェットのmainLayoutの座標を示している。
我々の addContact() 関数の中で、それらのボタンを無効にするので、連絡先を加えるときに間違えて押すこともない。
nextButton->setEnabled(false); previousButton->setEnabled(false);
また、submitContact()関数の中で、nextButton と previousButton, を有効にする、連絡先の数に応じて有効にする。これをするには以下のコードを使う。
int number = contacts.size(); nextButton->setEnabled(number > 1); previousButton->setEnabled(number > 1);
このコードは cancel() 関数でも使う。
QMap オブジェクトを環状連結リストのように使うことを意図している。なので、next()関数では連絡先のイテレータを得る必要がある、なので:
もし、イテレータが終末でないなら、一つインクリメントする
もし、イテレータが終末なら、最初の連絡先に移動させる。これで環状連結リストのように振る舞う。
void AddressBook::next() { QString name = nameLine->text(); QMap<QString, QString>::iterator i = contacts.find(name); if (i != contacts.end()) i++; if (i == contacts.end()) i = contacts.begin(); nameLine->setText(i.key()); addressText->setText(i.value()); }
正しいオブジェクトに移動できたら、その内容をnameLineとaddressTextに表示する。
同様に、previous()関数でもイレテータを得る必要がある。
もし、イレテータが最初なら、終末に移動する。
そしてイテレータを1つデクリメントする。
void AddressBook::previous() { QString name = nameLine->text(); QMap<QString, QString>::iterator i = contacts.find(name); if (i == contacts.begin()) i = contacts.end(); i--; nameLine->setText(i.key()); addressText->setText(i.value()); }
再び、現在のオブジェクトの内容を表示する。
Files:
tutorials/addressbook/part3/addressbook.cpp
tutorials/addressbook/part3/addressbook.h
tutorials/addressbook/part3/main.cpp
tutorials/addressbook/part3/part3.pro
QGISで傾斜度を計算するときの注意点
ラスタ解析のDEM(地形モデル)で傾斜度を計算する時に、デフォルトでは適切に傾斜を計算できない。傾斜を%で表すなら可能だが、度数では無理だった。
ラスタのxy軸(緯度経度)とz軸(メートル)の単位が異なる場合は、比率(垂直単位の水平単位に対する比率)を111120に設定する。
もう一つの方法は、xy座標の単位をメートルな空間参照系に変換すること。レイヤーを名前を付けて保存→「WGS84/UTM zone 54N、EPSG32654」などに変更
変更後なら、デフォルトのまま傾斜度を計算できる。しかし、前の方法と結果を比較すると、細かい部分で微妙に違いが見られた。前の方法のほうが傾斜度の値がスムーズになっているようにみえる。
しかし、111120の値の出処が気になるので、少し調べたところ、緯度1度が111120メートルとのことだった。
ソース:http://osgeo-org.1560.x6.nabble.com/Slope-not-calculating-correctly-td4738276.html
QtでGUIアプリーション作成入門(2)
作成したGUIを使って連絡先を追加できるようにする。
新しい連絡先を追加するためのボタンを加える。さらに、その連絡先をアプリ内で保存するコンテナを加える。
アドレスブック・クラスの定義
Qtではボタンをクリックするなどのユーザーの操作によりシグナルが出される、それを受け取り処理をする関数をスロットと呼ぶ。
アプリのクラス内にボタンなどのGUIクラスと、スロットになる関数を、メンバとして追加する。そして、そのGUIクラスのシグナルと、スロット関数、を結合する。スロットになるメンバ関数は public slot: セクションで宣言する必要がある。
まずは3つのボタンと、それぞれに対応する3つのスロット関数を追加する。
adressbook.h
//スロット public slots: void addContact(); void submitContact(); void cancel(); private: QLineEdit *nameLine; QTextEdit *addressText; //ボタン QPushButton *addButton; QPushButton *submitButton; QPushButton *cancelButton; //内部データ格納用 QMap<QString, QString> contacts; QString oldName; QString oldAddress; };
3つの QPushButton オブジェクト (addButton, submitButton, cancelButton) をメンバ変数として加える。
アドレスブックの連絡先を格納するコンテナが必要。QMap オブジェクト使う、連絡先は、鍵-値ペアとして保存される:連絡先の名前を鍵, アドレスを値とする。
つの QString オブジェクト (oldName and oldAddress) を宣言する。これらのオブジェクトは最後に表示した入力フォールドの内容を保持する。
アドレスブック・クラスの実装
アドレスブック・クラスのコンストラクタ内で、addButton, submitButton, and cancelButton をインスタンス化して、nameLine と addressText を読み込み専用にセットする。
adressbook.h
class AddressBook : public QWidget { ... addButton = new QPushButton(tr("&Add")); addButton->show(); submitButton = new QPushButton(tr("&Submit")); submitButton->hide(); cancelButton = new QPushButton(tr("&Cancel")); cancelButton->hide(); ... nameLine->setReadOnly(true); addressText->setReadOnly(true); ... }
addButton は show() を呼び出すことで表示されるが、 submitButton と cancelButton は hide() を呼び出すことで隠される。この2つのボタンはユーザーがAddボタンをクリックした時のみ表示されるようにする、これは下で述べるaddContact() 関数内で操作する。
tr()はアプリを複数の言語に対応させるために必要、翻訳するべき文字列を指定するのに使う。ユーザーから見える文字列には常にtr()を付けておくとよい。
次に、各ボタンが押された時の動作を記述する関数(スロット関数)を用意する。スロットして呼び出されるメンバ関数はaddressbookクラス宣言の中で private slots: のスコープ内で宣言する必要がある。
addressbook.h
private slots: void addContact(); void submitContact(); void cancel();
addressbook.cpp クラス定義に3つのスロット関数の定義を記述
void AddressBook::addContact(){} void AddressBook::submitContact(){} void AddressBook::cancel(){}
AddressBook::AddressBook()
次に、コンストラクタの中で、各プッシュボタン・クラスの clicked() シグナルと、スロットとして呼び出される関数を結びつける。
AddressBook::AddressBook(QWidget *parent) { ... //マクロを使った記法 connect(addButton, SIGNAL(clicked()), this, SLOT(addContact())); connect(submitButton, SIGNAL(clicked()), this, SLOT(submitContact())); connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancel())); //関数へのポインタを使った記法 connect(addButton, &QPushButton::clicked, this, &AddressBook::addContact); connect(submitButton, &QPushButton::clicked, this, &AddressBook::submitContact); connect(cancelButton, &QPushButton::clicked, this, &AddressBook::cancel); ... }
次に、プッシュボタンをAddressBookウィジェットの上にレイアウトする。まずはQVBoxLayout を用いてボタンを縦に整列する。
...
QVBoxLayout *buttonLayout1 = new QVBoxLayout;
buttonLayout1->addWidget(addButton, Qt::AlignTop);
buttonLayout1->addWidget(submitButton);
buttonLayout1->addWidget(cancelButton);
buttonLayout1->addStretch();
...
addStretch() は複数のプッシュボタンが、空間内に同じ間隔で配置するのではなく、ボタン同士の間隔は小さくウィジェットの上端に近く配置する。下の図を参照。
addLayout().を使って buttonLayout1 をメインレイアウトの(1,2)要素として追加する。これで buttonLayout1をmainLayoutの子レイアウトとして入れ子状に配置することができる。
QGridLayout *mainLayout = new QGridLayout; mainLayout->addWidget(nameLabel, 0, 0); mainLayout->addWidget(nameLine, 0, 1); mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop); mainLayout->addWidget(addressText, 1, 1); mainLayout->addLayout(buttonLayout1, 1, 2);
addContact()
Addボタンを押したら、現在入力フィールドに表示されている連絡先を oldName と oldAddressに保持しておいてから、入力フィールドをクリアした後、読込専用をオフにして入力可能な状態にする。さらに、フォーカスが nameLine にセットされ submitButton と cancelButtonが表示される。
void AddressBook::addContact() { oldName = nameLine->text(); oldAddress = addressText->toPlainText(); nameLine->clear(); addressText->clear(); nameLine->setReadOnly(false); nameLine->setFocus(Qt::OtherFocusReason); addressText->setReadOnly(false); addButton->setEnabled(false); submitButton->show(); cancelButton->show(); }
submitContact()
submitContact() 関数は3つのパートに分けられる。
1)連絡先の詳細を nameLine と addressText から抽出して、 QString オブジェクトに格納する。フィールドが空なのにSubmitボタンを押さないように確かめる、もし、押したら QMessageBox を表示してnameとaddressを入力するようにメッセージを表示する。
※ QMessageBox::information() の第2引数はメッセージボックスのタイトルだが、Macでは表示されない。
void AddressBook::submitContact() { QString name = nameLine->text(); QString address = addressText->toPlainText(); if (name.isEmpty() || address.isEmpty()) { QMessageBox::information(this, tr("Empty Field"), tr("Please enter a name and address.")); return; }
連絡先が既に登録されていないかチェックする。されていないなら、連絡先を追加し、それを知らせるメッセージを表示する。
if (!contacts.contains(name)) { contacts.insert(name, address); QMessageBox::information(this, tr("Add Successful"), tr("\"%1\" has been added to your address book.").arg(name)); } else { QMessageBox::information(this, tr("Add Unsuccessful"), tr("Sorry, \"%1\" is already in your address book.").arg(name)); return; }
もし、連絡先が既に存在したら、重複して追加しないようにメッセージを表示する。連絡先オブジェクトは鍵-値ペアに基いているので、鍵が一意であることを確保する必要がある。
最後にボタンの表示を通常の状態に復帰させる。
if (contacts.isEmpty()) { nameLine->clear(); addressText->clear(); } nameLine->setReadOnly(true); addressText->setReadOnly(true); addButton->setEnabled(true); submitButton->hide(); cancelButton->hide(); }
cancel()
cancel() 関数は最後に表示した連絡先詳細を復帰して addButtom を使用可能にし、ssubmitButtonとcancelButtonを隠す。
void AddressBook::cancel() { nameLine->setText(oldName); nameLine->setReadOnly(true); addressText->setText(oldAddress); addressText->setReadOnly(true); addButton->setEnabled(true); submitButton->hide(); cancelButton->hide(); }
QtでGUIアプリーション作成入門(1)
Qtフレームワークを使って下のようなアプリケーションを作ってみる。色んな所でQt入門記事があるけど、公式Qtドキュメントのチュートリアルが結局わかりやすかった。
通常はユーザーインターフェースの作成にはQtデザイナー使用するが、Qtの動作を理解するために、あえてそれを使わないで、ソースコードからUIを作成する方法を紹介する。
対象はC++は既にわかっていてCUIソフトは作ったことあるけど、GUIはない人。
現在のQtのバージョンはQt5.1、もうすぐQt5.2の正式版がリリースされる、5.2ではiOSもサポートされるので、iPhoneアプリも作成できるようになります。
プロジェクトの作成
プロジェクトの新規作成>Qt Guiアプリケーション
- 名前:AddressBook
- クラス名:AddressBook
- 基底クラス:QWidgets
以下のファイルが生成される
- AddressBook.pro:プロジェクトの設定ファイル
- main.cpp:メイン関数がある
- addressbook.h:AddressBookクラスのヘッダ
- addressbook.cpp:AddressBookクラスの実装
コンパイル&実行はQtクリエイターの実行ボタンでもいいけど、コマンドラインからは.proがあるディレクトリにcdして。
qmake&&make
qmakeがMakefileを作成して、それをmakeする。するとAddressBook.exeなり.appができる。
基本的UIの作成
ソースコードで作成したUIとQtデザイナーで作成したUIは両立するが表示が重なるので配置には注意が必要。
addressbook.h
#include "addressbook.h" #include "ui_AddressBook.h"//Qtデザイナーで作成したui用 #include <QtWidgets> class QLineEdit; class QTextEdit; class AddressBook : public QWidget { Q_OBJECT public: AddressBook(QWidget *parent = 0); private: QLineEdit *nameLine;//名前を入力するUI要素 QTextEdit *addressText;//住所を入力するUI要素 };
AddressBookクラスを QWidget クラスのサブクラスとして定義するので、
このクラスは QLineEdit andQTextEdit のポインタをメンバ変数として持つ。それぞれ名前と住所を格納する。メンバ変数がポインタなのは、インスタンス化は実行時にするため。これらのクラスのためのヘッダ
他にもQLabelは文字列をウィンドウに表示するのに使うが、これのオブジェクトの宣言は含まない、これを参照する必要はないため。
addressbookクラスのコンストラクタは QWidget 型の引数 parent を受け取る。これはAddressBookウィジェットが他のウィジェットから呼び出された時に、呼び出し元の親ウィジェットを指定するために使うが、ここではAddressBookはユーザーが呼び出すトップレベルのウィジェットなので=0がデフォルトになっている。
addressbook.cpp
AddressBook::AddressBook(QWidget *parent) : QWidget(parent) { QLabel *nameLabel = new QLabel(tr("Name:")); nameLine = new QLineEdit; QLabel *addressLabel = new QLabel(tr("Address:")); addressText = new QTextEdit;
Qtでのトップレベル・ウィジェットのコンストラクタの主な役割はUI要素をセットアップすること。このコンストラクタでは、QLabel オブジェクト nameLabel と addressLabel がインスタンス化される、同様に、nameLine と addressText もインスタンス化される。
tr() 関数は翻訳された文字列を返す(なければそのままの文字列)。この関数は引数として与えられた QString 文字列を他の言語に翻訳するべきものとして印を付ける。翻訳すべき文字列が現れるときには常に使うべき。
レイアウト
Qtでプログラミンする際にはレイアウトがどのように働くのか理解しておくと便利。Qtは、各ウィジェットを配置するために、3つの主要なレイアウトクラスを提供する: QHBoxLayout, QVBoxLayout and QGridLayout 。
ここでは QGridLayout を使い、ラベルと入力フィールドを構造的に配置する。QGridLayout は空間を格子状に分け、ウィジェットを配置する、行と列の数を指定する。
上のダイヤグラムはセルのレイアウトとウィジェットの位置を示している、次のコードでこのアレンジメントを指定する。
QGridLayout *mainLayout = new QGridLayout; mainLayout->addWidget(nameLabel, 0, 0); mainLayout->addWidget(nameLine, 0, 1); mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop); mainLayout->addWidget(addressText, 1, 1);
addressLabel は Qt::AlignTop を付加的な引数として使っている。これはセル(1,0)が垂直中心に位置しないようにするため。
レイアウトオブジェクトをこのウィジェット上にインスタンス化するために、ウィジェットの setLayout() 関数を呼び出す必要がある:
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
最後に、ウィンドウ名を "Simple Address Book" とする。
アプリケーションの実行
main.cppにメイン関数が記述されている。この関数内で QApplication オブジェクト, app をインスタンス化する。
QApplication は様々なアプリケーションワイドな機能を提供する、例えば、デフォルトフォントやカーソル、イベントループ。なのでQtのGUIアプリには常に1つの QApplication オブジェクトが存在する。
int main(int argc, char *argv[]) { QApplication app(argc, argv); AddressBook addressBook; addressBook.show(); return app.exec(); }
メイン関数内で addressbookウィジェットをインスタンス化し、表示するために show() 関数を呼び出している。しかし、ウィジェットはアプリケーションのイベントループが始まるまでは表示されない。アプリケーション・クラスの exec() 関数を呼び出すことでイベントループを開始している。この関数の返り値がmain関数の返り値として利用されている。
アドレスブック・ウィジェットをメイン関数のメモリ領域でインスタンス化することで、メイン関数のスコープを外れるとアドレスブックやその子ウィジェットのメモリは開放され、メモリーリークを防ぐ。
MacのUSキーボードでOptionキーによる特殊文字入力の無効化
MacではOptionキーを押しながら他のキーを打つと特殊文字が入力される。そのためOptionキーを使ったキーバインドが使えなかった。それを可能にする方法。
このサイトからMacのキーレイアウトファイルをダウンロードする。
以下にチェックが入っているか確認
- Mac OS X .keylayout (XML) file* (download)
- Yes, but leave the "option" keystrokes blank.
- U.S. (QWERTY)
Create Resource ボタンでダウンロード
ダウンロードしたファイル (My Layout.keylayout) を ~/Library/Keyboard Layouts に移す。
システム環境設定>キーボード>入力ソース から、その他の入力ソースのMy Layoutを追加
入力ソースとしてMy Layoutを選択しなくても追加するだけで、普段入力ソースとして使っているGoogle日本語入力でもOptionキーによる特殊文字入力が無効になる。
Optionキー自体が無効になるわけではないので、Optionキーを使ったキーバインドは使える。