[转载]Delphi之使用资源文件(Using Resource Files)

mikel阅读(1110)

[转载]Delphi之使用资源文件(Using Resource Files) – 瓢虫Monster – 博客园.

New Term

每个Windows应用程序都使用资源。资源(Resources)不是可执行代码,但它属于程序的一部分元素。

典型的Windows程序的资源有:

  • 加速器(Accelerators)
  • 位图(Bitmaps)
  • 光标(Cursors)
  • 对话框(Dialog boxes)
  • 图标(Icons)
  • 菜单(Menus)
  • 数据表(Data tables)
  • 字串表(String tables)
  • 版本信息(Version information)
  • 用户定义的专用资源(User-defined specialty resources)如声音和视频文件

Note

用Project Options对话框的Version Info页面可轻松地将版本信息加到Delphi工程中。如下图:

0246

资源一般包括在扩展名为.rc的资源脚本文件中(resource script file),资源文件就是文本文件。资源文件用资源编译器编译,并在链接时加到应用程序的.exe文件中。

通常大家认为资源要加到可执行文件中,但是有些资源,如位图、字符串表、波形文件,既可以放到外部文件中(.bmp、.txt、.wav),也可加到.exe文件并包含到应用程序文件中。

把资源放到.exe文件中有两条主要优点:

  • 存取资源的速度更快。因为在一个可执行文件中查找资源花的事件比从磁盘文件中装入资源花的时间要少。
  • 程序和资源可一起包含到单个单元(即.exe文件)中,而不需要一大堆的支持文件。

它的不足之处是:会使.exe文件稍稍增大。其大小不会比外部资源文件加可执行文件大。但是增加大小会使加载该程序的时间加长。

是把资源存为外部资源文件,还是把资源放到.exe文件中,这得由编程人员自己定。但要记住的是:这两种方式用哪一种都行(甚至可以在同一个程序中使用两种方式)。

Delphi中的资源(Resources in Delphi)

传统的Windows程序几乎都至少包含一个对话框和一个图标。但是,Delphi应用程序有所不同。首先,Delphi应用程序中没有真正意义上的对话框,实质上也就是没有对话框资源(Delphi中存储的窗体是资源,但它们是RCDATA资源,而不是对话框资源)。

Delphi 应用程序有传统意义的图标资源。创建应用程序时,Delphi负责创建图标资源文件。类似地,在为Speedbutton、Image组件或BitBtn 组件选择位图时,Delphi将所选位图文件包含到窗体资源中(作为窗体资源的一部分)。在建立应用程序时,窗体和它的全部资源一起包括到程序文件中。这 些都是自动处理的。

有时需要在通常的Delphi处理中以外使用资源。例如,要制作动画,必须有一系列的位图,将它们装载进来作为可以最快速度执行的资源。在这种情况下,就需要知道如何把资源捆绑到Delphi应用程序中。

把 资源文件捆绑到可执行文件中是件非常容易的事,实际创建资源却要困难的多。如果有一个好的资源编辑器,创建诸如位图、图标和光标之类的基本资源并不困难, 但创建具有专业化品质的3D位图和图标却是一项艺术性的工作。我们肯定遇到过很多不错的程序,但它们的位图按钮实在难看。我们可以利用Delphi自带的 Image Editor创建位图、图标和光标。

如果要创建字符串资源、用户数据资源、波形文件资源或其他专用资源,则可能需要第三方资源编辑器。

Note

如 果手头有老版本的Borland Pascal,可使用其中的Resource Workshop编辑器编辑专用资源。创建好资源后,会形成一个.rc文件,Delphi中带有Borland Resource Compiler,用Borland Resource Compiler(BRCC32.EXE)将它编译成.res文件。从技术上讲,可以用任何一种文本编辑器创建.rc文件并用资源编译器编译它,但使用资 源编辑器创建资源要容易的多。

现在在推荐一个款比较不错的第三方资源编辑器Resource Builder,该软件界面简洁,使用简单,大家可以百度一下。

编译资源文件(Compiling Resource Files)

资源文件创建好后,要用资源编译器来编译它。编译资源文件的方法有两种:

  • 从命令行手工编译资源文件。
  • 添加一个批处理文件工程到工程组。

用其中任意一个方法,编译完后都得到一个.res文件,将它链接到应用程序中。

