[转载]socket 实现WordPress博客自动发文系列 之 登录

mikel阅读(1091)

[转载]socket 实现WordPress博客自动发文系列 之 登录 – 啊峰 – 博客园.

没有时间详细的写文章了,就随便记录并且分享一下。该方法能扩展到秒杀器哦。只是针对不同的网站 需要不同的分析而已。

公司需求以后要能从自己的文章资源平台,选择文章发布到wordpress站群,所以需要一个自动发布文章的小功能。工作之余发布到园子里和大家分享下。

之前尝试用httpwebrequest 对象方式去实现但发现有cookies接收不全的现象,所以改用socket 模拟http post请求去实现,代码写的很乱,只是初步的探索,也参考了很多园子里前辈的代码。小小AD下:
.net技术研究QQ群(  41050480)
合肥软件开发技术联盟(31065717)
非常渴望和大家一起交流!

主要几个方法:

///
/// 带上cookies 获取需要登录验证的页面
///
///
<span> </span>请求的URL          ///
cookies字符串          ///
页面编码          ///
public string GetPage(string url, string cookies, string encoding)
{
Uri URI = new Uri(url);
string strHTML = string.Empty;//用来保存获得的HTML代码
IPHostEntry gist = Dns.GetHostEntry(URI.Host);//获得当前URL的IP地址
IPAddress ip = gist.AddressList[0];//提取IP地址
IPEndPoint ipEnd = new IPEndPoint(ip, 80);//封装IP地址和端口
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//实例化Stock
try
{
socket.Connect(ipEnd);
}//自动循环捕捉连接
catch
{ }
string sendString = "GET " + URI.PathAndQuery + " HTTP/1.1\r\n";
sendString += "Connection:close\r\n";
sendString += "Content-Type: application/x-www-form-urlencoded\r\n";
sendString += "Host:" + URI.Host + "\r\n";
if (!string.IsNullOrEmpty(cookies))
sendString += "Cookie:" + cookies + "\r\n\r\n";
byte[] ms = UTF8Encoding.GetEncoding(encoding).GetBytes(sendString);//将头部转换成byte形式
socket.Send(ms);//发送
int recv = -1;//定义接受数据长度
byte[] data = new byte[1024];//用来保存接收数据
do
{
recv = socket.Receive(data);
strHTML += Encoding.GetEncoding(encoding).GetString(data, 0, recv);
} while (recv != 0);
return strHTML;
}

socket方式post 登录 之前用httpwebrequest方式 但始终登录不了,原因是cookies接受不全,就改用socket方式 自行处理cookies

///
///
///
///
<span> </span>登录地址          ///
发送的字符串          ///
网页编码          ///
public string PostData(string postURL,string postString, string encoding)
{
string strHTML = "";//用来保存获得的HTML代码
Uri URI = new Uri(postURL);
string sendString;
sendString = "POST {0} HTTP/1.1\r\n";
sendString += "Host: {1}\r\n";
sendString += "User-Agent:Mozilla/5.0 (Windows NT 6.1; rv:5.0) Gecko/20100101 Firefox/5.0\r\n";
sendString += "Content-Type:application/x-www-form-urlencoded\r\n";
sendString += "Content-Length:{2}\r\n";
sendString += "Connection:close\r\n\r\n";
sendString += "{3}\r\n";
sendString = string.Format(sendString, URI.PathAndQuery, URI.Host, postString.Length, postString);
Byte[] ByteGet = Encoding.GetEncoding(encoding).GetBytes(sendString);
IPAddress hostadd = Dns.GetHostEntry(URI.Host).AddressList[0];
IPEndPoint EPhost = new IPEndPoint(hostadd, 80);
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s.Connect(EPhost);
if (!s.Connected)
{
strHTML = "链接主机失败";
}
s.Send(ByteGet, ByteGet.Length, SocketFlags.None);
strHTML = Recv(s, Encoding.GetEncoding(encoding));
return strHTML;
}

处理cookies以及重定向问题

///
/// 从返回的源代码中提取cookies 以及301或302跳转
///
///
///
///

public string GetCookies(string html, out string location)
{
StringBuilder sbCookies = new StringBuilder();
location = string.Empty;
string[] arr = html.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (string str in arr)
{
if (str.StartsWith("Set-Cookie: "))
{
int intStart = str.IndexOf(";");
string strCookie = str.Substring(12, intStart - 11);
sbCookies.Append(strCookie);
}
if (str.StartsWith("Location:"))
{
location = str.Substring(10);
}
}
return sbCookies.ToString();
}

项目打包下载 vs2010环境

/Files/chjf2008/AutoPostSolution.rar

[转载]Android开发教程 --- 葵花宝典第四层 控件之 Toast Spinner RadioButton

mikel阅读(923)

[转载]Android开发教程 — 葵花宝典第四层 控件之 Toast Spinner RadioButton – Jason_CC – 博客园.

Hi 大家好!

今天继续我们的控件学习,今天主要学习3种控件

1 Toast — 提示信息 (这种提示是不能获取到焦点,并且会在一定时间内消失,类似与Windows软件中的气泡消息)

2 Spinner — 下拉菜单 (这个就不用解释了吧。。)

3 RadioButton — 单选按钮 (同上)

那么,课程开始之前,同样是先上笑话。。

诊所门前坐着3个小孩——大男孩、小男孩、女孩。 护士问:小朋友,哪儿不舒服? 大男孩:我吞下了一个玻璃球。 护士问另一个:你呢?

女孩:那玻璃球是我的。 护士又问:哪你呢? 小男孩:接下来是我玩! 🙂

首先是Toast,先来看看运行起来默认的效果,如下图

这种效果还是比较常用的,其实Toast有5种不同的实现效果,本人觉得有3种比较常用,在这里我主要讲3种不同类型的Toast,分别是 默认效果、自定义位置效果、带图片效果。贴上代码,代码中都有详细注释:
[Java]
package TSD.Jason.Example;

import Android.app.Activity;
import Android.os.Bundle;
import Android.view.Gravity;
import android.view.MotionEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;

public class ToastActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.toast);
}

