SQLの窓

2016年06月26日


カスタム・リストビュー・ダイアログ : DialogFragment 内の ListView を ArrayAdapter でカスタムする



結果的には、DialogFragment を使用しない場合より簡単に実装できました。正直これで正しいのかどうかは解りませんが、ダイアログのインスタンスはシステムで再作成される事を前提にしているので、DialogFragment 内の onCreateDialog で全て実装する事によって、再度 View をセットするというような処理は必要ありません。但し、行を選択して閉じる時に、dismiss() によってダイアログを終わらせています。

リストビューのデータは、本来 newInstance で put すべきでしょうが、onCreateDialog 内で全て完結するほうがスッキリしているのでそうしました。

行のクリックでは、View からデータを取得していますが、MyData に何かメソッドを実装して実行したい場合は、
MyAdapter adapter = (MyAdapter) parent.getAdapter();
MyData my_data = (MyData) adapter.getItem(position);
で問題無いと思います MainActivity 内のソースコード
@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);

	// *********************************
	// ボタンをクリック
	// ( ダイアログフラグメント で表示 )
	// *********************************
	MainActivity.this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {

			 MyDialogFragment my_dialog_fragment = MyDialogFragment.newInstance("地域一覧");

			// ダイアログの表示
			// ※ この環境では、getSupportFragmentManager が必要です
			my_dialog_fragment.show(getSupportFragmentManager(),"dialog");

		}
	});

}

// *********************************
// static クラスの定義
// 1) DialogFragment
// 2) ArrayAdapter
// 3) MyData
// *********************************
public static class MyDialogFragment extends DialogFragment {

	// ユーザが呼び出す為のもの( 外側で処理しても良い )
	public static MyDialogFragment newInstance(String title) {
		// インスタンス作成
		MyDialogFragment my_dialog_fragment = new MyDialogFragment();
		// システムに引数を保存
		Bundle args = new Bundle();
		args.putString("title", title);
		my_dialog_fragment.setArguments(args);
		return my_dialog_fragment;
	}

	// *********************************
	// ここが、ダイアログの作成時に呼ばれます
	// 初回はユーザがダイアログを作成
	// デバイスを横にした時はシステムが
	// ダイアログを作成します
	// *********************************
	@Override
	public Dialog onCreateDialog(Bundle savedInstanceState) {

		// この中で使用するダイアログ作成用
		final AlertDialog.Builder ad_builder_in_fragment;

		// この DialogFragment に保存されているデータを取得
		// ( システムが再作成した場合でも Bundle よりデータを取得できます )
		String title = MyDialogFragment.this.getArguments().getString("title");

		// DialogFragment から Activity を取得して使う
		// ( ダイアログが使われる Activity を MyDialogFragment 内で取得しています )
		ad_builder_in_fragment = new AlertDialog.Builder(MyDialogFragment.this.getActivity());
		// タイトル設定
		ad_builder_in_fragment.setTitle(title);
		ad_builder_in_fragment.setNegativeButton("キャンセル", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// キャンセル
			}
		});
		// *********************************
		// ダイアログのメインビューに
		// リストビューを設定
		// *********************************
		LayoutInflater inflater = (LayoutInflater) MyDialogFragment.this.getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		ListView list_view = (ListView) inflater.inflate(R.layout.listview, null);
		// *********************************
		// 行をクリックした時のイベント
		// *********************************
		list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

				// View から行データを取得
				TextView tv;
				tv = (TextView) view.findViewById(R.id.textPlace);
				String textPlace = tv.getText().toString();
				tv = (TextView) view.findViewById(R.id.textCode);
				String textCode = tv.getText().toString();

				// メッセージの作成
				String message = String.format("%s : %s", textPlace, textCode);
				// logcat に表示
				Log.i("lightbox", message );
				// Toast で表示
				Toast.makeText(MyDialogFragment.this.getActivity(),message, Toast.LENGTH_SHORT).show();
				// TextView に表示
				tv = (TextView) MyDialogFragment.this.getActivity().findViewById(R.id.textView);
				tv.setText(message);

				// 破棄
				MyDialogFragment.this.dismiss();
			}
		});
		// *********************************
		// カスタム・アダプター
		// *********************************
		MyAdapter adapter = new MyAdapter(MyDialogFragment.this.getActivity(),R.layout.listview_item);

		// *********************************
		// ListView に表示するデータ
		// *********************************
		List<MyData> list = new ArrayList<MyData>();
		list.add(new MyData("大阪","27"));
		list.add(new MyData("東京","13"));
		list.add(new MyData("岡山","33"));
		list.add(new MyData("北海道","1"));
		list.add(new MyData("沖縄","47"));
		list.add(new MyData("京都","26"));
		list.add(new MyData("滋賀","25"));

		// *********************************
		// 新しく領域確保して配列データを作成する
		// *********************************
		MyData[] my_data = list.toArray( new MyData[0] );

		// *********************************
		// カスタム・アダプターにデータをセット
		// *********************************
		adapter.addAll(my_data);
		// *********************************
		// ListView にカスタム・アダプターをセット
		// *********************************
		list_view.setAdapter(adapter);

		ad_builder_in_fragment.setView(list_view);

		// ダイアログを作成してシステムに返す
		return ad_builder_in_fragment.create();
	}
}

