SQLの窓

2015年10月26日


Android の Data Binding( "クラス > 画面" の片方向 )における特殊コントロールの処理をデータクラス内に実装する

画面定義

Android の 公式の Data Binding は、データクラスから 画面への片方向です。また、対応しているのは setText メソッドを持つコントロールのようなので、ここで利用している NumberPickerSpinnerDatePicker では、個別にデータクラスのデータをセットする処理を実装する必要があるので、データクラス内に全て収めました。

このデータクラスは、Google Gson を使用して JSON から一括でデータをセットする事を想定しています。

注 : Data Binding と Google Gson を利用する事を目的としているため、画面用のデータは全て String で定義し、Getter や Setter を定義していません。必要ならば、Getter や Setter で拡張し、その場合でも Data Binding と Google Gson は正しく動作します

Syain クラス
import android.databinding.BaseObservable;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.DatePicker;
import android.widget.NumberPicker;
import android.widget.Spinner;

import java.util.Arrays;

public class Syain extends BaseObservable {

	// シリアライズ・デシリアライズをしない( static )
	static public MainActivity context = null;
	// NumberPicker 用
	static public NumberPicker np = null;
	static public String[] nums = {"男性","女性","不明"};
	static public int[] values = {-10,20,100};
	// Spinner 用
	static public Spinner sp = null;
	// DatePicker 用
	static public DatePicker dp = null;

	public String scode;
	public String kj;
	public String furi;
	public String syozoku;
	public String seibetu;
	public String kyuyo;
	public String teate;
	public String kanri;
	public String birth;
	public String sname;

	public Syain() {
		this.scode = "";
		this.kj = "初期状態";
		this.furi = "";
		this.syozoku = "";
		this.seibetu = "";
		this.kyuyo = "";
		this.teate = "";
		this.kanri = "";
		this.birth = "";
		this.sname = "";
	}

	// ******************************************
	// NumberPicker 用
	// ******************************************
	public void setupSeibetuControl() {
		np.setMinValue(0);
		np.setMaxValue(2);
		np.setDisplayedValues(nums);
		np.setValue(1);

	}
	public void setSeibetuControl(String seibetu) {
		if ( seibetu != null ) {
			this.seibetu = seibetu;
		}
		np.setValue(Integer.parseInt(this.seibetu));
	}
	public void getSeibetuControl() {
		this.seibetu = Integer.toString(np.getValue());
	}

	// ******************************************
	// Spinner 用
	// ******************************************
	public void setupSyozokuControl(String[] list_data) {
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(
				context,
				android.R.layout.simple_spinner_item);
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		adapter.addAll(list_data);
		sp.setAdapter(adapter);
	}
	public void setSyozokuControl(String syozoku,String[] list_value) {
		if ( syozoku != null ) {
			this.syozoku = syozoku;
		}
		int idx = Arrays.binarySearch(list_value,this.syozoku);
		sp.setSelection(idx);
	}
	public void getSyozokuControl(String[] list_value) {
		int idx = sp.getSelectedItemPosition();
		this.syozoku = list_value[idx];
	}

	// ******************************************
	// DatePicker 用
	// ******************************************
	public void setupBirthControl(Boolean spinners, Boolean calendar) {
		dp.setSpinnersShown(spinners);
		dp.setCalendarViewShown(calendar);
	}
	public void setBirthControl(String birth) {
		if ( birth != null ) {
			this.birth = birth;
		}
		if ( this.birth != null ) {
			String dt[] = this.birth.split("-");
			if ( dt.length == 3 ) {
				dp.updateDate(Integer.parseInt(dt[0]), Integer.parseInt(dt[1])-1, Integer.parseInt(dt[2]));
			}
		}
	}
	public void getBirthControl() {
		this.birth = String.format("%d/%d/%d",dp.getYear(),dp.getMonth()+1,dp.getDayOfMonth());
	}


}

※ 再利用の為、先頭のパッケージ記述は削除しています

各コントロール用の Getter の引数について