/* 屏幕触点事件
*该方法并不只处理一种事件,一般情况下以下三种情况的事件全部由onTouchEvent方法处理,
*只是三种情况中的动作值不同。
*
*屏幕被按下:当屏幕被按下时,会自动调用该方法来处理事件,此时MotionEvent.getAction()
*的值为MotionEvent.ACTION_DOWN,如果在应用程序中需要处理屏幕被按下的事件,
*只需重新该回调方法,然后在方法中进行动作的判断即可。
*
*屏幕被抬起:当触控笔离开屏幕时触发的事件,该事件同样需要onTouchEvent方法来捕捉,然后在方法中进行动作判断。
*当MotionEvent.getAction()的值为MotionEvent.ACTION_UP时,表示是屏幕被抬起的事件。
*
*在屏幕中拖动:该方法还负责处理触控笔在屏幕上滑动的事件,同样是调用MotionEvent.getAction()
*方法来判断动作值是否为MotionEvent.ACTION_MOVE再进行处理。
*
*
*
* event.getAction() //获取触控动作比如ACTION_DOWN

* event.getPointerCount(); //获取触控点的数量,比如2则可能是两个手指同时按压屏幕

event.getPointerId(nID); //对于每个触控的点的细节,我们可以通过一个循环执行getPointerId方法获取索引

event.getX(nID); //获取第nID个触控点的x位置

event.getY(nID); //获取第nID个点触控的y位置

event.getPressure(nID); //LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的

event.getDownTime() //按下开始时间

event.getEventTime() // 事件结束时间

event.getEventTime()-event.getDownTime()); //总共按下时花费时间

Toast.LENGTH_SHORT 较短时间
Toast.LENGTH_LONG 较长时间
*
* */
@Override
public boolean onTouchEvent(MotionEvent event) {

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println(“用户按下”);
break;
case MotionEvent.ACTION_UP:
System.out.println(“用户抬起”);
break;
case MotionEvent.ACTION_MOVE:
System.out.println(“用户移动”);
break;
}
Toast.makeText(this,”Toast 的使用方式:点击的X轴为:”+ event.getX() + ” 点击的Y轴为:” + event.getY(),
Toast.LENGTH_SHORT).show();
return true;
}

/**
* 自定义Toast显示位置
*/
private void ShowToast()
{
Toast toast = Toast.makeText(this,”Toast自定义的显示位置”,Toast.LENGTH_SHORT);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}

/**
* 自定义带图片的Toast
*/
private void ShowImgToast()
{
Toast toast = Toast.makeText(getApplicationContext(),
“带图片的Toast”, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
LinearLayout toastView = (LinearLayout) toast.getView();
ImageView imageCodeProject = new ImageView(getApplicationContext());
imageCodeProject.setImageResource(R.drawable.icon);
toastView.addView(imageCodeProject, 0);
toast.show();
}
}
[/java]

自定义位置效果运行如下图:

toast.setGravity(Gravity.CENTER, 0, 0); setGravity方法中

第一个参数是将Toast显示在什么方位,这里是居住

第二个参数 设置X轴的偏移量

第三个参数 设置Y轴的偏移量

大家可以动手修改下参数,然后运行看看效果。

带图片的Toast,运行效果如下图

我们代码中用到了一个事件,叫做 onTouchEvent() ,这个事件主要是用来捕获用户触摸屏幕的操作

这些标注出来的地方我在代码中已经详细注释了,希望大家认真思考,弄明白。

Spinner

下拉控件在Web页面中使用的频率大家有目共睹,是一个非常重要的控件。那么在Android中,它张什么样子呢?如下图

代码及注释如下:

package TSD.Jason.Example;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;

public class SpinnerActivity extends Activity {
private static final String[] m_types = {"A型","B型","AB型","0型","其他"};
private Spinner m_Spinner;
private ArrayAdapteradapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.spinner);
m_Spinner = (Spinner)this.findViewById(R.id.spinner1);

//将可选内容与ArrayAdapter连接
//第二个参数表示spinner没有展开前的UI类型
adapter = new ArrayAdapter(this,
android.R.layout.simple_spinner_item, m_types);

//设置下拉列表风格 第1种 simple_spinner_dropdown_item 第2种 simple_spinner_item
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
m_Spinner.setAdapter(adapter);

//设置下拉列表选中项监听事件
m_Spinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
/*
* 第一个参数  是适配器 <!--?-->是适配器里内容的类型,可把?改成你存的类型。
* 第二个参数 是你当前选择的view
* 第三个参数 是你所选项在适配器中的索引位置
* 第四个参数 选定项目的行数
*/
@Override
public void onItemSelected(AdapterView<!--?--> arg0, View arg1,
int arg2, long arg3) {
// TODO Auto-generated method stub
System.out.println(arg2);
System.out.println(arg3);
Toast.makeText(getApplicationContext(), "你选中的是" +m_types[arg2], Toast.LENGTH_SHORT).show();
}

//没选中或什么都不选时调用
@Override
public void onNothingSelected(AdapterView<!--?--> arg0) {
// TODO Auto-generated method stub
}

});

}
}

下拉菜单控件还是比较简单的,这里就不在过多介绍了

RadioButton

单选按钮大家应该不陌生吧,它在Android中是什么样呢?其实刚才在下拉菜单中大家已经看到了它的样子,上图

先看看布局文件中是如何定义的:

<!--?xml version="1.0" encoding="utf-8"?-->





大家注意到了吗?在RadioButton外边还嵌套了一层RadioGroup?

大家回忆一下在HTML中我们如何定义一组单选按钮呢? 是不是要通过一个叫做name的属性。将name设置为同一个名字,那么这些相同name的就在一个组中了,从而实现单选按钮效果,那么这个RadioGroup其实也类似与name属性,将一些单选按钮包裹成一组。

package TSD.Jason.Example;

import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;

public class radiobuttonActivity extends Activity {
RadioGroup m_RadioGroup;
RadioButton m_Radio1, m_Radio2, m_Radio3, m_Radio4;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.radiobutton);
m_RadioGroup = (RadioGroup) findViewById(R.id.radioGroup1);
m_Radio1 = (RadioButton) findViewById(R.id.radio0);
m_Radio2 = (RadioButton) findViewById(R.id.radio1);
m_Radio3 = (RadioButton) findViewById(R.id.radio2);
m_Radio4 = (RadioButton) findViewById(R.id.radio3);

/* 设置事件监听 */
m_RadioGroup
.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
// TODO Auto-generated method stub
if (checkedId == m_Radio2.getId()) {
DisplayToast("正确答案:" + m_Radio2.getText()
+ ",恭喜你,回答正确!");
} else {
DisplayToast("请注意,回答错误!");
}
}
});
}