// *********************************
// MyData 専用アダブター
// *********************************
public static class MyAdapter extends ArrayAdapter {

	public MyAdapter(Context context, int resource) {
		super(context, resource);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		View rowView = convertView;
		if (rowView == null) {
			// 現在の View の取得
			LayoutInflater inflater = (LayoutInflater) getContext().getSystemService
				(Context.LAYOUT_INFLATER_SERVICE);
			rowView = inflater.inflate(R.layout.listview_item, null);
		}

		MyData my_data = (MyData)this.getItem(position);

		TextView tv;
		// listview_item 内の textPlace にデータをセット
		tv = (TextView) rowView.findViewById(R.id.textPlace);
		tv.setText(my_data.toString());
		// listview_item 内の textCode にデータをセット
		tv = (TextView) rowView.findViewById(R.id.textCode);
		tv.setText(my_data.getValue());

		return rowView;
	}
}

// *********************************
// MyData
// *********************************
public static class MyData {

	private String myString;
	private String myValue;

	public MyData(String myString,String myValue) {
		this.myString = myString;
		this.myValue = myValue;
	}

	// データ取得用
	String getValue() {
		return myValue;
	}

	@Override
	public String toString() {
		return myString;
	}
}


※ 全てのソースコードはこちらにあります




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

カスタム・リストビュー・ダイアログ : ダイアログ内の ListView を ArrayAdapter でカスタムする


※ この処理には、DialogFragment は使用していません。

AlertDialog 内で表示されるリストビューを外側で定義してカスタマイズするサンプルです。AlertDialog.Builder の setView で、自由にダイアログ内のメインコンテンツを差し替えれるので、ListView をそのままセットしてみました。

もちろん、ArrayAdapter を継承した独自クラスを作成して、お決まりのその中での getView の処理も実装します。問題は、表示される度に ListView をセットしなおす必要がある事をテストして知りましたが、ListView を setView でセットした後に再度 setView する場合、いったん ListView を ダイアログ内の View から削除する必要がありました。

通常、DialogFragment では無い使い方では、 AlertDialog.Builder で作成された AlertDialog は常にメモリに残っているのでそのような処理が必要なのだと思います。ボタンがクリックされる度に、AlertDialog を 毎回 1 から作成して、使うのであればそのような必要も無いのでしょうが、そうなると使用後に削除する必要が出て来るのでこのような実装になっています。

行のクリックは、ListView の OnItemClickListener で行う事になるので、AlertDialog の hide メソッドで閉じています。

また、行データの参照は、Adapter を直接参照できるので、Adapter の getItem 経由で行っています。