Google Gson がデータを全てセットしてくれるので、その直後の処理としては、引数を必要としません。ですから、Google Gson のデシリアライズで受け取った値を使用する場合は、引数に null を使用します。
// 現在の内容でコントロールセット( fromJson 用なので、null 指定 )
syain.setSeibetuControl(null);
syain.setSyozokuControl(null, getResources().getStringArray(R.array.list_value));
syain.setBirthControl(null);


BaseObservable の継承について

ここでは、必要無かったのでこの BaseObservable の機能を使用していませんが、データクラス内のデータを個別に変更してリアルタイムで画面に反映させる場合に BaseObservable の通知機能を使います。しかし、自動生成されるバインド用のクラスの invalidateAll() を使ったほうが簡単であると思います。( Google Gson は、Setter を使用しないので利用できませんでした )

static フィールドについて

Google Gson のシリアライズとデシリアライズの対象外にする為に使用しています。当然、クラス共通となる為、画面定義と一対一と言う認識での実装です。



posted by lightbox at 2015-10-26 13:49 | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

Android の Data Binding における include を使用した画面分割

Android デベロッパーの Data Binding Guide に書かれていますが、bind:user="@{user}" のように variable で指定した変数を引き継ぐだけです。



この記述は、引き継がれた( include された) 画面にも記述して、さらに第三画面を include できます。



注意 : デザイン画面でエラーのようなものが出る場合は、( とりあえず Clean Project を実行して ) 左上の x をクリックして閉じて下さい。( カスタム要素のせいです )


画面全体のソースコード

引き継がれた( include された) 画面
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:bind="http://schemas.android.com/apk/res-auto"
        tools:context=".MainActivity">

    <data>
        <variable
            name="user"
            type="sample.lightbox.androidbind1017.Syain"/>
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.syozoku}"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:id="@+id/textView3"
            android:layout_margin="4dp"/>

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.sname}"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:id="@+id/textView4"
            android:layout_margin="4dp"/>

        <NumberPicker
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/numberPicker"/>

        <Spinner
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/spinner"
            android:spinnerMode="dropdown"/>

        <DatePicker
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/datePicker"
            android:datePickerMode="spinner"/>

        <include
            layout="@layout/ex_contents2"
            android:id="@+id/ex2"
            bind:user="@{user}"/>

    </LinearLayout>
</layout>


第三画面
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:bind="http://schemas.android.com/apk/res-auto"
        tools:context=".MainActivity">

    <data>
        <variable
            name="user"
            type="sample.lightbox.androidbind1017.Syain"/>
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">


        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{user.kj}"
            android:id="@+id/editText2"
            android:background="@drawable/border"
            android:padding="5dp"/>

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TOP"
            android:id="@+id/button4"/>

    </LinearLayout>
</layout>

Data Binding 画面の注意事項

画面定義内は常に英数字・記号を使用する必要があります

現時点では、画面内の文字列に日本語を使用できません。実際使う場合は、初期値を直接書き込む場合とバインド用の変数に使う場合ですが、前者はリソースとして定義して日本語を使わずに参照擦れば動作します。しかし、後者では使え無い場合があります(使える場合もある)。


posted by lightbox at 2015-10-26 10:10 | Android Studio 2 | このブログの読者になる | 更新情報をチェックする

2015年10月03日


PHP で Windows標準のオブジェクト(CDO.Message)とGMail を使ってメール送信

ひさしぶりにテスト( Windows7 ) しようとすると、Gmail からエラーが返って来ましたが、Gmail 側で安全性の低いアプリの許可を『有効』にする必要がありました。

また、php 側では、php_com_dotnet.dll を php.ini で有効にする必要があります。

※ CDO.Message に関する詳細は、ソース内に URL を記述しています

関連する記事

Windows標準のオブジェクト(CDO.Message)とGMail を使ってメール送信

本来は、VBScript で実行するものですが、PHP が分かる人なら、こちらのほうがいろいろ応用がきいて使い勝手もいいと思います。

▼ バッチファイル
------------------------------------------------------
@echo off
setlocal
set PATH=c:\php;%PATH%