/* 显示Toast */
public void DisplayToast(String str) {
Toast toast = Toast.makeText(this, str, Toast.LENGTH_LONG);
// 设置toast显示的位置
toast.setGravity(Gravity.TOP, 0, 220);
// 显示该Toast
toast.show();
}
}

今天就先讲到这里,希望大家动手去练习,熟练使用它们。

源码已经上传到天圣达网站,大家可以去下载 http://www.bj-stl.com/android.html

[转载]周末浅说--未将对象引用设置到对象的实例(System.NullReferenceException)

mikel阅读(779)

[转载]周末浅说–未将对象引用设置到对象的实例(System.NullReferenceException) – 路过秋天 – 博客园.

System.NullReferenceException:未将对象引用设置到对象的实例,这是一个新鸟,中鸟,老鸟都避不开的错误。

下面基础的解释一下这错误:

1:本质上的错误:

object a;//a是Null对象
protected void Page_Load(object sender, EventArgs e)
{
a.ToString();//调用一个Null对象的方法
}

当然啦!结果就如下图了:

这么赤裸裸的写出这种代码,不太容易,通常更倾向于下面一种:

2:通常性的错误:

示例1:一个过滤某些字符的函数:

public static string FilterValue(string value)
{
string[] filterChar = new string[] { \’, ,, >, <, =, ;, \”, };
for (int i = 0; i < filterChar.Length; i++)
{
value
= value.Replace(filterChar[i], “”);
}
return value.Trim( );
}

这个函数比如容易看的出:如果value传进来为Null的时候,就等于Null.Replace被调用,就出现了上面的错误。

因此,通常的,在函数的首行,都会对value进行:if(!string.IsNullOrEmpty(value)) 一下。

示例2:再举一下通用性的调用错误,绑定,Eval(“字段”) ,这个方法比较常见,某些情况要转字符串比较,这里示例一下:

<%# Eval(字段).ToString()==1?Yes:No %>

当Eval(“字段”)为Null时,一个Null.ToString(),必然也会出现上面的错误,那什么情况出现?

1:字段的值为Null

2:空数据行,就是你表一行数据都没有,全是Null。

所以预防性的写法是:

<%# Convert.ToString(Eval(字段))==1?Yes:No %

好了,看到本文的不管懂的还是不懂的,现在都应该懂了,如果你非要说你不懂,我得赞扬你智商高,下面有智商介绍,别放过。

见到这异常:就是一个Null的对象调用了方法(属性或其它成员)变成Null.XXX引发的。

当然啦,出现这种异常的场景,那可是万万千,数也数不完,但本质是一样的。

个人观点认为,在三只鸟中发生此错误的原因各不同,基本如下:

新鸟:不知道这个错误,或见这错误的次数太少,所以代码基本防都不防,模仿式,大量的函数都潜伏这种错误杀手。

个人猜测:新鸟写的代码,都不加判断的原因可能:

其一:是他们不知这种情况,刚学习,经验不足,未有处理这种异常的经验。

其二:推测是他们高调的认为:多一个Null的判断,会使得性能下降,他们追求高性能,因此,基本上,不加。

中鸟:知道这个错误,只是考虑的不多,心不够细,人不够稳,写代码基本会加,但普遍不加。

中鸟比新鸟吃的虫,肯定多,所以出现这种情况,原因当然不一样了啦。

个人猜测:中鸟写的代码,出现Null引用的原因可能是:

其一:没有养成思维习惯,在加班的压力下,写个函数都是刷刷的就出来了,偶尔会加,普遍不加,加还是不加,等错误出来了再加。

其二:中鸟这时期处于高性能研发性时期,最喜欢的和别人讨论性能问题,特别是当for的次数达到百万级别时,当性能从0.03秒下降到0.01秒时,会为整整提高3倍的性能而欢乎,并认为这是一个重量级的发现,然后推荐推荐给后来者,并BS一些不这么写的新手或同级的鸟。
同理:一个函数加一个null判断,得上升到百万次的调用级别的高度考虑,如果这判断被调用百万次,那性能不是大大的损失?
如果加2个判断,那就是2*百万次的调用,那就是相当大的性能损失,这怎么可以接受的呢?
所以,能不加就不加,加不加,等错误出来了再加。
其三:太懒了,这个本人是这么理解的说:

大伙都知道,中鸟写代码,基本都属于面向对象型的了,那就是天天和对象搞在一块的了,每个对象都要搞来搞去,再多的精也伤不起!

好吧,一个函数传一个参数,给你加一个判断,代码也不多,不算大括号就两行。

可是中鸟基本上写的函数的参数,偏偏三四五六七八九十个,这下让人纠结了:

加吧,一想,工作量太大了,而且这性能感觉不高;

不加吧,好像也没什么问题,这么一想啊,眼前阔然开朗,好,加不加,错误出来了再加。

还有的,不仅是参数的判断要折腾,函数内部产生的对象,也要搞一搞,太多对象要考虑。
光靠精力与考虑,加点人之常情,所以大多数情况是发生在:加不加,错误出来了再加!

老鸟:对这错误太熟悉,心也够细,写代码潜意识会主动加防,但百密一疏,该来的还是会来,躲过初一,躲不过十五。

老鸟吃的虫就更多了,而且老鸟们身经百战之后,觉得系统稳定,才是幸福。

个人猜测:老鸟写的代码,出现Null引用的原因可能是:

其一:代码写多了,基本上都靠潜意识反应,就是说潜能发挥了,再白点就是习惯性思维。

所以基本上都不会怎么犯这错误,但是光靠潜意识,基本都能挡住,基本之外的,还得靠正常思维。

老鸟通常精力不太好,偶尔会走神,一走神,就漏了一个,再一走神,又漏了一个,再一走神,被神招唤了,太平间多了一位客人。

所以我写代码,尽量不走神,免的被招唤,但偶尔也会漏。

其二:是假老鸟,老鸟是装的,其实还是中鸟,硬要装,不过会装,说明智商高。

社会的法则表明,生存的越好的,装的程度越高,越会装,生活就越好,装到最高境界,那就是装孙子。

孙子是一名历史人物:会三十六计,装孙子的说明智商真的很高,没里绝对没有鄙视之意,因为三十六计有时候我也在学,只是智商一直上不去,所以境界一直上不去。