MainActivity 内のソースコード
private AlertDialog ad = null;
private AlertDialog.Builder ad_builder;
private MyData[] my_data;
private ListView list_view;
private MyAdapter adapter;

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

	// *********************************
	// ListView に表示するデータ
	// *********************************
	List<MyData> list = new ArrayList<MyData>();
	list.add(new MyData("大阪","27"));
	list.add(new MyData("東京","13"));
	list.add(new MyData("岡山","33"));
	list.add(new MyData("北海道","1"));
	list.add(new MyData("沖縄","47"));
	list.add(new MyData("京都","26"));
	list.add(new MyData("滋賀","25"));

	// *********************************
	// 新しく領域確保して配列データを作成する
	// *********************************
	my_data = list.toArray( new MyData[0] );

	// *********************************
	// ノーマルダイアログ作成用インスタンス作成
	// *********************************
	ad_builder = new AlertDialog.Builder(MainActivity.this);
	// *********************************
	// タイトル設定
	// *********************************
	ad_builder.setTitle("地域一覧");
	// *********************************
	// キャンセルイベント
	// *********************************
	ad_builder.setNegativeButton("キャンセル", new DialogInterface.OnClickListener() {
		@Override
		public void onClick(DialogInterface dialog, int which) {
			// キャンセル
		}
	});
	// *********************************
	// ダイアログのメインビューに
	// リストビューを設定
	// *********************************
	LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
	list_view = (ListView) inflater.inflate(R.layout.listview, null);
	// *********************************
	// 行をクリックした時のイベント
	// *********************************
	list_view.setOnItemClickListener(new AdapterView.OnItemClickListener() {
		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

			// Adapter 内の行データを取得
			MyData my_data = (MyData) adapter.getItem(position);

			// メッセージの作成
			String message = String.format("%s : %s", my_data.toString(), my_data.getValue());
			// logcat に表示
			Log.i("lightbox", message );
			// Toast で表示
			Toast.makeText(MainActivity.this,message,Toast.LENGTH_SHORT).show();
			// TextView に表示
			TextView tv;
			tv = (TextView) MainActivity.this.findViewById(R.id.textView);
			tv.setText(message);

			// 非表示
			ad.hide();
		}
	});
	// *********************************
	// カスタム・アダプター
	// *********************************
	adapter = new MyAdapter(MainActivity.this,R.layout.listview_item);
	// *********************************
	// カスタム・アダプターにデータをセット
	// *********************************
	adapter.addAll(my_data);
	// *********************************
	// ListView にカスタム・アダプターをセット
	// *********************************
	list_view.setAdapter(adapter);

	// *********************************
	// ボタンをクリック
	// *********************************
	MainActivity.this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {

			// 初回はなにもしない
			if ( ad != null ) {
				// ダイアログ内の親 View から ListView を削除
				ViewGroup vg = (ViewGroup) list_view.getParent();
				vg.removeView(list_view);
			}
			// ダイアログに ListView をセット
			ad_builder.setView(list_view);
			// ダイアログの表示
			// ( AlertDialog は 非表示処理に使用 )
			ad = ad_builder.show();

		}
	});

}

// *********************************
// MyData 専用アダブター
// *********************************
private class MyAdapter extends ArrayAdapter {

	public MyAdapter(Context context, int resource) {
		super(context, resource);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		View rowView = convertView;
		if (rowView == null) {
			// 現在の View の取得
			LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService
				(Context.LAYOUT_INFLATER_SERVICE);
			rowView = inflater.inflate(R.layout.listview_item, null);
		}

		MyData my_data = (MyData)this.getItem(position);

		TextView tv;
		// listview_item 内の textPlace にデータをセット
		tv = (TextView) rowView.findViewById(R.id.textPlace);
		tv.setText(my_data.toString());
		// listview_item 内の textCode にデータをセット
		tv = (TextView) rowView.findViewById(R.id.textCode);
		tv.setText(my_data.getValue());

		return rowView;
	}
}

// *********************************
// MyData
// *********************************
private class MyData {

	private String myString;
	private String myValue;