1、 从命令行编译(Compiling from the Command Line)

从命令行编译资源文件,只需打开Windows中的命令提示框,并输入一行与下面相似的命令:

brcc32 jjres.rc

0247

当然,必须保证当前系统目录为Delphi安装目录的Bin目录下,如果不是,则必须输入BRCC32.EXE的完整路径。这个资源编译器速度非常快,甚至不等察觉,它就把资源脚本文件编译完成了。

2、 使用批处理文件工程(Using a Batch File Project)

添加一个批处理文件到工程组,与从命令行编译一样简单,并且还有一个好处:保证资源文件总是最新的。要搞清楚批处理文件如何工作,可执行下面的步骤:

(1)创建一个新的应用程序;

(2)选择【View | Project Manager】打开“Project Manager”工程管理器,如下图:

0248

(3)点击“Project Manager”工具栏上的“Add New Project”按钮,显示Object Repository对象库,如下:

0249

(4)双击Batch File图标来创建文件工程。将该批处理文件工程以Project2的名称添加到“Project Manager”中,如下:

0250

(5)用鼠标右键点击批处理文件节点并选择Save,将文件保存为test.bat

0251

(6)用鼠标右键再次点击批处理文件节点并选择【Edit/Options】,会弹出“Batch File Options”对话框;

0252

(7)在Command文本框内输入下列正文:

del myfile.res

brcc32 myfile.rc

(8)点击OK关闭“Batch File Options”对话框。

这 个练习锁做的就是创建一个批处理文件,当编译工程组时,它就会执行。第(7)步输入的批处理文件命令删除一个名为myfile.res文件,并调用 Delphi资源编译器编译myfile.rc文件。用资源编译器编译myfile.rc文件会生成一个名为myfile.res的文件。

工 程组中的下一个工程可能要使用myfile.res。呵呵,那为什么要先删除myfile.res文件呢?这是因为,删除该文件后,就能知道资源编译器是 重新建立了这个文件。如果资源编译器创建资源失败,则任何要使用这个资源文件的工程都将编译失败,并报告编译错误,提示编程人员,建立资源文件出错。

把资源文件链接到你的可执行文件中(Linking Resource Files to Your Executable)

编译好资源文件后,要把编译后的资源文件链接到程序的可执行文件中,可使用$R编译器指令。例如,要链接包含在myfile.res文件中的二进制资源,可在主窗体单元的开头处插入下面一行:

1
{$R myfile.res}

就这么简单!只要指定的文件存在,Delphi就会在链接时把这个编译过的资源添加到可执行文件中。

使用资源的样本程序(A Sample Program Using Resources)

下面的清单中,列出了Jumping Jack的程序的主窗体单元。这个程序显示一个带声音效果的简单动画。主窗体上有两个按钮:一个Image组件和一个Label组件。Jumping Jack程序说说明了资源在Delphi应用程序中的使用。它特别说明了如何加载以资源文件形式存储的位图,如何加载并显示字符串资源,以及如何播放资源 文件中的波形音频。清单后面还列出了部分资源文件。先看看清单,然后再分析程序。

JJMain.pas清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
unit JmpJackU;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, MMSystem;
{$R JJRES.RES}
const
IDS_UP = 101;
IDS_DOWN = 102;
type
TMainForm = class(TForm)
Image: TImage;
Label1: TLabel;
Start: TButton;
Stop: TButton;
procedure FormCreate(Sender: TObject);
procedure StartClick(Sender: TObject);
procedure StopClick(Sender: TObject);
private
{ Private declarations }
Done: Boolean;
procedure DrawImage(var Name: string);
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.DrawImage(var Name: string);
begin
{ 从资源文件中读取位图,通过资源名称}
Image.Picture.Bitmap.LoadFromResourceName(HInstance, Name);
{ 让Image有机会显示位图}
Application.ProcessMessages;
{ 延缓,让动画变慢}
Sleep(20);
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
Image.Picture.Bitmap.LoadFromResourceName(HInstance, 'ID_BITMAP1');
end;
procedure TMainForm.StartClick(Sender: TObject);
var
s: string;
ResName: string;
i: Integer;
Buff: array[0..9] of Char;
begin
s := 'ID_BITMAP';
Done := False;
while not Done do
begin
for i := 1 to 5 do
begin
ResName := s + IntToStr(i);
DrawImage(ResName);
end;
LoadString(HInstance, IDS_UP, Buff, SizeOf(Buff));
Label1.Caption := Buff;
Label1.Refresh;
PlaySound('ID_WAVEUP', HInstance, SND_ASYNC or SND_RESOURCE);
Sleep(200);
for i := 5 downto 1 do
begin
ResName := s + IntToStr(i);
DrawImage(ResName);
end;
PlaySound('ID_WAVEDOWN', HInstance, SND_ASYNC or SND_RESOURCE);
LoadString(HInstance, IDS_DOWN, Buff, SizeOf(Buff));
label1.Caption := Buff;
Label1.Refresh;
Sleep(200);
end;
end;
procedure TMainForm.StopClick(Sender: TObject);
begin
{ 当“Stop”按钮按下时,告诉循环停止}
Done := True;
end;
end.