下面再补充一下,个人对中老鸟的看法,以下观点仅为作者扮演的个人的臆测观点,和作者本人无关:

中鸟何以追求性能?

臆测:因为他们通常只接触到系统的一部分,缺少整个系统体系的了解,所以他们希望在他们负责的那一个区域里,写出性能至上的代码,这能说有错吗?

没错,而且理论上就应该这么干!但是,稳定不足,如果能写出又稳定又高性能的代码,有多好呢!

重点还是讲老鸟:老鸟何以不太关注性能,而求稳定?

其实,老鸟并不是不关注性能,而是他关注的是:

一:稳定,这个很重要:

因为系统一上线:

首先:得对老板负责啊,你说是不是?

然后:如果这个产品是要给客户演示的,那得对客户负责啊,你说是不是?

再者:如果这个产品要上线运营,那得对访客负责啊,你说是不是?

所以,不管你系统怎么样,首先,保证稳定,至少给老板或客户或访客演示或操作的时候,你不能出错,至于慢点不慢点,那个好商量,好商量。

二:整体性能大于局部性能

I:这个就很明显了,你一个算法写的很好,可是其它选手数据库写的差,一访问,很慢,这怎么说的过去。

II:所以要保证整体访问性能差不多先,然后再进行局部优化,这多符合中国人当前的优化思维啊。

III:再说了,每个人局部性能都最大化了,一访问,还是慢,找不到着优化的地方,这可是要出事的:老板得出血买硬件了。

IV:还有,整体上加了缓存+静态化html后,你会发现,局域的最大优化代码,基本都派不上用场了,因为直接就是访问+返回,

至于您那最大化性能的逻辑代码,那是千年走一回了。

当然了,个人对此观点是很负责的,绝对没有任何轻视局部性能最大化的意思,相反还得鼓励大伙局部性能最大化,努力写出最优代码:

一来:这是每个码农往上走必经的阶段,跳过不是件好事。

二来:多让老板出下血,可以平衡下员工不满的心情:你让我加班,我就让你出血,多好呢。

重大说明:

本篇文章绝大多数观点为作者扮演的个人的臆测观点,和本人无关,本人认为,以上观点有些片面,可能与客观事实不符。

请各位看客看在周末的份上,少一份偏激,多一份激动,开X吧!

本视频到此为止,欢迎收看,下次再会,谢谢!

PS:最近顺路折腾了下 CYQ.Data V4.5离线帮助文档,很快发布,敬请关注。

[转载]Windows上搭个Nginx集群环境玩玩

mikel阅读(1097)

[转载]Windows上搭个Nginx集群环境玩玩 – sxwgf – 博客园.

话说nginx是一个非常NB的高性能Web和反向代理服务器,传说新浪、迅雷等大网站都在用。以前也就听大牛们讲讲,没什么太深刻的概念,今天终 于自己亲手操刀实践了一把,顺便把过程记录了下来分享给大家,这个很基础,就用轮询的方式来做一个负载均衡,最简单的配置了,今后再去深入了解它。

对了,不知道nginx是什么的同学就先自己去捣鼓一下,回头如果有兴趣可以再来看下去,给几个链接:

http://zh.wikipedia.org/zh/Nginx

http://baike.baidu.com/view/926025.htm

由于我linux实在是用不溜,所以就在windows搞搞了。

一、在windows上安装nginx

1、从这里下载nginx的windows版本

2、把压缩文件解压至c盘根目录,并将文件夹重命名成nginx

3、在conf目录下的nginx.conf文件中,指定一个不冲突的端口号,这里测试用8088,代码段如下:

server {
     listen       8088;
     server_name  localhost;
}

4、打开cmd命令行,运行如下命令:

>cd c:\nginx
>nginx

好了,试试吧,打开浏览器,输入127.0.0.1:8088,如果出现下图,那就说明nginx服务器已经成功安装并已经在跑了。

二、简单配置一下,搞个负载均衡集群测试环境

这里我就只有一台电脑,2G的内存,由于不做性能测试,就用虚拟机算了,虚拟机我用的是VMware,下面描述一下整个测试环境吧:

*物理主机一台,CPU:core2 T5750,2G内存,Windows 7操作系统,IP地址192.168.1.98,主机名sxwgf-PC,该主机用来当作Nginx代理服务器(P)和一台Web服务器(A)

*在物理主机中开一台虚拟主机,Windows Server 2003操作系统,IP地址192.168.1.99,主机名hzdk-vpc,该主机用来当作另一台Web服务器(B)

1、打开conf目录下的nginx.conf,具体配置代码如下:

worker_processes  1;
 
events {
    worker_connections  1024;
}
 
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
 
    upstream wgf.com{
    server 192.168.1.98;    #真实服务器A(sxwgf-PC)   
        server 192.168.1.99;    #真实服务器B(hzdk-vpc)
    }
 
    server {    #Nginx代理服务器
        listen       8088;
 
        server_name  localhost;
 
        location / {
            root   html;
            index  index.html index.htm;
        proxy_pass  http://wgf.com;
        proxy_redirect  default;
        }
 
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
 
    }
}

2、重启一下nginx吧,你可以在任务管理器中将原来的两个nginx进程结束然后按前面安装时的方法启动nginx,也可以直接输入命令:nginx -s reload来重启

3、准备两个完全一样的ASP.NET测试网站程序,分别放在主机A和虚拟主机B的IIS中,输入对应的ip地址试一下吧:

输入192.168.1.98

输入192.168.1.99

最后我们再来访问一下我们的nginx代理服务器,看看他能不能让我们访问到真实的服务器A和B,访问结果是每刷新一次就在A和B之间切换,好像我们在轮次访问A和B一样,但我们表面上都是访问的代理服务器127.0.0.1:8088,以下是截图:

刷新一次后:

这样就起到了简单的轮询访问的效果,一定程度上起到了负载分流的作用,当然这个是最简单,更高级的用法正在研究中。。。谢谢阅读!

[转载]vs 文档注释 文档注释模板设置

mikel阅读(1203)

[转载]vs 文档注释 文档注释模板设置 – 德明 – 博客园.

vs中的///文档注释类似java中/** */文档注释。能自动的生成帮助文档。