	public MyData(String myString,String myValue) {
		this.myString = myString;
		this.myValue = myValue;
	}

	// データ取得用
	String getValue() {
		return myValue;
	}

	@Override
	public String toString() {
		return myString;
	}
}


※ 全てのソースコードはこちらにあります



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

AlertDialog.Builder の setItems(int itemsId, DialogInterface .OnClickListener listener) を使用した、ListView ダイアログ : ノーマルと DialogFragment の共存サンプル




ListView ダイアログの中の ListView を ArrayAdapter でカスタマイズする前のテンプレートとして作成しました。一般的には、setItems で、文字列の配列をセットするのが通常だと思われるので、どうせなら、と思ってリソースにデータを定義して使用しています。

カスタム・リストビュー・ダイアログ : ダイアログ内の ListView を ArrayAdapter でカスタムする

カスタム・リストビュー・ダイアログ : DialogFragment 内の ListView を ArrayAdapter でカスタムする

1) MainActivity 内でのリソースの参照
MainActivity.this.getResources()
2) public static class MyDialogFragment 内でのリソースの参照
MyDialogFragment.this.getActivity()

MainActivity 内のソースコード
// *********************************
// ノーマルでは ダイアログフラグメントは
// 使用していません
// *********************************
private AlertDialog.Builder ad_builder;

// *********************************
// Android 初期設定
// *********************************
@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	// 画面の表示
	setContentView(R.layout.activity_main);

	// *********************************
	// ノーマルダイアログ作成用インスタンス
	// *********************************
	ad_builder = new AlertDialog.Builder(MainActivity.this);
	// タイトル設定
	ad_builder.setTitle("地域一覧");
	ad_builder.setNegativeButton("キャンセル", new DialogInterface.OnClickListener() {
		@Override
		public void onClick(DialogInterface dialog, int which) {
			// キャンセル
		}
	});
	// *********************************
	// ノーマル用データのセットと、行を選択時の処理
	// *********************************
	ad_builder.setItems(R.array.ken, new DialogInterface.OnClickListener() {
		@Override
		public void onClick(DialogInterface dialog, int which) {

			String[] ken = MainActivity.this.getResources().getStringArray(R.array.ken);
			int[] ken_value = MainActivity.this.getResources().getIntArray(R.array.ken_value);

			// メッセージの作成
			String message = String.format("%s : %d", ken[which], ken_value[which]);

			// logcat に表示
			Log.i("lightbox", message );

			// Toast で表示
			Toast.makeText(MainActivity.this,message,Toast.LENGTH_SHORT).show();

			// TextView に表示
			TextView tv;
			tv = (TextView) MainActivity.this.findViewById(R.id.textView);
			tv.setText(message);

		}
	});

	// *********************************
	// ボタンをクリック
	// ( ノーマル表示 )
	// *********************************
	MainActivity.this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {

			// ダイアログの表示
			ad_builder.show();

		}
	});
	

	// *********************************
	// ボタンをクリック
	// ( ダイアログフラグメント で表示 )
	// *********************************
	MainActivity.this.findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
		@Override
		public void onClick(View v) {

			// インスタンス作成
			MyDialogFragment my_dialog_fragment = new MyDialogFragment();
			// システムに引数を保存
			Bundle args = new Bundle();
			args.putString("title", "地域一覧");
			my_dialog_fragment.setArguments(args);

			// 定義しておいた newInstance メソッドを使う場合
			// MyDialogFragment my_dialog_fragment = MyDialogFragment.newInstance("地域一覧");

			// ダイアログの表示
			// ※ この環境では、getSupportFragmentManager が必要です 
			my_dialog_fragment.show(getSupportFragmentManager(),"dialog");

		}
	});

}

// *********************************
// ここから、ダイアログフラグメントを使用して
// 表示する処理用のクラス定義です
// ダイアログフラグメント( static )
// *********************************
public static class MyDialogFragment extends DialogFragment {