php mail.php "題名" "本文\nで す\nよ"

endlocal
------------------------------------------------------

mail.php
<?php
// ***********************************************
// バッチファイル内容
// setlocal は、環境変数を一時的に設定する為に使用します
// php.exe は、c:\php にあります
// ***********************************************
/*
@echo off
setlocal
set PATH=c:\php;%PATH%

php mail.php "題名" "本文\nで す\nよ"

endlocal
*/

// ***********************************************
// php.ini で必要な拡張
// ***********************************************
/*
extension=php_com_dotnet.dll
*/

// ***********************************************
// Gmail 側の設定
// ***********************************************
/*
安全性の低いアプリの許可を『有効』にする

https://myaccount.google.com/security?pli=1#connectedapps
*/

// ***********************************************
// PHP の処理開始
// ***********************************************
$strFrom = "私です <ユーザ名@gmail.com>";
$strTo = "あなたです <宛先メールアドレス>";

$strServer = "smtp.gmail.com";
$nPort = 465;
$strUser = "ユーザ名@gmail.com";
$strPass = "パスワード!";

// ***********************************************
// CDO.Message( CDO for Windows 2000 )
// ***********************************************
$cdo = new COM( "CDO.Message" );

$cdo->From = $strFrom;
$cdo->To = $strTo;

// ***********************************************
// 題名
// ***********************************************
$cdo->Subject = $argv[1];

// ***********************************************
// バッチファイルで引渡した本文文字列内の \n を実際の改行に変換
// ***********************************************
$data = str_replace( "\\n", "\n", $argv[2] );
$cdo->Textbody = $data;

// ***********************************************
// 送信情報オプション
// ***********************************************
$cdo->Cc = "メールアドレス1,メールアドレス2";
//$cdo->Bcc = "";
$cdo->Htmlbody = "<img src=\"http://winofsql.jp/image/winofsql.png\">";

// ***********************************************
// ファイル添付
// ***********************************************
$cdo->AddAttachment( "C:\\Users\\lightbox\\Desktop\\画像\\_img.jpg" );

// cdoSendUsingPort : 2 : Send the message using the network (SMTP over the network)
// https://msdn.microsoft.com/en-us/library/ms527265.aspx.
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/sendusing"] = 2;

// The name (DNS) or IP address of the machine hosting the SMTP service through which messages are to be sent.
// https://msdn.microsoft.com/en-us/library/ms527294.aspx
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/smtpserver"] = $strServer;

// The port on which the SMTP service specified by the smtpserver field is listening for connections.
// https://msdn.microsoft.com/en-us/library/ms526227.aspx
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/smtpserverport"] = $nPort;

// Indicates that SSL should be used when sending messages using the SMTP protocol over the network.
// https://msdn.microsoft.com/en-us/library/ms526975.aspx
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/smtpusessl"] = true;

// Specifies the authentication mechanism to use when authentication is required to send messages
// to an SMTP service using a TCP/IP network socket.
// https://msdn.microsoft.com/en-us/library/ms526600.aspx
// 1 : Use basic (clear-text) authentication
// https://msdn.microsoft.com/en-us/library/ms526961.aspx
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/smtpauthenticate"] = 1;

// ユーザとパスワード
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/sendusername"] = $strUser;
$cdo->Configuration->Fields["http://schemas.microsoft.com/cdo/configuration/sendpassword"] = $strPass;

$cdo->Configuration->Fields->Update();

$cdo->Send();

// ***********************************************
// レジストリ内容
// ***********************************************
/*
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}]
@="CDOMessage Class"

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}\InprocServer32]
@="C:\\Windows\\system32\\cdosys.dll"
"ThreadingModel"="Both"

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}\ProgID]
@="CDO.Message.1"

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}\Programmable]

[HKEY_CLASSES_ROOT\CLSID\{CD000001-8B95-11D1-82DB-00C04FB1625D}\VersionIndependentProgID]
@="CDO.Message"
*/
?>

参考情報