如果我想在每次创建文件时,自动生成文档注释(注意是自动生成文档注释而不是帮助文档),如下面的代码,需要设置VS的模板,新创建的cs类文件会根据模板的样子进行生成。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MODEL
{
///
/// FileName: Class1.cs
/// CLRVersion: 2.0.50727.3053
/// Author: Ming
/// Corporation:
/// Description:
/// DateTime: 2011-7-23 21:32:54
///
class Class1
{
}
}

常用的VS文件模板有3个,分别是Class.zip、Interface.zip、From.zip.

我以Class.zip模板设置为例,模板在vs2008下的路径

D:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\ItemTemplatesCache\CSharp\Code\2052

双击打开Class.zip直接编辑Class.cs,不用解压缩,编辑完保存。模板代码设置如下:

   /// <summary>
    /// FileName: $safeitemrootname$.cs
    /// CLRVersion: $clrversion$
    /// Author: Ming
    /// Corporation: 
    /// Description: 
    /// DateTime: $time$
    /// </summary>
    class $safeitemrootname$
    {
    }

这里$var$ 都是系统的变量,模板参数是要区分大小写的,大家需要注意。系统提供的可用的参数如下:

参数 说明
clrversion
公共语言运行库 (CLR) 的当前版本。

GUID [1-10]
用于替换项目文件中的项目 GUID 的 GUID。最多可以指定 10 个唯一的 GUID(例如,guid1))。

itemname
用户在添加新项对话框中提供的名称。

machinename
当前的计算机名称(例如,Computer01)。

projectname
用户在新建项目对话框中提供的名称。

registeredorganization
HKLM\Software\Microsoft\Windows NT\CurrentVersion\RegisteredOrganization 中的注册表项值。

rootnamespace
当前项目的根命名空间。此参数用于替换正向项目中添加的项中的命名空间。

safeitemname
用户在“添加新项”对话框中提供的名称,名称中移除了所有不安全的字符和空格。

safeprojectname
用户在“新建项目”对话框中提供的名称,名称中移除了所有不安全的字符和空格。

time
以 DD/MM/YYYY 00:00:00 格式表示的当前时间。

userdomain
当前的用户域。

username
当前的用户名。

year
以 YYYY 格式表示的当前年份。

保存并关闭,完成模板设置,会发现新创建的类文件如您所愿。

其他vs版本的设置步骤相同。在vs根目录下搜索Class.zip等模板文件的物理路径

ItemTemplates与ItemTemplatesCache的区别在于,如果您设置了ItemTemplates下的模板,需要在VS命令行中运行devenv /setup 命令 ,以Itemtemplates模板生成ItemTemplatesCache的模板,也就是说ItemTemplatesCache模板的设置会被原始的Itemtemplates模板还原。所以最好不要轻易改变Itemtemplates模板下的内容(他不能还原)。

Web下的Class.zip设置用于对web网站下的类文件起作用。

[转载]Android开发教程 --- 葵花宝典第三层 控件之 Button CheckBox EditText TextView

mikel阅读(938)

[转载]Android开发教程 — 葵花宝典第三层 控件之 Button CheckBox EditText TextView – Jason_CC – 博客园.

Hi 大家好!

今天开始,我将陆续编写Android UI中的常用控件,来帮助大家学习这些控件。

照例,上笑话。。。

A先生发现妻子的手机上经常有一则陌生人的短信,而且每次短信的内容都是一样的:“赵兄托你帮我办点事。”一天晚上十点半,A先生一举将出轨的妻子和那个正在苟合的男人擒拿后,大骂:TMD,你以为那短信我看不懂?倒过来读就 是“十点半我帮你脱胸罩”! clip_image002

这节主要讲4个控件,分别是Button CheckBox EditText TextView

这4个控件将是使用频率很高的控件,也是比较简单的控件。

我在这里已经编写好了每一个控件,以及注释,来方便大家熟悉。每一个控件都是一个活动(窗体),如下图

将程序运行起来后,默认显示的是ButtonActivity活动,效果如下

1 Button

当程序运行起来,默认就是Button控件的页面,大家也看到了窗体中摆放了很多的按钮,那么如何去定义一个Button呢?

思路是这样的:先去创建一个布局文件,然后在布局文件中添加这个窗体所需的控件,然后在Activity中绑定这个布局文件,在Activity中也能通过代码的方式,修改控件属性,绑定事件等。。。

有了这样的思路我们就开始干活。

1 创建一个布局文件,在项目的 res文件夹 –> layout文件夹

右键 新建-> 文件

在弹出的对话框中的文件名后去填写这个文件的名称,我们取名叫做

button.xml

或者也可以这样创建

注意,选择其他选项

注意:创建名称时,不要使用特殊字符和大写字母。否则你将无法正确创建出布局文件。。

当我们创建成功后,在双击打开XML文件 然后切换到代码视图

然后在LinearLayout中间添加一个Button标签,如下

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout
xmlns:Android=”http://schemas.android.com/apk/res/android”
android:layout_width=”match_parent”
android:layout_height=”match_parent”>
<Button android:id=”@+id/btn1″

android:layout_width=”fill_parent”
android:layout_height=”wrap_content”

android:text=”@string/btnck” />
</LinearLayout>

颜色代表的含义:

红色: 代表你所创建出的控件是什么

蓝色: 为所创建出来的控件赋一个ID,最好是一个唯一的名字,这个ID将会在gen文件夹下的R.java中的Class ID类中生成一个int 类型的常量,至于有什么用处,如果做过编程,都知道我们要在后台获取这些控件,来控制它们,修改属性啊,获取用户的操作等。后面将会说道在代码中如果使 用。

紫色: 代表这个控件的宽度和高度。

fill_parent :代表此控件将铺满父类定义的宽度(如果父类定义的宽度也是fill_parent ,那么代表父类的宽高,为整个屏幕大小),那么这个控件的宽度将铺满屏幕。

match_parent:和上边的fill_parent 一样,都是铺满,区别在于match_parent属性是Android2.2及以上的版本中才会有。

wrap_content:代表自适应高度,即:内容有多高,那么它就显示多高。

黄色: 代表你将在控件中显示什么文本。这里我们使用的是MVC模式,即在string.xml中定义好,然后在这里应用。

到这里第一步完成,接下来就是在Activity中去引用这个布局文件。

通过setContentView方法就可以将我们刚才定义的布局文件和这个窗体绑定上,然后就可以直接运行。

运行出来后,控件能正常显示,但是没有任何功能,这显然也没有太多的意义,下面就是通过代码来控制控件及绑定事件的操作。