	// ユーザが呼び出す為のもの( 外側で処理しても良い )
	public static MyDialogFragment newInstance(String title) {
		// インスタンス作成
		MyDialogFragment my_dialog_fragment = new MyDialogFragment();
		// システムに引数を保存
		Bundle args = new Bundle();
		args.putString("title", title);
		my_dialog_fragment.setArguments(args);
		return my_dialog_fragment;
	}

	// *********************************
	// ここが、ダイアログの作成時に呼ばれます
	// 初回はユーザがダイアログを作成
	// デバイスを横にした時はシステムが
	// ダイアログを作成します
	// *********************************
	@Override
	public Dialog onCreateDialog(Bundle savedInstanceState) {

		// この中で使用するダイアログ作成用
		AlertDialog.Builder ad_builder_in_fragment;

		// この DialogFragment に保存されているデータを取得
		// ( システムが再作成した場合でも Bundle よりデータを取得できます )
		String title = MyDialogFragment.this.getArguments().getString("title");

		// DialogFragment から Activity を取得して使う
		// ( ダイアログが使われる Activity を MyDialogFragment 内で取得しています )
		ad_builder_in_fragment = new AlertDialog.Builder(MyDialogFragment.this.getActivity());
		// タイトル設定
		ad_builder_in_fragment.setTitle(title);
		ad_builder_in_fragment.setNegativeButton("キャンセル", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// キャンセル
			}
		});
		// データのセットと、行を選択時の処理
		ad_builder_in_fragment.setItems(R.array.ken, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {

				// 現在の Activity
				// ( ダイアログが使われる Activity を MyDialogFragment 内で取得しています )
				FragmentActivity this_activity = MyDialogFragment.this.getActivity();

				// リソースより表示データと対応する内部コードを取得しています
				String[] ken = this_activity.getResources().getStringArray(R.array.ken);
				int[] ken_value = this_activity.getResources().getIntArray(R.array.ken_value);

				// メッセージの作成
				String message = String.format("%s : %d", ken[which], ken_value[which]);

				// logcat に表示
				Log.i("lightbox", message );

				// Toast で表示
				Toast.makeText(this_activity,message,Toast.LENGTH_SHORT).show();

				// TextView に表示
				TextView tv;
				tv = (TextView) this_activity.findViewById(R.id.textView);
				tv.setText(message);

			}
		});


		// ダイアログを作成してシステムに返す
		return ad_builder_in_fragment.create();
	}
}


※ 全てのソースコードはこちらにあります




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

2016年06月20日


ブラウザの geolocation で Google MAP に現在地を表示。ライブラリでさらに詳細情報。API の geocoder で名称・住所から Google MAP を表示して、ライブラリでさらに詳細情報を取得。

緯度・経度関連で、4つの機能を実装したデモページです


※ この デモは https でアクセスしますが、http でもアクセスできるので注意して下さい
※ http でアクセスした場合、Google Chrome では現在地を取得できません

1) navigator.geolocation.getCurrentPosition でブラウザの現在位置を取得
2) ライブラリ(DmGeocorder) を使用して緯度・経度から場所情報を取得
3) Google の API の geocoder.geocode で 住所・名前から緯度・経度を取得

4) Google Maps JavaScript API で MAP 表示

制限事項

Google Chrome ては、PC でも スマホでも、現在地取得には https を使うか localhost でないと動作しません。( 他のブラウザでは今のところ動作しているようですが、将来的には同じになる可能性があります )
事実、現在 Yahoo の雨雲ズームレーダでは、Chrome では現在位置が取れません。
通常のサイトで使用して、PC の開発者ツールで表示すると、以下のようにメッセージが出ます


getCurrentPosition() and watchPosition() are deprecated on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://goo.gl/rStTGz for more details.
DmGeocorder は、自分でサーバに準備して使うものです。ですが、とりあえずデモ内で使用しているものに関して外部からの使用制限は設けていません。 Google Maps JavaScript API は、API コンソールで登録した APIKEY を使用し、使用するドメインを登録しているので他所では使用できません。 もし、他所で使用しようとすると以下のようになります デモのソースコード
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">

<style>
body,input {
	font-family: "ヒラギノ角ゴPro W3","Hiragino Kaku Gothic Pro","メイリオ",Meiryo,"MS Pゴシック",Verdana,Arial,Helvetica,sans-serif;
	font-size: 16px;
}

a {
	color: navy;
}

#target_area {
	width: 600px; 
	height: 480px; 
}
#address {
	margin-bottom: 10px;
	width: 450px;
}


@media screen and (max-width:774px) {

	#target_area {
		width: 100%; 
	}

	#address {
		width: 250px;
	}

}
</style>

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
// *************************************
// 初期位置
// *************************************
var lat = 34.7013233;
var lng = 135.4966954;

var geo = null;


$(function(){

	// *************************************
	// 現在位置を取得してマップに反映する
	// *************************************
	$("#getcur").on("click",function(){

		// *************************************
		// Chrome では、この実行には https か 
		// localhost である必要があります
		// *************************************
		navigator.geolocation.getCurrentPosition(function(target){
			geo = target;
			console.dir(target);

			var obj = {};

			for( value in target.coords ) {
				obj[value] = target.coords[value];
			}

			// ブラウザの geolocation で取得した内容
			$("#latlng").text( JSON.stringify(obj,null,"    ") );

			lat = geo.coords.latitude;
			lng = geo.coords.longitude;

			// Google MAP の再表示
			loadMap(document,"target_area",lat,lng,15);

			// サーバーのライブラリから場所情報を取得
			$.get("https://lightbox.sakura.ne.jp/toolbox/g_ken.php?lat="
				+geo.coords.latitude
				+"&lng="
				+geo.coords.longitude,
				function(data){
					console.dir(data);
					$("#latlng2").text( JSON.stringify(data,null,"  ") );
			
				}
			);
				
		});

	});

});

</script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCQq2Yaz_ue8jVhf2LAQBlE73RJ17jd0tM"></script>
<script>
var geocoder = new google.maps.Geocoder();
var map;

$(function(){
	// *************************************
	// 住所・名前から位置情報を取得
	// *************************************
	$("#geo_action").on("click",function(){
		geocoder.geocode( {'address': $("#address").val()}, function(results, status) {
			if (status == google.maps.GeocoderStatus.OK) {
				map.setCenter(results[0].geometry.location);
				var marker = new google.maps.Marker({
					map: map,
					position: results[0].geometry.location
				});
				// lat と lng
				console.log(results[0].geometry.location.lat(),results[0].geometry.location.lng());

				// *************************************
				// サーバーのライブラリから場所情報を取得
				// *************************************
				$.get("https://lightbox.sakura.ne.jp/toolbox/g_ken.php?lat="
					+results[0].geometry.location.lat()
					+"&lng="
					+results[0].geometry.location.lng(),
					function(data){
						console.dir(data);
						$("#latlng2").text( JSON.stringify(data,null,"  ") );
				
					}
				);

			}
			else {
				alert("Geocode が失敗しました : " + status);
			}
		});
	});
});

// *************************************
// Google MAP の表示
// *************************************
function loadMap(doc,obj_str,a,b,c) {
	var latlng = new google.maps.LatLng(a,b);
	var myOptions = {
		zoom: c,
		center: latlng,
		mapTypeControlOptions: {
			mapTypeIds: [
				google.maps.MapTypeId.HYBRID,
				google.maps.MapTypeId.ROADMAP,
				google.maps.MapTypeId.SATELLITE
			],
			style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
		},
		mapTypeId: google.maps.MapTypeId.HYBRID,
		scaleControl: true
	};
	map = new google.maps.Map(doc.getElementById(obj_str),myOptions);
}

// *************************************
// 最初の Google MAP の表示
// *************************************
google.maps.event.addDomListener(window, 'load', function () {
	loadMap(document,"target_area",lat,lng,15);
}); 
</script>
</head>
<body>

住所 <input type="text" id="address"> <input type="button" id="geo_action" value="実行">
<div id='target_area'></div>
<br><br>
<input type="button" id="getcur" value="現在位置を取得してマップに反映する">

<br>
▼ ブラウザの geolocation で取得した内容
<pre id="latlng"></pre>
▼ <a target="_blank" href="https://github.com/demouth/DmGeocoder">ライブラリ</a>より取得した場所情報
<pre id="latlng2"></pre>


</body>
</html>


以下のツールで、スマホで簡単に URL を送る事ができます。



posted by lightbox at 2016-06-20 15:01 | Google | このブログの読者になる | 更新情報をチェックする

2016年06月18日


MySQL で、主キーの作り変えのプロセス / serial では、自動的に インデックスが作成されます

serial は、自動採番列を作成する為に使いますが、その際列名でユニークインデックスが作成されています。しかし、bigint(20) unsigned NOT NULL AUTO_INCREMENT で作成した場合は何も作成されないので、削除しても動作します。

ストーリー

掲示板テーブルを作成しましたが、主キーを自動採番列としているので、一つの掲示板でしか使用する事が出来ないため、掲示板(スレッド)を区別する為の ID として no 列を追加する事が目的です。

現状確認

show create table board で、MySQL に登録されている create table 文を取得します。この時、UNIQUE KEY `row_no` (`row_no`) が定義されている事が解ります。

列追加

alter table `board` add `no` VARCHAR(20) after `row_no` で、元の主キーである row_no の後ろに no 列を追加します。この時、既にデータが投入されている場合は、no の中は null が設定されます。

主キー削除

主キーを作り変える為に、いったん現在の主キーを alter table board drop primary key で削除します。そして、show create table board で定義の変化を確認します。

主キー作成

既にデータが投入されている場合は、no 列が null の為、主キーが作成できません。なので、全ての列のデータに何かデータをセットします( update board set no = '0' )

その後、alter table board add primary key(`row_no`,`no`) で主キーを作成します。

serial で作成されたユニークキーの削除

特に実行する必要はありませんが、それほど必要なインデックスでは無いので削除する場合は、show index from board でインデックス名を確認して、alter table board drop index row_no で削除します。

データの復帰

既に新しいフォーマットで作成されたデータがある場合は、insert into board select * from board2 という SQL でデータを投入できます。
※ board2 が保存されていた新しいフォーマットのデータ

-- 最初に作成したテーブルのSQL
CREATE TABLE `board` (
  `row_no` serial,
  `body` varchar(1000),
  `subject` varchar(200),
  `from` varchar(20),
  `pdate` datetime,
  `cdate` datetime,
  primary key(`row_no`)
);

show create table board;

CREATE TABLE `board` (
  `row_no` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `body` varchar(1000) DEFAULT NULL,
  `subject` varchar(200) DEFAULT NULL,
  `from` varchar(20) DEFAULT NULL,
  `pdate` datetime DEFAULT NULL,
  `cdate` datetime DEFAULT NULL,
  PRIMARY KEY (`row_no`),
  UNIQUE KEY `row_no` (`row_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 主キーに掲示板IDを追加する為に、no 列を row_no の後に追加
alter table `board` add `no` VARCHAR(20) after `row_no`;

-- 主キーの削除
alter table board drop primary key;

show create table board;

CREATE TABLE `board` (
  `row_no` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `no` varchar(20) DEFAULT NULL,
  `body` varchar(1000) DEFAULT NULL,
  `subject` varchar(200) DEFAULT NULL,
  `from` varchar(20) DEFAULT NULL,
  `pdate` datetime DEFAULT NULL,
  `cdate` datetime DEFAULT NULL,
  UNIQUE KEY `row_no` (`row_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--※ すでにデータがある場合( no にセットするのは適当な文字列 )
update board set no = '0';

-- 主キー作成
alter table board add primary key(`row_no`,`no`);

show create table board;

CREATE TABLE `board` (
  `row_no` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `no` varchar(20) NOT NULL DEFAULT '',
  `body` varchar(1000) DEFAULT NULL,
  `subject` varchar(200) DEFAULT NULL,
  `from` varchar(20) DEFAULT NULL,
  `pdate` datetime DEFAULT NULL,
  `cdate` datetime DEFAULT NULL,
  PRIMARY KEY (`row_no`,`no`),
  UNIQUE KEY `row_no` (`row_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- インデックスの確認
show index from board;

-- インデックスの削除( ここは内容確認の為 )
alter table board drop index row_no;

CREATE TABLE `board` (
  `row_no` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `no` varchar(20) NOT NULL DEFAULT '',
  `body` varchar(1000) DEFAULT NULL,
  `subject` varchar(200) DEFAULT NULL,
  `from` varchar(20) DEFAULT NULL,
  `pdate` datetime DEFAULT NULL,
  `cdate` datetime DEFAULT NULL,
  PRIMARY KEY (`row_no`,`no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

-- 保存していたデータの復帰
insert into board select * from board2;




タグ:SQL
posted by lightbox at 2016-06-18 13:38 | MySQL | このブログの読者になる | 更新情報をチェックする

2016年06月15日


AsyncTask<Params, Progress, Result> の Progress を無しにして、onPostExecute 内の処理を interface を使って MainActivity 側で実行できるようにするクラスの作成と実行 : ジェネリクスの継承

通常使うのが、doInBackground で、その戻り値が UI スレッドで実行できればいい、と言うことを大目的としたクラスです。

UI スレッドに処理を投げる為に、専用の execute メソッドほもう一つ作って、そこの第一引数にイベントとしてインターフェイスを使うようにしています。

doInBackground は、Override される事が前提なので、なにもしていません。

StdAsyncTask
package lightbox.june.loadimage;

import android.os.AsyncTask;

public class StdAsyncTask<Params, Result> extends AsyncTask<Params, Void, Result> {

	UiAction<Result> ua = null;

	public interface UiAction<Result> {
		public void actUiAction(Result result);
	}

	public void execute(UiAction<Result> ua, Params... params) {
		this.ua = ua;
		this.execute(params);
	}

	@Override
	protected Result doInBackground(Params... params) {
		return null;
	}

	@Override
	protected void onPostExecute(Result result) {
		if( ua != null ) {
			ua.actUiAction(result);
		}
	}

}

AsyncTask の 二番目の 仮型引数 を Void にして、継承したほうでは必要無いようにしています。

そして、これをこのまま使ってもいいのですが、Drawable のデータを取得するという目的に特化した、StdAsyncTask を継承した HttpDrawable クラスが以下になります。
package lightbox.june.loadimage;

import android.graphics.drawable.Drawable;
import android.util.Log;

import java.io.InputStream;
import java.net.URL;

public class HttpDrawable extends StdAsyncTask<String,Drawable> {

	@Override
	protected Drawable doInBackground(String... params) {

		Drawable image = null;
		try {
			// インターネット上の画像を取得して、Drawable に変換
			URL url = new URL((String) params[0]);
			InputStream is = (InputStream)url.getContent();
			image = Drawable.createFromStream(is, "");
			is.close();
		}
		catch(Exception e) {
			Log.i("button", "インターネットのアクセスでエラーが発生しました");
		}
		return image;
	}

}


実行は、URL を用意して、イベント処理で画面の処理を行うのみとなります。
package lightbox.june.loadimage;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

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

		MainActivity.this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				String url = "http://news.biglobe.ne.jp/img/blnews/animal160128_02.jpg";
				HttpDrawable hd = new HttpDrawable();
				hd.execute(new StdAsyncTask.UiAction<Drawable>() {
					@Override
					public void actUiAction(Drawable drawable) {

						ImageView iv = (ImageView) MainActivity.this.findViewById(R.id.imageView);
						if ( drawable != null ) {
							iv.setImageDrawable(drawable);
						}

					}
				},url);

			}
		});
	}
}



posted by lightbox at 2016-06-15 21:53 | 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 終わり