JJRec.rc清单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
STRINGTABLE
BEGIN
101, "Up"
102, "Down"
END
ID_WAVEUP WAVE "up.wav"
ID_WAVEDOWN WAVE "down.wav"
ID_BITMAP1 BITMAP
MOVEABLE PURE LOADONCALL DISCARDABLE
LANGUAGE LANG_NEUTRAL, 0
BEGIN
'42 4D 76 02 00 00 00 00 00 00 76 00 00 00 28 00 '
'00 00 20 00 00 00 20 00 00 00 01 00 04 00 00 00 '
'00 00 00 02 00 00 00 00 00 00 00 00 00 00 10 00 '
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80 '
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80 '
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF '
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF '
'00 00 FF FF FF 00 BB BB BB BB BB BB BB BB BB BB '
'BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB BB '
'BB BB BB BB BB BB BB BB BB BB BB BB BB B0 B0 BB '
'BB BB BB BB BB BB BB BB BB BB BB BB BB B0 B0 BB '
此处省略了部分内容,详细内容请查看示例代码

分析:

主窗体类声明中声明了一个Done的布尔型字段,Done用于确定何时终止动画。DrawImage方法用于在Image组件中显示位图。

注意:上列代码中,使用了两个Windows API函数来加载字符串和波形文件资源。在StartClick方法中,LoadString函数加载一个字符串到到一个字符数组缓冲区内。然后将该字符数组分配给窗体上的Label组件的Caption属性。

PlaySound函数用于播放波形文件资源。PlaySound函数用SND_ASYNC标志通知Windows开始播放音频并立即将控制返回给 程序,这使得在播放音频的同时,动画能继续下去。SND_RESOURCE标志通知Windows,声音是一个资源,而不是磁盘上的一个文件。 LoadString和PlaySound函数都使用HInstance全局变量通知Windows到可执行文件中去查找资源。装入位图资源,使用VCL 方法LoadFromResourceName。

而资源文件JJRec.rc中的前5行说明字符串在资源脚本文件中的格式;使用文本编辑器创建字符串表非常容易。接下去是为两个波形文件创建各自的 WAVE资源,这两个波形文件已存在该工程目录中。资源编译器一看到WAVE声明,它就会读声音文件并将它们编译进二进制资源文件。

Note

从上面的清单中看出,使用文本编辑器来创建某些类型的资源是比较容易的事。如果位图和波形音频文件存为了外部文件,可像上面的清单那样将它们包含到.RC文件中,并用资源编译器将它们编译为二进制资源文件。其中二进制资源文件可链接到应用程序的可执行文件中。

上面的资源清单只是部分代码,用传统的资源编辑器创建的位图常常以数字数据的形式包含到资源文件中,位图的资源描述可以很长。Jumping Jack位图资源描述大约有200行,因此未在清单中全部列出。下图给出了Jumping Jack启动后的界面。

0253

为应用程序创建附加资源不是什么高深的学问,但也不是很简单的事情。要搞清楚它们如何协调配合要花一定的事件。

以上代码均在Delphi7中测试通过,示例代码下载:JumpingJack.rar

[转载]android ORM框架的性能简单测试(androrm vs ormlite)

mikel阅读(861)

[转载]android ORM框架的性能简单测试(androrm vs ormlite) – youxiachai – 博客园.

前言

看了一下现在的 Android设备,性能都不差,就懒得直接用SQLite,直接上ORM框架把,上网搜了一圈,觉得androrm, ormlite 这两个不错,当然,还有点别的,这里就不多做介绍,竟然说明了是简单测试,而本人,也不算是专业的测试人员,就测试一下这两个框架在同一设备下,插入 1w(本来是想插100w,后来插入10w,接着就只能插1w,呵呵有兴趣的可以去测试一下…)行数据的时间吧,给大家做一个简单参考,真正要做比较的 话,其实,测试,表查询才是最重要的,但是,关键我没有这样的数据源,要构建一个挺耗时间的.

测试用设备

设备名 原道N10
主控方案 RK2918
CPU 1 ghz
RAM 512 MB
系统版本 2.3.1
象限(quadrant stand) 2000分左右

影响整个测试的硬件指标估计就这几个了,测试的环境就是上表的数据了

图表

R语言生成的:

Rplot

最 快当然是直接用SQLite…(废话),从表中我们可以比较出,就ORM框架而言androrm有一丁点的速度优势,可能由于ormlite用注解字段的 方式,导致ormlite性能有着一定的损失(注解其实也是利用了反射的原理),不过,对于熟悉j2ee的朋友来讲ormlite更容易上手,而对于 python程序员学习过django这个框架的朋友更容易上手androrm.从这个简单的实验来看,官方推荐我们少用get/set方法也不是毫无道 理的,对于一个类的反射的耗时,以我的那台设备而言开销可能大约在2毫秒左右(这个以第三次androrm 与SQLite的相减再除与10000得出..),注意…这只是简单的测试而已!!!真正要比较性能还要考虑到GC的问题,所以这里这是随便说说而已!

文档活跃度

androrm ormlite
文档 不完善 超级齐全
社区 不活跃,我提交到一个bug,到现在都还没有修复的消息 活跃
更新频率 很快!

个人建议,想研究怎么写orm框架的可以用androrm,想速度的开发产品,用ormlite,其实,啥都不用最好,呵呵~

有兴趣的朋友可以下载我用来测试的源代码试一下

http://www.kuaipan.cn/file/id_2622545685705265.html

[转载]Android应用全屏的方法

mikel阅读(1203)

[转载]Android应用全屏的方法 – – 博客园.

一般Android的应用启动时都有欢迎界面,类似QQHD启动那样。比较大方绚丽。心动不如行动,有时间自己也来实现类似的效果,嘿嘿。QQ2011

观察发现QQHD的欢迎界面是全屏的,这个好办。下面就Android应用调用全屏方式说明一下。

一般使Android程序的画面充满整个屏幕,有两种方法。

1.直接代码编写

1 @Override
2     protected void onCreate(Bundle savedInstanceState)
3     {
4         requestWindowFeature(Window.FEATURE_NO_TITLE);
5 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
6         super.onCreate(savedInstanceState);
7         setContentView(R.layout.welcome);
8     }


2.配置AndroidManifest.xml

 1     <application
 2         android:icon="@drawable/ic_launcher"
 3         android:label="@string/app_name" >
 4         <activity
 5             android:name=".Welcome"
 6             android:label="@string/app_name"
 7             android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
 8         >
 9             <intent-filter>
10                 <action android:name="android.intent.action.MAIN" />
11                 <category android:name="android.intent.category.LAUNCHER" />
12             </intent-filter>
13         </activity>
14         <activity
15             android:name=".AboutApp"
16             android:label="@string/aboutapp_title"
17             android:theme="@android:style/Theme.Dialog"
18         />
19     </application>

安卓示例

[转载]sqlserver 行转列

mikel阅读(1019)

[转载]sqlserver 行转列 – 李 鹏 – 博客园.

SQLServer把行转成列在我们编码中是经常遇到的我做一个小例子大家看一下

 1 --创建一个表
 2 create table PayPhoneMoney
 3 (
 4     id int identity(1,1),
 5     userName Nvarchar(20),
 6     payType nvarchar(20),
 7     money   decimal,
 8     payTime datetime,
 9     constraint pk_id primary key(id)
10 )
11 --插入点数据
12 insert into PayPhoneMoney values('小李','支付宝',20,'2012-01-03')
13 insert into PayPhoneMoney values('小陈','工行',20,'2012-01-06')
14 insert into PayPhoneMoney values('小赵','交行',50,'2012-01-06')
15 insert into PayPhoneMoney values('小陈','支付宝',60,'2012-01-06')
16 insert into PayPhoneMoney values('小赵','工行',30,'2012-01-16')
17 insert into PayPhoneMoney values('小张','中行',30,'2012-01-16')
18 insert into PayPhoneMoney values('小李','支付宝',60,'2012-01-16')

看一下表中的数据

我们要想查一下每个人所有支付形式下的总钱数如图所示

1 -- 查一下每个人所有支付形式下的总钱数
2 select userName from PayPhoneMoney group by userName
3 select userName,
4     sum(case payType when '支付宝' then money else 0 end) as 支付宝 ,
5     sum(case payType when '工行' then money else 0 end) as 工行, 
6     sum(case payType when '交行' then money else 0 end) as 交行,
7     sum(case payType when '中行' then money else 0 end) as 中行
8 from PayPhoneMoney 
9 group by userName

–我们这只列出了几种支付方式实际中还有很多支付方式不能一个一个都用case when 吧
–可以这样

1 declare @cmdText varchar(8000)
2 set @cmdText='select userName, '
3 select @cmdText=@cmdText+' sum(case payType when'''+payType+'''Then money else 0 end) as '''+payType
4 +''','+char(10) from (select Distinct payType from PayPhoneMoney) T
5 print @cmdText--发现多一个逗号下面把逗号去掉
6 set @cmdText=left(@cmdText,len(@cmdText)-2)--去掉逗号
7 set @cmdText=@cmdText+'from PayPhoneMoney group by userName'
8 print @cmdText
9 exec(@cmdText)

看一下结果是一样的吧

[转载]asp.net mvc2网站部署在IIS6的方法

mikel阅读(1032)

[转载]asp.net mvc2网站部署在IIS6的方法 – 我思故我在… – 博客园.

部署环境: Server 2003 +IIS6

1.先安装好IIS6,再安装.net framework 4.0和ASP.NET mvc 安装包(主要是里面的一个dll,不安装也可以,只需要找到这个dll,将mvc.dll 放入网站bin目录下,这个dll文件的默认路径是C:\Program Files\Microsoft ASP.NET\ASP.NET MVC 2\Assemblies\System.Web.Mvc.dll)

2.在IIS中新建网站设置web主目录,这个不详细说了,接着说重点

3.在发布的网站上右击【属性】—【主目录】—-【配置】,在弹出的【应用程序配置】窗口中点击【添加】,点击【浏览】将“可执行文件”设置为“C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll”,“扩展名”设置为”.mvc”,取消【确认文件是否存在

然后在下面点击【插入】,同样选择aspnet_isapi.dll,取消【确认文件是否存在】。

在发布的网站上右击【属性】–【APS.NET】,将【ASP.NET version】设置为4.0.30319

4.在【Web服务扩展】中设置ASP.NET v4.0.30319 为允许

以上配置完成后就大功告成了,以上亲测成功,若有问题欢迎留言一起探讨!

PS:若先装的.net framework 4.0,后装的IIS,需要注册aspnet到IIS,方法如下:

注意:要以管理员的身份运行

启动cmd窗口 (win键+R )  ,找到 4.0所在的目录,本人机器目录是
C:\Windows\Microsoft.NET\Framework\v4.0.30319

启动CMD进入上面的目录C:\Windows\Microsoft.NET\Framework\v4.0.30319

运行  aspnet_regiis.exe -i

稍等一会, aspnet_regiis 注册成功

[转载]ActionScript中Event类的几个属性

mikel阅读(1894)

[转载]Event类的几个属性 – 赵杰民 – 博客园.

var mc:MovieClip = new MovieClip();
mc.graphics.beginFill(0x0066cc);
mc.graphics.drawRect(100,100,200,200);
addChild(mc);
mc.addEventListener(MouseEvent.CLICK,onClick);
function onClick(e:MouseEvent):void
{
 trace(e.type)         // Event类下的,表示事件的类型
 trace(e.bubbles)      // Event类下的,指示事件是否为冒泡事件
 trace(e.cancelable)   // Event类下的,表示是否忽视事件的默认行为
}

bubbles  默认false  true 说明可以使用冒泡事件false 说明不可以

cancelable默认false如果不执行默认行为,则此值为 true;否则为 false。它是只读属性如果要修改可以用preventDefault()方法,可以取消默认行为

代码可通过访问 cancelable 属性来检查是否可以阻止任何指定事件对象的默认行为。 cancelable 属性包含一个布尔值,用于指示是否可以阻止默认行为。 您可以使用

preventDefault() 方法阻止或取消与少量事件关联的默认行为。

cancelable 还可以这样理解表示某个事件的默认行为能否被阻止。 true表示可以阻止,false表示不可以。

Event类的eventPhase属性也是只读属性,表示事件流的阶段。1、表示捕获阶段 2、目标阶段 3、冒泡阶段

var sp1:Sprite = new Sprite();
var sp2:Sprite = new Sprite();
this.addChild(sp1);
sp1.addChild(sp2);
drawRect(sp1,0xff9900,200);
drawRect(sp2,0x0000ff,100);
function drawRect(obj:DisplayObject,c:uint,b:uint):void
{
 //  这里要把严谨模式去掉
 obj.graphics.beginFill(c);
 obj.graphics.drawRect(0,0,b,b);
}
sp1.name = "sp1";
sp2.name = "sp2";
//  为所有节点注册事件
//   使用捕获阶段
stage.addEventListener(MouseEvent.CLICK,clickFunc,true);
this.addEventListener(MouseEvent.CLICK,clickFunc,true);
sp1.addEventListener(MouseEvent.CLICK,clickFunc,true);
//   使用目标阶段
sp2.addEventListener(MouseEvent.CLICK,clickFunc);      // sp2属于目标阶段不用设置true
//    冒泡阶段
stage.addEventListener(MouseEvent.CLICK,clickFunc);
this.addEventListener(MouseEvent.CLICK,clickFunc);
sp1.addEventListener(MouseEvent.CLICK,clickFunc);
function clickFunc(e:MouseEvent):void
{
 var s:String = e.currentTarget.name;  // 获得实例名
 if(s)   //  如果存在实例名,那么就输出实例名
 {
  trace(s,"阶段" + e.eventPhase);
 }
 else    //  如果实例名不存在,说明到达舞台,输出stage
 {
  trace("stage","阶段" + e.eventPhase);
 }
}

[转载]Android中文API合集(7)开发者指南合集(2) (chm格式下载)

mikel阅读(1200)

[转载]Android中文API合集(7) + 开发者指南合集(2) (chm格式) – 农民伯伯 – 博客园.

前言

Android中文翻译组是一个非盈利性质的开源组织至今已超过300人报名参与关于翻译组的介绍,请看这里。欢迎更多朋友加入,发邮件到over140@gmail.com申请加入或直接参与Wiki编辑。

Android中文翻译组WIKI网站http://wikidroid.sinaapp.com/不管是否加入我们,请与我们一起自由编辑和分享相关中文资料。

Android中文翻译组官方网站http://androidbox.sinaapp.com/。有在线的中文API、开发者指南、开源项目以及Android视频专栏。

本合集发布日期:2012131,涵盖历次合集内容,最新版请关注翻译组微博:http://weibo.com/android2

截图

下载

本站

结束

由于精力有限,目前暂停了自动更新客户端的维护,内部组织结构还在调整,推荐想参与的朋友直接参与到WIKI编辑。

[转载]解决SWFUpload在Chrome、Firefox等浏览器下的问题

mikel阅读(1837)

[转载]解决SWFUpload在Chrome、Firefox等浏览器下的问题 – 杨中科 – 博客园.

SWFUpload 是一个非常不错的异步上传组件,但是在Chrome、Firefox等浏览器下使用的时候会有问题。问题如下:为了防止跳过上传页面直接向“接受 SWFUpload上传的一般处理程序”(假如是Upload.ashx)发送请求造成WebShell漏洞,我的系统中对于Upload.ashx进行 了权限控制,只有登录用户才能进行上传。在IE下没问题,但是在Chrome下运行报错“用户未登录”。

经过搜索得知:因为SWFUpload是靠Flash进行上传的,Flash在IE下会把当前页面的Cookie发到Upload.ashx,但是Chrome、Firefox下则不会把当前页面的Cookie发到Upload.ashx。因为Session是靠Cookie中保存的SessionId实现的(传智播客的ASP.NET视频教程中讲到了Session和Cookie的关系,对于这点不熟悉的可以参考《传智播客视频教程2011版:ASP.NET≠拖控件》),这样由于当前页面的Cookie不会传递给Flash请求的Upload.ashx,因此请求的文件发送到Upload.ashx就是一个新的Session了,当然这个Session就是没有登录的了。

解决这个问题的思路也很简单,那就是手动把SessionId传递给服务器,再服务器端读出SessionId再加载Session。其实解决问题的办法SWFUpload的Demo中已经给出了,那就是在SWFUpload的构造函数中设置post_params参数:

                swfu = new SWFUpload({
                    // Backend Settings
                    upload_url: "/Upload.ashx",
                    post_params: {
                        "ASPSESSID": "<%=Session.SessionID %>"},
post_params中设定的键值对将会以Form表单的形式传递到Upload.ashx,也就是SWFUpload提供了为请求增加自定义请求参数的接口。
上面的代码把当前页面的SessionId写到ASPSESSID值中,当用户上传文件后,ASPSESSID就会传递到服务器上了,在Global.asax的Application_BeginRequest中添加如下代码:
            var Request = HttpContext.Current.Request;
            var Response = HttpContext.Current.Response;
            /* Fix for the Flash Player Cookie bug in Non-IE browsers.
             * Since Flash Player always sends the IE cookies even in FireFox
             * we have to bypass the cookies by sending the values as part of the POST or GET
             * and overwrite the cookies with the passed in values.
             * 
             * The theory is that at this point (BeginRequest) the cookies have not been read by
             * the Session and Authentication logic and if we update the cookies here we'll get our
             * Session and Authentication restored correctly
             */

            try
            {
                string session_param_name = "ASPSESSID";
                string session_cookie_name = "ASP.NET_SESSIONID";

                if (HttpContext.Current.Request.Form[session_param_name] != null)
                {
                    UpdateCookie(session_cookie_name, HttpContext.Current.Request.Form[session_param_name]);
                }
                else if (HttpContext.Current.Request.QueryString[session_param_name] != null)
                {
                    UpdateCookie(session_cookie_name, HttpContext.Current.Request.QueryString[session_param_name]);
                }
            }
            catch (Exception)
            {
                Response.StatusCode = 500;
                Response.Write("Error Initializing Session");
            }
其中UpdateCookie方法的定义如下:
        static void UpdateCookie(string cookie_name, string cookie_value)
        {
            HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(cookie_name);
            if (cookie == null)
            {
                cookie = new HttpCookie(cookie_name);
                //SWFUpload 的Demo中给的代码有问题,需要加上cookie.Expires 设置才可以
                cookie.Expires = DateTime.Now.AddYears(1);                
                HttpContext.Current.Request.Cookies.Add(cookie);
            }
            cookie.Value = cookie_value;
            HttpContext.Current.Request.Cookies.Set(cookie);
        }

原理:当用户请求到达ASP.NET引擎的时候Application_BeginRequest方法首先被调用,在方法中看客户端是否提交上来了ASPSESSID,如果有的话则把ASPSESSID的值写入Cookie(以”ASP.NET_SESSIONID”为Key,因为ASP.Net中SessionId就是保存在”ASP.NET_SESSIONID”为Key的Cookie中的),Application_BeginRequest方法后就可以从Cookie中读取到”ASP.NET_SESSIONID”的值还原出页面的Session了。

如果网站中还用到了Membership的FormsAuthentication验证,则还需要把AUTHID也按照SessionID的方法进行处理,这一点是其他讲到SWFUpload这个Bug处理的文章中没有提到的。

在SWFUpload的构造函数中设置post_params参数:

                swfu = new SWFUpload({
                    // Backend Settings
                    upload_url: "/AdminHT/UploadArticleImg.ashx",
                    post_params: {
                        "ASPSESSID": "<%=Session.SessionID %>",
                        "AUTHID" : "<%=Request.Cookies[FormsAuthentication.FormsCookieName].Value%>"
                    },
在在Global.asax的Application_BeginRequest中添加如下代码:
            try
            {
                string auth_param_name = "AUTHID";
                string auth_cookie_name = FormsAuthentication.FormsCookieName;

                if (HttpContext.Current.Request.Form[auth_param_name] != null)
                {
                    UpdateCookie(auth_cookie_name, HttpContext.Current.Request.Form[auth_param_name]);
                }
                else if (HttpContext.Current.Request.QueryString[auth_param_name] != null)
                {
                    UpdateCookie(auth_cookie_name, HttpContext.Current.Request.QueryString[auth_param_name]);
                }

            }
            catch (Exception)
            {
                Response.StatusCode = 500;
                Response.Write("Error Initializing Forms Authentication");
            }

[转载]jquery插件制作心得

mikel阅读(984)

[转载]jquery插件制作心得 – 殷海超 – 博客园.

今天刚刚把jquery的插件制作学习了一下,总结一下别人写的和自己的心得,方便其他初学者的学习,考虑到要学习jquery插件制作的人一定知道jquery插件的好处和通用性,这里就不多说
一、先从一个简单的实例,不需要带参数的一个方法开始
//创建一个匿名函数   
(function($){   
    //给jQuery附加一个新的方法(详细见备注1)
   $.fn.extend({    
        //插件的名字
        MyFirstName: function() {   
           //迭代当前匹配元素集合
            return this.each(function() {   
var obj = $(this);
                //自己的代码  
            });   
        }   
    });   
)(jQuery);
备注1:理解$.fn.extend和$.extend的区别,大概的说前者是将MyFirstName这个方法合并到jquery的实例对象中,例如$(“#txtmy”).add(3,4)这样调用方法,后者是将MyFirstName这个方法合并到jquery的全局对象中,例如$.add(3,4); 这样调用方法
详细区别见(http://ioryioryzhan.iteye.com/blog/232971)

二、有参数的
//创建一个匿名函数   
(function($){   
    //给jQuery附加一个新的方法(详细见备注1)
   $.fn.extend({    
        //插件的名字
        MyFirstName: function() {   
//定义默认参数
Var parms={
Parms1:1,
Parms2:2
}
//合并用户传的参数和默认参数,返回给options(详细见备注2)
var options = $.extend(defaults, options);  
           //迭代当前匹配元素集合
            return this.each(function() { 
//把合并后的参数赋值给o
var o=  options;
//迭代当前匹配元素
var obj = $(this);
                //自己的代码  
            });   
        }   
    });   
)(jQuery);
备注2:var options = $.extend(defaults, options); 意思是把defaults和options合并,如果后者有和前者名称一样的元素,后者覆盖前者,然后合并给defaults,然后defaults赋值给options,如果是var options = $.extend({},defaults, options);那么是把前者和后者合并给{}这个参数,然后赋值给options,defaluts的结构和值都没有变化
详细区别见(http://www.cnblogs.com/holygis/archive/2011/11/02/2232659.html)

[转载]降低即时搜索的服务器压力

mikel阅读(1013)

[转载]降低即时搜索的服务器压力 – 我有我在 – 博客园.

在做即时搜索(就是像百度搜索输入文本框内容的时候自动搜索出类似的信息)的时候一般都是点击键盘触发搜索事件 一般用onkeydowm或onkeyup (也许onpropertychange是很好的,但可惜在ff和chorme下是不支持的)这样每次点击键盘就会搜索 如果有很多用户的情况下,那么服务器的压力是很大的 怎么办 只能减少提交搜索次数解决了下面这两个方法是文本框每次onkeyup的触发事件—Str是搜索关键字
AjaxSearch: function (Str) {
if (Str.trim() == “”) { return false; }
if (NetHome.PostMessage.posting == false) {     //NetHome.PostMessage.posting 一个判断是否在提交中的变量
NetHome.PostMessage.posting = true;
setTimeout(“NetHome.Utility.AjaxSearching()”, 1000);
}
},
AjaxSearching: function () {
var Str = $(‘#searchtxt’).val().trim();//文本框的值
$.post(“/Ajax/AjaxSearch”, { SearchKey: Str }, function (Msg) {
//处理展示搜索内容的代码
}
NetHome.PostMessage.posting = false;
});
},

这样的效果就是 第一次触发提交事件的一秒后才执行提交搜索 搜索的关键字也是一秒后输入的关键字 并且在一次提交过程中,不会再接受其他提交事件  从而大大降低每次点击键盘都提交给服务器带来的压力

注意:setTimeout的第一个参数(待执行的代码)要当作字符串输入 并且代执行的代码
如果是有参数的方法  那么参数必须是全局变量(至少不能是在这个方法中定义的变量)

示例页面