还记得刚才我们在XML中设置的那个ID吗?

这里,通过  btn1 =(Button)findViewById(R.id.btn1);方式,就可以将刚才定义的那个Button控件获取到,并赋给btn1对象。btn1是一个Button对象。

通过btn1对象就可以给这个按钮设置一些外观属性,如上图。

绑定事件

这段代码首先使用了setOnClickListener方法,并使用了一个匿名内部类来实现一个Button的单击事件。里面的Intent 以及startActivity方法,在我之前的教程中都有介绍,如果大家遗忘了可以在去看看。

到这里,我们的Button就介绍到这里,Button主要就是获取用户的点击,然后对应的在onClick里做你需要的处理。

2 CheckBox

先来看看CheckBox张啥样,以及可以干什么,如图

是不是和我们的HTML中的checkbox一样?是的,其实就是一个多选按钮,操作还是比较简单,直接贴代码了

也是一样,这里我创建了一个checkbox.xml布局文件,以及一个叫CheckBoxActivity.java的Activity

然后是CheckBoxActivity.java,我先定义了一些全局变量,你需要在窗体中用到什么类型的控件,就先去声明什么类型的控件对象,然后通过findViewById方法获取它们,然后再操作这些控件对象。如下图

首先,将布局XML与窗体绑定,然后再逐一获取控件

可以和上边所讲的Button一样,设置外观属性或者绑定事件,我在这里直接为CheckBox绑定了选项更改事件监听器

当复选框的选中状态发生改变时将会触发onCheckedChanged函数,通过checkBox1.isChecked()方法就能获取到此复选框现在的状态 true为选中状态,false为未选中状态。

3 EditText

编辑框操作也是比较简单,直接贴代码

运行效果图

4 TextView 主要用来做提示的文本

同上,这里不再赘述

希望我的教程,能给大家一点点帮助,也希望大家能给出我的不足和建议。来帮助我更好的去做教程,谢谢大家!

源代码已经上传到天圣达网站,大家可以去下载:

http://www.bj-stl.com/android.html

[转载]XPath语法 在C#中使用XPath示例

mikel阅读(1254)

[转载]XPath语法 在C#中使用XPath示例 – 玉开 – 博客园.

XPath可以快速定位到Xml中的节点或者属性。XPath语法很简单,但是强大够用,它也是使用xslt的基础知识。

示例Xml:

<!--?xml version="1.0" encoding="utf-8" ?-->

100     this is a black cat

80     this is a white cat

80     this is a yellow cat

100     this is a black dog

80     this is a white dog

80     this is a yellow dog

XPath的语法:

1. XPath中的符号

符号

说明

示例

示例说明

/

表示从根节点开始选择

/pets

选择根节点pets

表示节点和子节点之间的间隔符

/pets/dog

选择pets节点下的dog节点

//xx

表示从整个xml文档中查找,而不考虑当前节点位置

//price

选择文档中所有的price节点

.

单个英文半角句点表示选择当前节点

/pets/.

选择pets节点

..

双点,表示选择父节点

/pets/dog[0]/..

表示pets节点,也就是第一个dog节点的父节点

@xx

表示选择属性

//dog/@color

表示选择所有dog节点的color属性集合

[…]

中括号表示选择条件,括号内为条件

//dog[@color=’white’]

所有colorwhitedog节点

//dog[/price<100]

所有price字节点值小于100dog节点

中括号内数字为节点索引,类似C#等语言中的数组,数组下标是从1开始的

//dog[1]

1dog节点

//dog[last()]

最后一个dog节点,last()xPath内置函数

|

单竖杠表示合并节点结合

//dog[@color=’white’] | //cat[@color=’white’]

color属性为whitedog节点和color属性为whitecat节点

*

星号表示任何名字的节点或者属性

//dog/*

表示dog节点的所有子节点

//dog/@*

表示dog节点的所有属性节点

2. XPath数学运算符
+ 加号表示加
表示数字相减
* 表示乘以
div 表示除以,这里数学上的除号/已经被用作节点之间分隔符了
mod 表示取余
3. XPath逻辑运算符
= 等于,相当于C#中的 ==
!= 不等于
> 大于
>= 大于等于
< 小于
<= 小于等于
and 并且 与关系
or 或者 或关系
4. XPath Axes 从字面翻译这个是XPath轴的意思,但根据我的理解这个翻译成XPath节点关系运算关键字更合适,就是一组关键字加上::双冒号表示和当前节点有关系的一个或者一组节点.
使用语法: axisname::nodetest[predicate] 即轴名字::节点名字[取节点条件]
具体说明如下:

关键字

说明

示例

示例说明

ancestor

当前节点的父祖节点

ancestor::pig

当前节点的祖先节点中的pig节点

ancestor-or-self

当前节点以及其父祖节点

ancestor::pig

attribute

当前节点的所有属性

attribute::weight

相当于@weightattribute::@是等价的

child

当前节点的所有字节点

child::*[name()!=’price’]

选择名字不是price的子节点

descendant

子孙节点

descendant::*[@*]

有属性的子孙节点

descendant-or-self

子孙节点以及当前节点

descendant-or-self::*

following

Xml文档中当前节点之后的所有节点

following::*

following-sibling

当前节点的同父弟弟节点

following-sibling::

preceding

Xml文档中当前节点之前的所有节点

preceding::*

namespace

选取当前节点的所有命名空间节点

namespace::*

parent

当前节点的父节点

parent::

相当于双点..

preceding-sibling

当前节点之后的同父兄节点

preceding-sibling::*

self

当前节点

self::*

相当于单点.


5. 常用的XPath函数介绍:
在XPath表达式中常用的函数有下面两个:
position() 表示节点的序号例如 //cat[position() = 2] 表示取序号为2的dog节点
last() 表示取最后一个节点 //cat[last()]
name() 表示当前节点名字 /pets/*[name() != ‘pig’] 表示/pets下名字不是pig的子节点
XPath的函数还有很多,包括字符串函数,数字函数和时间函数等,具体可以参考w3的网站
以上是XPath的语法,下面我们看下如何在.Net中使用XPath
在.Net中可以通过XPathDocument或者XmlDocument类使用XPath。XPathDocument是只读的方式定位Xml节点或者属性文本等,而XmlDocument则是可读写的。
如下代码示例展示了如何使用XPathDocument和XmlDocument
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.XPath;
using System.Xml;

namespace UseXPathDotNet
{
class Program
{
static void Main(string[] args)
{
UseXPathWithXPathDocument();

UseXPathWithXmlDocument();

Console.Read();
}

static void UseXPathWithXmlDocument()
{
XmlDocument doc = new XmlDocument();
doc.Load("http://www.cnblogs.com/yukaizhao/rss");
//使用xPath选择需要的节点
XmlNodeList nodes = doc.SelectNodes("/rss/channel/item[position()&lt;=10]");
foreach (XmlNode item in nodes)
{
string title = item.SelectSingleNode("title").InnerText;
string url = item.SelectSingleNode("link").InnerText;
Console.WriteLine("{0} = {1}", title, url);
}
}

static void UseXPathWithXPathDocument()
{
XPathDocument doc = new XPathDocument("http://www.cnblogs.com/yukaizhao/rss");
XPathNavigator xPathNav = doc.CreateNavigator();
//使用xPath取rss中最新的10条随笔
XPathNodeIterator nodeIterator = xPathNav.Select("/rss/channel/item[position()&lt;=10]");
while (nodeIterator.MoveNext())
{
XPathNavigator itemNav = nodeIterator.Current;
string title = itemNav.SelectSingleNode("title").Value;
string url = itemNav.SelectSingleNode("link").Value;
Console.WriteLine("{0} = {1}",title,url);
}

}
}
}

XPath使用示例,请看下面的代码注释

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;

namespace UseXPath1
{
class Program
{
static void Main(string[] args)
{
string xml = @"<!--?xml version=""1.0"" encoding=""utf-8"" ?-->

100     this is a black cat

80     this is a white cat

110     this is a yellow cat

114     this is a black dog

80     this is a white dog

80     this is a yellow dog

8000     this is a white pig
";

using (StringReader rdr = new StringReader(xml))
{
XmlDocument doc = new XmlDocument();
doc.Load(rdr);

//取所有pets节点下的dog字节点
XmlNodeList nodeListAllDog = doc.SelectNodes("/pets/dog");

//所有的price节点
XmlNodeList allPriceNodes = doc.SelectNodes("//price");

//取最后一个price节点
XmlNode lastPriceNode = doc.SelectSingleNode("//price[last()]");

//用双点号取price节点的父节点
XmlNode lastPriceParentNode = lastPriceNode.SelectSingleNode("..");

//选择weight*count=40的所有动物,使用通配符*
XmlNodeList nodeList = doc.SelectNodes("/pets/*[@weight*@count=40]");

//选择除了pig之外的所有动物,使用name()函数返回节点名字
XmlNodeList animalsExceptPigNodes = doc.SelectNodes("/pets/*[name() != 'pig']");

//选择价格大于100而不是pig的动物
XmlNodeList priceGreaterThan100s = doc.SelectNodes("/pets/*[price div @weight &gt;10 and name() != 'pig']");
foreach (XmlNode item in priceGreaterThan100s)
{
Console.WriteLine(item.OuterXml);
}

//选择第二个dog节点
XmlNode theSecondDogNode = doc.SelectSingleNode("//dog[position() = 2]");

//使用xpath ,axes 的 parent 取父节点
XmlNode parentNode = theSecondDogNode.SelectSingleNode("parent::*");

//使用xPath选择第二个dog节点前面的所有dog节点
XmlNodeList dogPresibling = theSecondDogNode.SelectNodes("preceding::dog");

//取文档的所有子孙节点price
XmlNodeList childrenNodes = doc.SelectNodes("descendant::price");
}

Console.Read();
}
}
}

C#处理Xml的相关随笔:

7.通过Xslt转化Xml格式

请尊重作者的劳动,转载请保留链接 玉开的技术博客

[转载]相似图片搜索的原理

mikel阅读(992)

[转载]相似图片搜索的原理 – 阮一峰的网络日志.

作者: 阮一峰

日期: 2011年7月21日

上个月,Google把“相似图片搜索”正式放上了首页。

你可以用一张图片,搜索互联网上所有与它相似的图片。点击搜索框中照相机的图标。

一个对话框会出现。

你输入网片的网址,或者直接上传图片,Google就会找出与其相似的图片。下面这张图片是美国女演员Alyson Hannigan。

上传后,Google返回如下结果:

类似的”相似图片搜索引擎”还有不少,TinEye甚至可以找出照片的拍摄背景。

==========================================================

这种技术的原理是什么?计算机怎么知道两张图片相似呢?

根据Neal Krawetz博士的解释,原理非常简单易懂。我们可以用一个快速算法,就达到基本的效果。

这里的关键技术叫做”感知哈希算法”(Perceptual hash algorithm),它的作用是对每张图片生成一个”指纹”(fingerprint)字符串,然后比较不同图片的指纹。结果越接近,就说明图片越相似。

下面是一个最简单的实现:

第一步,缩小尺寸。

将图片缩小到8×8的尺寸,总共64个像素。这一步的作用是去除图片的细节,只保留结构、明暗等基本信息,摒弃不同尺寸、比例带来的图片差异。

第二步,简化色彩。

将缩小后的图片,转为64级灰度。也就是说,所有像素点总共只有64种颜色。

第三步,计算平均值。

计算所有64个像素的灰度平均值。

第四步,比较像素的灰度。

将每个像素的灰度,与平均值进行比较。大于或等于平均值,记为1;小于平均值,记为0。

第五步,计算哈希值。

将上一步的比较结果,组合在一起,就构成了一个64位的整数,这就是这张图片的指纹。组合的次序并不重要,只要保证所有图片都采用同样次序就行了。

= = 8f373714acfcf4d0

得到指纹以后,就可以对比不同的图片,看看64位中有多少位是不一样的。在理论上,这等同于计算“汉明距离”(Hamming distance)。如果不相同的数据位不超过5,就说明两张图片很相似;如果大于10,就说明这是两张不同的图片。

具体的代码实现,可以参见Wote用python语言写的imgHash.py。代码很短,只有53行。使用的时候,第一个参数是基准图片,第二个参数是用来比较的其他图片所在的目录,返回结果是两张图片之间不相同的数据位数量(汉明距离)。

这种算法的优点是简单快速,不受图片大小缩放的影响,缺点是图片的内容不能变更。如果在图片上加几个文字,它就认不出来了。所以,它的最佳用途是根据缩略图,找出原图。

实际应用中,往往采用更强大的pHash算法和SIFT算法,它们能够识别图片的变形。只要变形程度不超过25%,它们就能匹配原图。这些算法虽然更复杂,但是原理与上面的简便算法是一样的,就是先将图片转化成Hash字符串,然后再进行比较。

P.S.

我在网站首页加上了一些我喜欢的摄影作品,欢迎参观。

(完)

[转载]PC通过android手机的3G网络上网

mikel阅读(969)

[转载]PC通过android手机的3G网络上网 – 蓝之风 – 博客园.

经常在出差,旅游过程中如果没有无线网卡,而我们有需要通过网络处理一些工作,比如收发邮件等等。虽然手机可以完成我们的工作,但是毕竟屏幕小,键盘操作不方便,严重影响工作效率,在这种情况下如果本本能通过手机上网,那就是一大进步,也大大提高工作效率,减少操作痛苦。

在网上找了很多方法,但是我觉得这个方法是最简单的介绍给大家,这里需要两款软件一个手机端的安装包(下载),一个pc端的安装包(下载),使用非常简单,分别安装在手机和pc上然后用数据线连接,分别启动软件,pc上会创建一个虚拟网卡,在桌面右下角的状态栏有个小图标,点右键“connection”就可以连上网络了,接下来你就可以畅游网络了

[转载]Flex Spark皮肤定制

mikel阅读(1544)

[转载]Flex Spark皮肤定制 – twaver – 博客园.

Flex3到Flex4,增加了Spark组件,这是Flex的一次重要升级,基本上组件全部重写了一套,为了保持向下兼容,出现了同一组件两套实现并存的现象,虽然说Spark组件中也可嵌入MX组件,但实际使用常会遇到些小麻烦,例如mx:Tree滚动条异常,透明背景无法监听鼠标事件等等,如果你使用定制的组件,写法稍有不规范,就会出现Spark下显示异常,比如之前定制的TWaver圆角文本输入框就是如此,不得不在Spark下重新实现。

Spark与MX组件的区别

Spark最大的目的或许是方便Adobe兜售它的Flash Catalyst,当然这是个玩笑,Spark组件更加轻量,更易扩展。所有的Flex组件都从UIComponent继承,Spark组件也是如此,只 不过它多了一层包装,从SkinnableComponent继承。MX中每个组件对应一个类,在Spark体系中,每个组件对应两个类,一个 Component类,一个Skin类,例如按钮组件对应:spark.components.Button和 spark.skins.spark.ButtonSkin,这种设计实现了组件行为逻辑与视图呈现的分离,就像将程序员和美工的工作分开一样,这也是 MVC思想的产物。
Flex 3与Flex4的区别详见:
Differences between Flex 3 and Flex 4
what is difference in halo and spark in Flex3 and Flex4

Spark组件外观定制

前面提到Flash Catalyst,这就是Adobe提供的组件外观可视化编辑工具,这个工具主要针对美工、设计师,对于习惯于写代码的程序员们也可以使用Flash Builder 4+来定制组件。
回到实际问题,之前我定制的圆角文本输入框在Spark框架下出现了问题,我决定将其改造,使用定制组件Skin的方式实现圆角文本输入框。

定制圆角文本输入框

需求与分析

我的需求很简单,文本框带圆角,其内放个图标,如同mac osx的搜索框。实现思路也很清晰,给矩形增加圆角,再多放个icon,定好位置,做好布局……

定义组件类

开始动手,按Spark组件定制的步骤,先定义组件类,再定义外观类。
组件类描述组件的行为和属性,这里我们定义一个 CustomTextInput.as,继承于spark.components.TextInput,组件行为不需要特别定义,这里只是增加两个样 式:icon和radius,分别表示图标和圆角半径,而具体的呈现将在Skin类中实现。

package component{
import skin.CustomTextInputSkin;
import spark.components.TextInput;

[Style(name="icon", inherit="no", type="Object")]
[Style(name="radius", inherit="true", type="Number")]

public class CustomTextInput extends TextInput{
[Embed(source="/images/search.png")]
private const defaultIcon:Class;

public function CustomTextInput(){
super();
this.setStyle('icon', defaultIcon);
this.setStyle('radius', 10);
this.setStyle("skinClass", CustomTextInputSkin);
}
}
}

定义外观类外观类描述组件的呈现,这里我们按Flash Builder提示创建MXML Skin,选择名称为CustomTextInputSkin,设置Host component为component.CustomTextInput, 完成向导,自动生成文件CustomTextInputSkin.mxml



生成的文件实际上是默认TextInputSkin的复本,找到下面的片段:

<!-- border -->
<!--- @private -->

<!--- @private -->

<!-- fill -->
<!--- Defines the appearance of the TextInput component's background. -->

<!--- @private Defines the background fill color. -->

<!-- shadow -->
<!--- @private -->

<!-- text -->
<!--- @copy spark.components.supportClasses.SkinnableTextBase#textDisplay -->

其中边框,填充,阴影,文本框都有对应的块,分别对边框、填充、阴影添加圆角,并在文本块增加了图片组件,修改如下:

<!-- border -->
<!--- @private -->

<!--- @private -->

<!-- fill -->
<!--- Defines the appearance of the TextInput component's background. -->

<!--- @private Defines the background fill color. -->

<!-- shadow -->
<!--- @private -->

<!-- icon -->

<!-- text -->
<!--- @copy spark.components.supportClasses.SkinnableTextBase#textDisplay -->

使用运行测试定制的组件,代码如下:

<!--?xml version="1.0" encoding="utf-8"?-->







运行界面

代码下载

CustomComponentSkinSource.zip

注意

此代码使用的Flex SDK 4.5编译,需要在Flash Player 10.2+运行,当然你也可以稍微改造一下代码,使其兼容Flex SDK 4.0,如图标改s:Image为mx:Image:

1 <!-- icon -->
2 <mx:Image id="icon" x="0" y="0" source="{hostComponent.getStyle('icon')}" verticalAlign="middle" height="100%"/>

参考文档

http://www.unitedmindset.com/jonbcampos/2010/03/21/new-spark-skinning-workflow/
http://www.slideshare.net/danorlando/creating-custom-spark-components-in-flex-4
http://www.adobe.com/devnet/flex/videotraining/exercises/ex5_06.html