電波女と青春男 6
なんか急にみんな積極的になっていた。
前川さんがなにげに積極的だけどこう一歩引く感じ。もうちょっと押せばいいのに。
リューシさんがちょっと頭おかしいレベルで電波ってた。いまやエリオより電波女ですよこの子。
そしてエリオは相変わらずほんのちょっとずつ変わってきている。
中盤は正直ダレてたというか、なんかみんな思わせぶりな発言ばっかりだしなんかよくわかんない人出てくるし、名前出てこないから誰?みたいな気分だったんだけど。
『どこで伏線張ってたテメー』
どこというか、もう全部と言ってもいいぐらいだったような。おっさんはなんとなくそんな気がしていたけど、ほかは全然思いもよらなかったなあ。
それぞれの特別な今日という日を、そしてきっと続くはずのこれからの良い日を。
エリオがどうなるのか楽しみにしていよう。
とある飛空士への追憶 3
正直なところ2巻になっても空戦始まらなくて、3巻からついに空戦との報を聞きつつも諦めかけていたところをやっと借りて読んだ。
中盤まで読み進めてやっとかと思ったけど、ミツオペア触接機の雷撃援護とか、単縦陣での逃走シーンは手に汗握るものだった。
海猫との遭遇、レヴァームの国名とファナ姓とかいろいろ前作との地図だけでない繋がりを感じさせていたし、
カルの才能の発露、それからアリエル、クレアのこと。とかいろいろあと2巻で終わるのかな。
とりあえずやっぱり話としては王道中の王道を突き進んでいるらしく、でも実際自分が空戦モノの王道な物語を読んだことがあるのかと聞かれればそんなものはないわけで。
だからこそどんな幕引きになるのかをすごく楽しみにしているんだと思う。
eclipseの動的Webモジュールのバージョンを3.xから2.xに下げる方法
ちょっとつまづいたのでメモ。
java1.6設定で作った動的Webプロジェクトを、1.5を使うように変更しようとしたら、プロジェクト・ファセット設定画面で変更できなかった。
「動的Webプロジェクトをアンインストールできません」とかなんとか。
こういうときはプロジェクトの設定ファイルを直接弄ってしまえばいいっぽい。
eclipseを一旦終了して、
プロジェクトルート\.settings\org.eclipse.wst.common.project.facet.core.xml を編集する。
JREのバージョン設定
<installed facet="jst.java" version="5.0"/>
JavaSE6なら6.0に。
動的Webプロジェクトのバージョン設定
<installed facet="jst.web" version="2.5"/>
保存したらeclipseを起動して、プロジェクトのクリーン(と再ビルド)を行う。
MySQLのLIKE句の検索対象に文字列型と整数型を連結した場合の注意
今日知ったこと。
CREATE TABLE emp ( id INT AUTO_INCREMENT PRIMARY KEY , name VARCHAR(40) NOT NULL );
とかいうテーブルの時に、下のSELECT文のLIKE句はケース依存になる。
SELECT id, name, CONCAT(emp, id) FROM emp WHERE CONCAT(emp, id) LIKE '%a%'
A5M2などでWHERE句を外したSELECT文を実行してみると、CONCAT(emp, id)のカラムがバイナリで表示された。整数型と文字列型を結合したらこうなるのか?ってことでリファレンスよく読んだらちゃんと書いてあった。
http://dev.mysql.com/doc/refman/5.1/ja/string-functions.html
(一部抜粋)
CONCAT(str1,str2,...)
引数を連結した結果であるストリングを戻します。ひとつ以上の引数を持つ場合があります。すべての引数が非バイナリ ストリングである場合、結果は非バイナリ ストリングになります。引数がひとつでもバイナリ ストリングを含む場合は、結果はバイナリ ストリングになります。数値の引数はそれに等しいバイナリ ストリング形態に変換されます。それを避けたい場合は、次の例のように、明示的なタイプ キャストを使用することができます :
SELECT CONCAT(CAST(int_col AS CHAR), char_col);
キャストの他にも、
SELECT id, name, CONCAT(emp, id) FROM emp WHERE UPPER(CONCAT(emp, id)) LIKE UPPER('%a%')
とかでも回避できる。あんまりきれいじゃないですね。ちなみに、
SELECT id, name, CONCAT(emp, id) FROM emp WHERE CONCAT(emp, 1) '%a%'
これはバイナリ型にならずにケース非依存で検索できた。なぜ?
手動で追加した値をSimpleCursorAdapterで使う
デバッグとかのときとか、DB使いたくないとき用に。
ArrayAdapterを継承して新しいクラス作ってgetViewオーバーライドして値追加して…ってやるのはめんどくさい。
そこで、SimpleCursorAdapterの引数に使う、DBのクエリ結果を格納するCursorを擬似的に作成する。
二次元表のCursorとして使えるクラスMatrixCursorを使う。
もともとのコードは1つ前の記事。
public class MyListActivity extends ListActivity implements SimpleCursorAdapter.ViewBinder { /** 仮想的に作成するDBのカラム名 */ private static final String FROM = { "_id", "checked", "name" }; private static final int ID = 0; private static final int CHECK = 1; private static final int NAME = 2; /** AdapterでバインドするViewのID */ private static final int TO = { R.id.text_number, R.id.check, R.id.text_name }; /** ListViewにDBの値をバインドするクラス */ private SimpleCursorAdapter adapter; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // DBを仮想的に作成して値を追加していく。FROM配列の長さ=addRowする配列の長さ。 MatrixCursor c = new MatrixCursor(FROM); c.addRow(new String { "1", "0", "Cupcake" }); c.addRow(new String { "2", "1", "Donut" }); c.addRow(new String { "3", "1", "Eclair" }); c.addRow(new String { "4", "1", "Froyo" }); c.addRow(new String { "5", "0", "Gingerbread" }); c.addRow(new String { "6", "0", "Honeycomb" }); adapter = new SimpleCursorAdapter(getApplicationContext(), R.layout.list_row, c, FROM, TO); adapter.setViewBinder(this); setListAdapter(adapter); } public boolean setViewValue(View view, Cursor cursor, int columnIndex) { switch (columnIndex) { case CHECK: CheckBox cb = (CheckBox) view; cb.setChecked(cursor.getInt(columnIndex) == 1); return true; case ID: TextView number = (TextView) view; number.setText("No." + cursor.getString(columnIndex)); return true; case NAME: break; default: break; } return false; } }
SimpleCursorAdapterのAdapt先にsetTextなどをする値をいじる
前回はSimpleCursorAdapterを継承して新しいクラスを作ってたけど、listenerいらないならそこまでしなくても大丈夫。
main.xml
<?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" />
list_row.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content"> <CheckBox android:id="@+id/check" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingRight="5dp" /> <TextView android:id="@+id/text_number" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/check" /> <TextView android:id="@+id/text_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/text_number" android:layout_alignLeft="@id/text_number" android:textSize="23sp" /> </RelativeLayout>
public class MyListActivity extends ListActivity implements SimpleCursorAdapter.ViewBinder { /** * AdapterでバインドされるデータのDB内カラム名 * DBに_idカラムがないとIllegalStateExceptionが発生する。) */ private static final String FROM = { "_id", "checked", "name" }; // 0番目は_id private static final int ID = 0; private static final int CHECK = 1; private static final int NAME = 2; private static final String DB_FILENAME = "database.db"; private static final String DB_TABLENAME = "database"; private static final int DB_VERSION = 2; /** AdapterでバインドするViewのID */ private static final int TO = { R.id.text_number, R.id.check, R.id.text_name }; /** ListViewにDBの値をバインドするクラス */ private SimpleCursorAdapter adapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); MyDBOpenHelper helper = new MyDBOpenHelper(getApplicationContext(), DB_FILENAME, null, DB_VERSION); SQLiteDatabase db = helper.getReadableDatabase(); Cursor c = db.query(DB_TABLENAME, null, null, null, null, null, null); adapter = new SimpleCursorAdapter(getApplicationContext(), R.layout.list_row, c, FROM, TO); adapter.setViewBinder(this); setListAdapter(adapter); } public boolean setViewValue(View view, Cursor cursor, int columnIndex) { switch (columnIndex) { case CHECK: CheckBox cb = (CheckBox) view; cb.setChecked(cursor.getInt(columnIndex) == 1); return true; case ID: TextView number = (TextView) view; number.setText("No." + cursor.getString(columnIndex)); return true; default: break; } return false; } }
DBに入れたデータ
_id | checked | name |
---|---|---|
1 | 0 | Cupcake |
2 | 1 | Donut |
3 | 1 | Eclair |
4 | 1 | Froyo |
5 | 0 | Gingerbread |
6 | 0 | Honeycomb |
表示結果
内部クラスでも、無名クラスでも大丈夫。
とにかくSimpleCursorAdapter.ViewBinderのsetViewValueを実装してSimpleCursorAdapterにsetViewBinderする。
SimpleCursorAdapterで表示させているListViewのWidgetにListenerをセットする
- SimpleCursorAdapterを継承したクラスを作成する
- newViewメソッドをオーバーライドする
- 引数のView変数(たぶんリスト行のレイアウトが入ってる)からwidgetを生成する
- widgetにListenerをセットする
public class MyCursorAdapter extends SimpleCursorAdapter { private CheckBox checkBox; public MyCursorAdapter(Context context, int layout, Cursor c, String from, int to) { super(context, layout, c, from, to); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { View view = super.newView(context, cursor, parent); checkBox = (CheckBox) view.findViewById(R.id.list_row_button); checkBox.setOnClickListener(new onCheckBoxClickListener()); return view; } public class onCheckBoxClickListener implements OnClickListener { public void onClick(View v) { Log.e("MyCursorAdapter", String.valueOf(checkBox.isChecked())); } } public class MyViewBinder implements SimpleCursorAdapter.ViewBinder { public boolean setViewValue(View view, Cursor cursor, int columnIndex) { if (columnIndex == cursor.getColumnIndex("check")) { boolean check = (cursor.getInt(columnIndex) == 1); checkBox.setChecked(check); return true; } return false; } } }
ViewBinderには、DBから取得した値を単純にTextViewにそのまま書き込むだけなら不要。
DBから取った値を加工してTextViewにBindしたり、上のコードみたいにCheckBoxなどBindする場合は、このメソッドを実装して、どのcolumnのときにどのViewにBindするかを書く。
あとはListActivityでsetAdapterすればいい。