メーラーからGmailへの接続時に認証(パスワード)のエラーが生じる場合の対処方法



posted by lightbox at 2015-10-03 21:44 | PHP + 通信 | このブログの読者になる | 更新情報をチェックする

2015年10月01日


Android : DatePickerDialog で、4種類のダイアログを使い分ける( spinner と calendar の組み合わせ )

Android 5.1 ですが、プログラムからスタイルの 1属性を(容易には)変更できないようなので、二つのスタイルを用意して必要な DatePickerDialog を作成して使用します。何もしないと、大きなカレンダーになり、初期表示の日付の前後の日付選択は簡単ですが、年月の変更をしたい場合は、スピナーを組み合わせる必要があります。

しかし、スピナーへの変更がスタイル経由でしかできないので、DatePickerDialog のコンストラクタでテーマを指定できるほうを使って適宜選択します。





<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="android:Theme.Material.Light">
    </style>

    <style name="MyDialogTheme" parent="android:Theme.Material.Light.Dialog">
        <item name="android:datePickerStyle">@style/MyDatePicker</item>
    </style>
    <style name="MyDialogTheme2" parent="android:Theme.Material.Light.Dialog">
        <item name="android:datePickerStyle">@style/MyDatePicker2</item>
    </style>

    <style name="MyDatePicker" parent="android:Widget.Material.DatePicker">
        <item name="android:datePickerMode">spinner</item>
    </style>
    <style name="MyDatePicker2" parent="android:Widget.Material.DatePicker">
        <item name="android:datePickerMode">calendar</item>
    </style>
</resources>


MainActivity
package sample.lightbox.calendar;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.DatePicker;

import java.util.Calendar;

public class MainActivity extends Activity {

	private DatePickerDialog spinnerDatePicker = null;
	private DatePickerDialog calendarDatePicker = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		final Calendar calendar = Calendar.getInstance();
		int year = calendar.get(Calendar.YEAR);
		int monthOfYear = calendar.get(Calendar.MONTH);
		int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);

		spinnerDatePicker = new DatePickerDialog(
				MainActivity.this,
				R.style.MyDialogTheme,
				new DatePickerDialog.OnDateSetListener() {
					@Override
					public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
						String buffer = String.format("%4d/%02d/%02d",year,monthOfYear+1,dayOfMonth);
						Log.i("lightbox",buffer);
					}
				},year,monthOfYear,dayOfMonth);

		calendarDatePicker = new DatePickerDialog(
				MainActivity.this,
				R.style.MyDialogTheme2,
				new DatePickerDialog.OnDateSetListener() {
					@Override
					public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
						String buffer = String.format("%4d/%02d/%02d",year,monthOfYear+1,dayOfMonth);
						Log.i("lightbox",buffer);
					}
				},year,monthOfYear,dayOfMonth);


		MainActivity.this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				spinnerDatePicker.getDatePicker().setSpinnersShown(true);
				spinnerDatePicker.getDatePicker().setCalendarViewShown(false);
				spinnerDatePicker.show();
			}
		});

		MainActivity.this.findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				spinnerDatePicker.getDatePicker().setSpinnersShown(false);
				spinnerDatePicker.getDatePicker().setCalendarViewShown(true);
				spinnerDatePicker.show();
			}
		});

		MainActivity.this.findViewById(R.id.button3).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				spinnerDatePicker.getDatePicker().setSpinnersShown(true);
				spinnerDatePicker.getDatePicker().setCalendarViewShown(true);
				spinnerDatePicker.show();
			}
		});

		MainActivity.this.findViewById(R.id.button4).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				calendarDatePicker.show();
			}
		});
	}

}

フラグメントバージョンは、Android Developer の Creating a Date Picker を参考にしますが、現状では getSupportFragmentManager では無く getFragmentManager を使用します。

また、常に spinner 側を使用するのであれば、メインテーマの中に、以下を入れてしまえばいいはずです。
<item name="android:dialogTheme">@style/MyDialogTheme</item>
参考


posted by lightbox at 2015-10-01 03:04 | Android Studio 2 | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり