uzullaの日記

本家:about等:Twitter
 | 

2008-06-11

単なるflatなボタンが欲しいんだけど

| 07:49

ただ単に、一色で、ボーダーとかなく、グラデとかなく、プレーンなFlatボタンがほしいんだけど…。

(カッコイイとかじゃなく、デザイナーの指示がそうだったので…)


Buttonクラスは色々な設定ができるのだが(プロパティが数えられないほど)、

	<mx:Button label="text"   
		fillAlphas="[1.0, 1.0]" 
		fillColors="[#990000, #990000, #FF0000, #FF0000]" 
		color="0xFFFFFF"
		textRollOverColor="0xFFFFFF"
        	textSelectedColor="0xFFFFFF"
        	highlightAlphas="[0.0, 0.0]"
        	borderColor="0x00990000"
 		themeColor="#FF0000"/>

とか色々やっても完全にプレーンなものがつくれなかった。

何となくソレっぽいから俺的にはもうこれでいいんじゃね?とおもうけど、くおりてぃちぇっく通らないとめんどくさいな…。


…簡単なコンポーネント書くか…。


mx.skins.halo.ButtonSkin?

mx.skins.halo.ButtonSkin とかいうのと同等な物を用意すればできるんかなあ、

でもよくわからんし、自分で書いたほうが速いな…間違いなく。


よく考えれば(考えなくても)

静的な画像を用意して、RollOverで差し替えるっつうHTML的な手法でもいいよなー…w

デザイナーから上がってきた画像にできるだけ似せる、というだけの話だし。


書いた

Enable/Disable辺りが適当すぐる、単に消すだけってww

package jp.cfe.widget
{
	
	import flash.events.MouseEvent;
	
	import mx.controls.Label;
	import mx.core.UIComponent;
	import mx.events.ResizeEvent;
/*
 フラットなボタンを作成する

	btn = new FlatButton();
	btn.setupByText(genImg, 0x990000, 0xFF0000, "ボタンテキスト", 0xFFFFFF,10,10);
	btn.move(250, 390);
	this.addChild(btn);

	btn.enable = false; //ボタンを隠す
*/

	public class FlatButton extends UIComponent
	{
		private var elipseWidth:uint = 1;
		private var elipseHeight:uint = 1;
		private var color:uint = 0;
		private var roColor:uint = 0;
		private var text:Label = new Label();
		
		private var vPadding:uint = 3 * 2;
		private var hPadding:uint = 40 * 2;
				
		private var onClickFunction:Function;
		
		public function FlatButton()
		{
			super();
			this.addChild(text);
			//text.text = '';
		}
		
		public function setupByText(_onClickFunction:Function, //クリックされたときの関数
				_color:uint=0x990000, //ボタンボディの色
				_rocolor:uint=0xFF0000, //マウスオーバー時のボタンボディの色
				_text:String="", //テキスト
				_textColor:uint=0x000000, //テキストの色
				_ew:uint=10, _eh:uint=10 //カドの丸さ
				):void
		{
			color = _color;
			roColor = _rocolor;

			text.text = _text;
			text.setStyle("color", _textColor);
			text.setStyle("textAlign", "center");
			text.setStyle("fontWeight", "bold");
			text.setStyle("fontSize", 13 );
			elipseWidth = _ew;
			elipseHeight = _eh;
											
			onClickFunction = _onClickFunction;
			
			this.addEventListener(ResizeEvent.RESIZE, onResize);
			this.addEventListener(MouseEvent.CLICK, onClick);
			this.addEventListener(MouseEvent.MOUSE_OVER, onMouseIn);
			this.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
			
			draw();
		}
		
		//
		// ボタンを押せないように、消す
		//
		public function set enable(_enable:Boolean):void{
			if(_enable){
				this.visible = true;
				this.addEventListener(MouseEvent.CLICK, onClick);
			}else{
				this.visible = false;
				this.removeEventListener(MouseEvent.CLICK, onClick);				
			}
		}
		

		//
		//  ボタンの色を切り替える
		//
		private function drawBase(roFlag:Boolean):void{
				//再描画する
				this.graphics.clear();
				
				var _color:uint = (roFlag == true)? roColor: color;
				this.graphics.beginFill(_color);
				this.graphics.drawRoundRect(0,0,this.width,this.height,elipseWidth,elipseHeight);
		}

		//
		// 描画する
		//		
		private function draw():void
		{
			text.validateNow();

			this.width  = text.textWidth      + hPadding;
			this.height = text.textHeight + 1 + vPadding; //なぜか文字の下1ドットが切れるので

			drawBase(false);
			text.width = this.width;
			text.height = text.textHeight + 1;
			text.y = this.height/2 - text.height/2 - 2;

		}
		
		
		private function onClick(e:MouseEvent):void{
			onClickFunction();
		}	
		private function onResize(e:ResizeEvent):void{
			draw();
		}
		private function onMouseIn(e:MouseEvent):void{
			drawBase(true);
		}
		private function onMouseOut(e:MouseEvent):void
		{
			drawBase(false);
		}
		
	}
}

まあ、これくらいだと俺みたいなダサ坊でも数十分で書ける訳で、Flexは楽でイイですね。



FlexにJPEG画像を読み込ませる為に、一度サーバーで反射させるやり方

| 05:35

最近なんにも書いてないので。

Flexで画像を編集するツールを書いているが、Flexだと当然ローカルファイルがよめないので、一度サーバーにULして、それをDLしてローディングする必要がある。


リフレクター

サーバーPHPとかでこんなのを設置する


<?php
/*
Filedataというnameでファイルをポストすると、
./images/{GUID}_filename.jpg
に保存し、URLの文字列をレスポンスする。
*/

$MAXIMUM_FILESIZE = 1024 * 2000; // 2000KB
$MAXIMUM_FILE_COUNT = 10; // keep maximum 10 files on server

require("Guid.php");
$Guid = new Guid();
$filename = $Guid->toString() . "_" .$_FILES['Filedata']['name'];

if ($_FILES['Filedata']['size'] <= $MAXIMUM_FILESIZE)
{
  move_uploaded_file($_FILES['Filedata']['tmp_name'], "./temporary/".$filename);
  $type = exif_imagetype("./temporary/".$filename);

  if ($type == 1 || $type == 2 || $type == 3){ // GIF or JPG or PNG.
    rename("./temporary/".$filename, "./images/".$filename);
  } else{ // Not popular image format.
    unlink("./temporary/".$filename);
    echo "NG";
    exit;
  }
}else{
  echo "OVERSIZE";
  exit;
}

$directory = opendir('./images/');
$files = array();

while ($file = readdir($directory))
{
  array_push($files, array('./images/'.$file, filectime('./images/'.$file)));
}

usort($files, sorter);

if (count($files) > $MAXIMUM_FILE_COUNT)
{
  $files_to_delete = array_splice($files, 0, count($files) - $MAXIMUM_FILE_COUNT);
  for ($i = 0; $i < count($files_to_delete); $i++)
    {
      @unlink($files_to_delete[$i][0]);
    }
}

closedir($directory);
print("http://localhost/images/".$filename);

function sorter($a, $b)
{
  if ($a[1] == $b[1])
    {
      return 0;
    }
  else
    {
      return ($a[1] < $b[1]) ? -1 : 1;
    }
}
?>

上のコードはかなり適当、Adobeのサンプルコード*1を多少弄った物。

guid.php*2は適当なランダムファイル名を付ける為の物。

処理としては、POSTされたファイルをサーバーに保存し、そのファイルをHTTPでGETできるURLを返す。

途中でファイルが画像であるかチェックしているが、この辺り省けば何のファイルでも使える。


ライブラリ

次はメインとなるライブラリ

package jp.cfe.file
{
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.net.FileFilter;
	import flash.net.FileReference;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	
	import mx.managers.CursorManager;

/**
 * サーバーにファイルをアップロードして、アップロードされたファイルのURLを取得する。
 * var rl:ReflectLoad = new ReflectLoad(callbackFunction);
 * rl.setFileFilter("Images", "*.jpg;*.gif;*.png");
 * rl.browse();
 * 
 * アップロードが終わったらコールバック関数が呼ばれる。
 * 
 */
	public class ReflectLoad
	{
		
		private var _fr:FileReference;
		private var _ff:FileFilter = null;
		
		public var fileUrl:String;
		public var status:Boolean = false;
	
		public var reflectorUrl:String = "http://localhost/ul.php";
		public var uploadParamName:String = "Filedata";

		public var responseHandlerFunction:Function;

		public function ReflectLoad(_func:Function)
		{
			_fr = new FileReference();
			_fr.addEventListener(Event.SELECT, imgSelectHandler);
			_fr.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,imgUploadCompleteHandler);
			responseHandlerFunction = _func;
		}

		public function browse():void{
			_fr.browse([_ff]);
		}

		public function setFileFilter(desc:String, suffix:String):void{
			_ff = new FileFilter(desc, suffix);
		}

		private function imgSelectHandler(event:Event):void{
			//マウスカーソルをBusyに
			CursorManager.setBusyCursor();
			
		    var request:URLRequest = new URLRequest(reflectorUrl);
		    var params:URLVariables = new URLVariables();

		    request.method = URLRequestMethod.POST;
		    request.data = params;

		    _fr.upload(request,uploadParamName);
		}
		
		private function imgUploadCompleteHandler(event:DataEvent):void{
			 if(event.data.toString().substr(0,4) == 'http'){
		 		//Alert.show(event.data.toString());
				fileUrl = event.data.toString();
				status = true;
				responseHandlerFunction(this);
			 }else{
			 	// maybe, server was failed.
				status = false;
				responseHandlerFunction(this);
			 	//Alert.show("something wrong");
			 }
			 
 			//マウスカーソルをnomalに
			CursorManager.removeBusyCursor();
		}


	}
  
}


利用例

で、上のライブラリはこんな風に使う。

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.net.URLRequest;
import mx.controls.Image;
import mx.managers.CursorManager;
	
import jp.cfe.file.ReflectLoad;
	
private _loader:Loader;

//
// reflectLoadを用いて画像をロード 1
// ファイル選択画面を出す
//
private function loadNewImg():void{
	var _rl:ReflectLoad = new ReflectLoad(rlCallback);
	_rl.setFileFilter("Images", "*.jpg;*.gif;*.png");
	_rl.browse();
}
//
// reflectLoadを用いて画像をロード 2
// ULした画像をLoaderでDLロードする
//
private function rlCallback(_rl:ReflectLoad):void{
	if(_rl.status){
		//マウスカーソルをBusyに
		CursorManager.setBusyCursor();
		_loader = new Loader();
		_loader.load( new URLRequest(_rl.fileUrl) );
		_loader.contentLoaderInfo.addEventListener( Event.COMPLETE, completedata );
	}else{
		//ULにミスっているのでエラー表示とか

	}
}
//
// reflectLoadを用いて画像をロード 3
// ロードが終わったloaderのデータをBitmapDataに展開し、諸々の処理をする。
//
public function completedata(e:Event):void{
	bmd = new BitmapData(_loader.content.width, _loader.content.height);
	var _image:Image = new Image();
	_image.source = new Bitmap(bmd);
	this.addChild(_image);
	CursorManager.removeBusyCursor();
}

こんな感じでロードする。


こんな面倒くさい事を本当はしたくないので

セキュリティ的な問題で直接ロードが出来ないようになっていると思うのだが、やる側がやったらこんな風にできるような事なので、fileReferenceから直接ByteArrayとかにロードできる仕組みが欲しいとおもった。

AIRとかだとできるんだけどなー。


後、Flexはイベント駆動なので、単にULしてDLしてロードするのに三個も関数をまたがねばならない。

実際、上の例だと_imageがロードされるイベントも待たなければならないので…めんどくさい。

もっとすっきり書ければいいのにな。

 |