[转载]win32进阶之路:程序托盘图标+右键弹出菜单 - 赵大哥 - 博客园

mikel阅读(826)

[转载]win32进阶之路:程序托盘图标+右键弹出菜单 – 赵大哥 – 博客园.

   开场白

本次介绍两个非常棒且实用的技巧:程序托盘图标和右键弹出菜单,效果如下图。

程序托盘图标用了迅雷的图标,右键点击时候会弹出三个选项的菜单。

程序托盘图标设置

我会用尽可能清晰明了的步骤介绍方式来讲述,我假设大家已经动手写了属于自己的windows窗体,刚学习win32的朋友可以看一下我之前的博客,有介 绍如何从头创建属于自己的第一个windows窗口,也可以直接参照本文末尾贴出的完整代码做一些参考。如果大家觉得其他方式更好或者对讲述不理解的可以 评论或者发送给我的邮箱believing_dan@hotmail.com,QQ382128698.

步骤1:声明托盘图标对象并给关键成员赋值。

步骤2:通知windows在右下角区域添加图标。

步骤3:处理托盘图标的左键点击和右键点击消息。

步骤1/2的代码:

 

 

        void NotifySwitch(HWND hWND,TCHAR operation[4])
{
if(!strncmp(operation, TEXT(“MIN”), 3))
{
               //声明变量并初始化
NOTIFYICONDATA nID = {};
                //关联的托盘图标资源,图标需要是16*16或者32*32像素的
nID.hIcon = (HICON)LoadImage(NULL, TEXT(“notify.ico”), IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
//托盘图标的提示语,即鼠标放在上面会弹出的提示
                strncpy_s(nID.szTip, TEXT(“自制锁屏软件卖萌中”), sizeof(TEXT(“自制锁屏软件卖萌中”)));
//托盘图标关联的窗口
                nID.hWnd = hWND;
//应用程序只有一个托盘图标的话可以随便设
                nID.uID = 1;
//托盘图标的类型,详解见MSDN
                nID.uFlags = NIF_GUID | NIF_ICON | NIF_MESSAGE | NIF_TIP;
//托盘图标关联的消息ID,托盘的左击和右击消息的消息ID就是它
                nID.uCallbackMessage = WM_MINMAXNotify;
//通知windows添加一个托盘图标,看参数就知道啦
                Shell_NotifyIcon(NIM_ADD, &nID);
}
}

步骤3的代码,即如何处理托盘关联的消息。

再次假设大家已经有了自己的windows窗体,完整代码参考本文最后贴出的代码。    

 

 

case WM_MINMAXNotify:
switch(lparam)
{
case WM_LBUTTONDOWN:
MessageBox(NULL, TEXT(“Recv notify icon message”), TEXT(“notify”), MB_ICONHAND);
break;
case WM_RBUTTONDOWN:
POINT pt;
GetCursorPos(&pt);
HMENU hMenu;
hMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_STRING , IDM_FIR, “秘籍”);
AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hMenu, MF_STRING, IDM_SEC, TEXT(“打怪”));
AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hMenu, MF_STRING, IDM_THI, TEXT(“补给”));
AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, NULL, hwnd, NULL);
break;
}
break;

是 不是太简单了!呵呵,就这么简单,在windows的窗体处理函数中增加一个case处理托盘关联的消息,鼠标对托盘的动作可以通过lparam参数来获 取,这里我处理了左键和右键的单击消息,左键单击弹出一个提示框,右键单击托盘……好嘛,我已经漏题了,没错,右键的处理就是添加一个弹出菜单。

增加右键弹出菜单

步骤1:创建一个PopMenu对象。

步骤2:为新增加的弹出菜单增加菜单项。

步骤3:显示新增加的菜单。

步骤4:处理菜单项的消息。

又用4步就搞定了这么实用的技巧,是不是小激动呢?尽管前面已经漏题了,还是讲一下代码吧。

创建一个弹出菜单的HMENU句柄,菜单分很多种,需要用对应的创建API

HMENU hMenu = CreatePopupMenu();

插入一个菜单项,并给菜单项起一个字符名称,这里必须设置菜单项的类型是MF_STRING,并给菜单项关联一个ID

AppendMenu(hMenu, MF_STRING , IDM_FIR, “秘籍”);

插入一个分隔符,让菜单更好看,啥?没错,就是更好看一点

AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);

 

对比一下前面的截图,不一样的地方就是分隔符在搞鬼了。

获取到当前的鼠标位置并显示刚创建的弹出菜单,这里有一个小技巧,为什么不把弹出菜单和当前窗口关联起来呢,这样点选菜单后就会自动销毁菜单了。

POINT pt;

GetCursorPos(&pt);  

TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, NULL, hwnd, NULL);

弹出菜单的响应消息属于WM_COMMAND命令系列,通过wparam可以区分点击的菜单项。

case WM_COMMAND:

switch (wparam)

{

case IDM_FIR:

MessageBox(NULL, TEXT(“Recv popup menu idm_fir message”), TEXT(“Popup”), MB_ICONINFORMATION);

break;

case IDM_SEC:

MessageBox(NULL, TEXT(“Recv popup menu idm_sec message”), TEXT(“Popup”), MB_ICONASTERISK);

break;

case IDM_THI:

MessageBox(NULL, TEXT(“Recv popup menu idm_thi message”), TEXT(“Popup”), MB_ICONEXCLAMATION);

break;

default:

break;

}

break;

源代码链接说明:完整代码是还在完善中的一个锁屏软件代码,可能要费些功夫去寻找一下本文介绍的功能,当然也可能会对大家有一些额外的帮助,下面是锁屏软件的截图,中间的妹子可是会眨眼卖萌的哟,子窗口会逐渐漂移,碰到屏幕边缘会反弹回来。

锁屏软件持续更新中,欢迎大家关注我的博客。

代码及示例 http://download.csdn.net/detail/hd770c/6920757

[转载]使用HTML 5/CSS3五步快速制作便签贴特效 - 苍狼老贼 - 博客园

mikel阅读(821)

[转载]使用HTML 5/CSS3五步快速制作便签贴特效 – 苍狼老贼 – 博客园.

本篇文字将展示给你的是,如何利用HTML5/CSS3,仅用5步就可以制作便签贴效果的HTML页面,效果图如下:

(注:图里的文字纯属杜撰,搞笑目的,如有雷同,纯属巧合,谢谢!)

 

 

注:该效果可以在Safari, Chrome,Firefox和Opera在看到效果,IE上由于对HTML5的支持不完全,所以看不出效果。

第一步:创建基本HTML和正方形

首先添加基本的HTML结构以及构建基本的正方形,代码如下:

  1. <ul> 
  2.        <li><a href=“#”> 
  3.            <h2>Dudu:</h2> 
  4.            <p>最近咋没有美女发帖呢?我一定给个头条推荐,recommend!recommend!</p> 
  5.        </a></li> 
  6.        <li><a href=“#”> 
  7.            <h2>汤姆大叔:</h2> 
  8.            <p>Team的一个成员去了Microsoft做SDE3,又得hire new member了</p> 
  9.        </a></li> 
  10.        <li><a href=“#”> 
  11.            <h2>技术弟弟:</h2> 
  12.            <p>O2DS和我翻译的书是一样,我一定要比他翻得快, 晚上加班翻,fast! fast! fast!</p> 
  13.        </a></li> 
  14.        <li><a href=“#”> 
  15.            <h2>Artech:</h2> 
  16.            <p>WCF的帖子真是少,看来我得多发点帖子让大家学习呢</p> 
  17.        </a></li> 
  18.        <li><a href=“#”> 
  19.            <h2>吉日嘎拉:</h2> 
  20.            <p>将权限管理、工作流管理做到我能力的极致,一个人只能做好那么很少的几件事情</p> 
  21.        </a></li> 
  22.        <li><a href=“#”> 
  23.            <h2>某武林高手:</h2> 
  24.            <p>低于25000块的面试再也不去了,它grandma的</p> 
  25.        </a></li> 
  26.    </ul> 

每个note都加一个href连接,主要是为了支持键盘访问,CSS代码如下:

  1. *{    
  2.     margin:0;    
  3.     padding:0;    
  4.   }    
  5.   body{    
  6.     font-family:arial,sans-serif;    
  7.     font-size:100%;    
  8.     margin:3em;    
  9.     background:#666;    
  10.     color:#fff;    
  11.   }    
  12.   h2,p{    
  13.     font-size:100%;    
  14.     font-weight:normal;    
  15.   }    
  16.   ul,li{    
  17.     list-style:none;    
  18.   }    
  19.   ul{    
  20.     overflow:hidden;    
  21.     padding:3em;    
  22.   }    
  23.   ul li a{    
  24.     text-decoration:none;    
  25.     color:#000;    
  26.     background:#ffc;    
  27.     display:block;    
  28.     height:10em;    
  29.     width:10em;    
  30.     padding:1em;    
  31.   }    
  32.   ul li{    
  33.     margin:1em;    
  34.     float:left;    
  35.   } 

效果如下:

 

 

第二步:阴影和手写草体字

这一步,是我们要实现正方形的阴影效果,并且将字体改为草体(仅限英文),由于google提供了Font API的支持,所以我们可以直接使用了,首先添加对Google API的调用:

  1. <link href=“http://fonts.googleapis.com/css?family=Reenie+Beanie:regular” rel=“stylesheet” type=“text/css”> 

然后设置引用这个字体:

  1. ul li h2 
  2.        {  
  3.            font-size140%;  
  4.            font-weightbold;  
  5.            padding-bottom10px;  
  6.        }  
  7.        ul li p  
  8.        {  
  9.            font-family“Reenie Beanie” ,arial,sans-serif,微软雅黑;  
  10.            font-size110%;  
  11.        } 

关于阴影,由于各个浏览器还都不完全支持,所以需要分别处理,代码如下:

  1. ul li a  
  2.      {  
  3.          text-decorationnone;  
  4.          color#000;  
  5.          background#ffc;  
  6.          displayblock;  
  7.          height10em;  
  8.          width10em;  
  9.          padding1em/* Firefox */ 
  10.          -moz-box-shadow: 5px 5px 7px rgba(33,33,33,1); /* Safari+Chrome */ 
  11.          -webkit-box-shadow: 5px 5px 7px rgba(33,33,33,.7); /* Opera */ 
  12.          box-shadow: 5px 5px 7px rgba(33,33,33,.7);  
  13.      } 

效果如下:

 

 

第三步:倾斜正方形

为了让正方形倾斜,我们需要在li->a里添加如下代码:

  1. ul li a{    
  2.    -webkit-transform:rotate(-6deg);    
  3.    -o-transform:rotate(-6deg);    
  4.    -moz-transform:rotate(-6deg);    
  5.  } 

但是为了能让正方形随机倾斜,而不是全部都倾斜,我们需要使用新的CSS3选择器,让正方形在每2个倾斜4个deg,每3个倾斜负3个deg,每5个倾斜5个deg:

  1. ul li:nth-child(even) a{    
  2.      -o-transform:rotate(4deg);    
  3.      -webkit-transform:rotate(4deg);    
  4.      -moz-transform:rotate(4deg);    
  5.      position:relative;    
  6.      top:5px;    
  7.    }    
  8.    ul li:nth-child(3n) a{    
  9.      -o-transform:rotate(-3deg);    
  10.      -webkit-transform:rotate(-3deg);    
  11.      -moz-transform:rotate(-3deg);    
  12.      position:relative;    
  13.      top:-5px;    
  14.    }    
  15.    ul li:nth-child(5n) a{    
  16.      -o-transform:rotate(5deg);    
  17.      -webkit-transform:rotate(5deg);    
  18.      -moz-transform:rotate(5deg);    
  19.      position:relative;    
  20.      top:-10px;    
  21.    } 

效果如下:

 

第四步:Hover和Focus时放缩正方形

想在hover和focus的时候达到缩放的效果,我们需要添加如下代码:

  1. ul li a:hover,ul li a:focus{    
  2.   -moz-box-shadow:10px 10px 7px rgba(0,0,0,.7);    
  3.   -webkit-box-shadow: 10px 10px 7px rgba(0,0,0,.7);    
  4.   box-shadow:10px 10px 7px rgba(0,0,0,.7);    
  5.   -webkit-transform: scale(1.25);    
  6.   -moz-transform: scale(1.25);    
  7.   -o-transform: scale(1.25);    
  8.   position:relative;    
  9.   z-index:5;    
  10. }  

设置z-index为5是为了让正方形在放大的时候盖住其它的正方形,同时因为也设置了focus,所以也支持Tab键切换访问,效果如下:

 

 

第五步:平滑过渡和添加颜色

第四步的特效,看起来有些生硬,我们可以添加Transition来达到平滑动画的效果,另外颜色比较单一,我们可以设置一下不同的颜色,首先在ul->li->a里添加Transition:

  1. -moz-transition:-moz-transform .15s linear;    
  2.  -o-transition:-o-transform .15s linear;    
  3.  -webkit-transition:-webkit-transform .15s linear;   

然后在even和3n里定义不同的颜色:

  1. ul li:nth-child(even) a{    
  2.       -o-transform:rotate(4deg);    
  3.       -webkit-transform:rotate(4deg);    
  4.       -moz-transform:rotate(4deg);    
  5.       position:relative;    
  6.       top:5px;    
  7.       background:#cfc;    
  8.     }    
  9.     ul li:nth-child(3n) a{    
  10.       -o-transform:rotate(-3deg);    
  11.       -webkit-transform:rotate(-3deg);    
  12.       -moz-transform:rotate(-3deg);    
  13.       position:relative;    
  14.       top:-5px;    
  15.       background:#ccf;    
  16.     } 

这样,就完成了我们最终的效果:

 

 

总结

至此,我们利用了HTML5和CSS3的基本特性做成了一个还不错的便签贴效果,HTML5/CSS3确实很强大,如果在加一些高级特性,比如和JavaScript结合起来,能实现更加牛逼的效果,从当耐特砖家给大家的HTML5实验室系列文章,就可以看出来了。

[转载]在Visual Studio上开发Node.js程序 - 大魔王mAysWINd - 博客园

mikel阅读(974)

[转载]在Visual Studio上开发Node.js程序 – 大魔王mAysWINd – 博客园.

【题外话】

最近准备用Node.js做些东西,于是找找看能否有Visual Studio上的插件以方便开发。结果还真找到了一个,来自微软的Node.js Tools for Visual Studio(NTVS),虽然现在仅发布了1.0 Alpha版本,但使用起来已经非常方便。而且,其开发团队与Python Tools for Visual Studio(PTVS)是同一个,而PTVS就是Visual Studio 2013中要创建自带的Python项目需要安装的那个程序,所以大可放心的使用NTVS。

 

【文章索引】

  1. NTVS介绍与安装
  2. NTVS项目创建和使用
  3. NTVS项目的调试
  4. NTVS项目的包管理

 

【一、NTVS介绍与安装】

从其官网(http://nodejstools.codeplex.com) 上可以找到其介绍,NTVS是一个使Visual Studio成为Node.js集成开发环境的免费、开源的插件,NTVS支持编辑、Intellisense、Profiling、npm包管理器、本 地以及远程调试(Windows、MacOS及Linux),同时其支持Windows Azure网站及云服务。

总之,该有的都有了。如果要安装NTVS的话,需要VS 2013或2012 Update4的Professional(或Test Professional)、Premium或Ultimate版本,同时需要安装有Node.js的0.10.20或以上的版本,有了这些准备后,就可 以去官网下载安装包进行安装了,需要注意的是,VS 2013和2012的安装包是各自独立的。

安装完成后,就会在Visual Studio的JavaScript类型中多出以下的项目类型:

 

【二、NTVS项目创建和使用】

对于Node.js而言,项目类型并不像.NET项目有这么多不同的类型,每种之间的开发环境等还有差异。对于上面的Blank Node.js Console Application和Web Application两个项目而言,无非就是前者模板的代码只提供了在控制台输出Hello World的代码;而后者则用Node.js创建了一个Http服务器,并为每个请求都输出Hello World罢了,即实现了一个简单的Web应用程序。而Express Application则是使用Node.js上的Express框架+Jade模板引擎+Stylus实现了一个小的Web应用程序。而剩下的第一个项 目则是从已有的Node.js项目中创建,后两个与其他的类似,只不过已经配置好了脚本和配置文件等可以直接部署到Windows Azure中。

项目创建后与Visual Studio的C#等项目没有太大区别,Intellisense功能也非常强大,敲入require的时候会提示所有的模块名称,同时选择每个模块的时 候会提示这个模块的作用和说明(如下图),并且键入回车可以直接补齐单引号等等,都非常方面。而对于每个模块,其所有方法和成员变量也都能自动显示出来, 只不过不像require那样会显示说明信息。

 

【三、NTVS项目的调试】

NTVS项目调试的方式与C#一样,都是F5运行并调试和Ctrl+F5只运行不调试,其会自动运行已安装的Node程序执行当前项目的代码。对于 Web Application项目并且使用了使用了http模块的话,还会自动打开浏览器访问指定的端口(可以在项目属性中关闭)。需要说明的是,对于 Node.js项目,有且仅有一个启动文件(相当于程序的Main()函数),程序从这个文件的开始执行,默认情况下项目创建后第一个创建的js文件为启 动文件,启动文件用粗体表示。如果需要设置其他文件为启动文件,右键单击选择设置就可以了(如下图) 。

在调试过程中,与其他项目一样,都可以设置断点、单步执行以及监视什么的都是可以用的,同时如果在程序代码中抛出了异常,在调试过程中也会提示出来(如下图)。

默认情况下,所有异常都将提示,当然也可以自己选择哪些异常不提示。可以在提示了异常之后选择“打开异常设置”,或者选择“调试”菜单,选择“异常”,如下图:

 

【四、NTVS项目的包管理】

NTVS还提供了非常方便的包管理方式,就如同在C#项目中添加引用一样方便的添加其他包。当然也可以自己使用npm安装相应的包,然后在项目中使 用,虽然调试运行没有问题,不过这样是没有Intellisense提示的。所以,如果项目中需要其他的包,可以右键单击npm,选择“Manage npm Modules…”(如下图),在npm包管理器中右侧的包名称中输入包的名称,然后点击下方的本地安装(为当前项目安装)就可以了,完成后会在左侧 出现已安装的包,然后在项目中require也会出现相应的包名,在使用包的时候也会有方法成员的提示等等。

安装完包后就会在解决方案管理器的npm下出现相应的包名,与C#项目添加引用类似。同时,与执行npm ls命令一样,也是可以查看包的依赖关系的(如下图)。

【相关链接】

  1. Introducing node.js Tools for Visual Studio:http://www.hanselman.com/blog/IntroducingNodejsToolsForVisualStudio.aspx
  2. [Visual Studio]NTVS – Node.js Tools For Visual Studio Bootcamp:http://www.dotblogs.com.tw/blackie1019/archive/2013/12/27/136557.aspx
  3. Microsoft Joins Forces with RedGate and Clickberry to Offer Node.js Tools for Visual Studio:http://www.infoq.com/news/2013/12/NTVS

[转载]用node-webkit把web应用打包成桌面应用 - 无双 - 博客园

mikel阅读(1086)

[转载]用node-webkit把web应用打包成桌面应用 – 无双 – 博客园.

node-webkit是 一个Chromium和node.js上的结合体,通过它我们可以把建立在chrome浏览器和node.js上的web应用打包成桌面应用,而且还可以 跨平台的哦。很显然比起传统的桌面应用,在某些特定领域用html5+css3+js开发的web应用更加简单和高效,而且还可以使用node.js的功 能,所以node-webkit还是很有用处的。

下面我通过一个简单的demo来介绍怎么样把一个web应用打包成一个可执行文件(这里只介绍windows环境)

首先新建一个index.html文件,作为我们这个demo的入口页面,我们暂且就把这个页面当成一个完整的web应用吧。内容随便写点什么,比如:

QQ截图20140210135428

然后创建配置文件 package.json,内容如下:

QQ截图20140210135428

其中的main属性就是用来指定入口文件的,这个属性的值可以是本地文件,也可以是远程网址,这样就相当于可以把一个远程的web应用直接变为一个桌面应用了。

除了name与main这两个属性外,还有很多其他有用的属性可以配置,比如指定应用的图标,显不显示浏览器的工具栏,指定浏览器的初始大小等等,具体的配置参数文档可看这里https://github.com/rogerwang/node-webkit/wiki/Manifest-format

 

现在我们有了两个文件了。

QQ截图20140210135428

 

然后将index.html和package.json这两个文件压缩到一个zip压缩包里,命名为app.zip

QQ截图20140210135428

 

现在app.zip这个压缩包里的内容应该是这样的:

QQ截图20140210135428

 

然后把app.zip这个文件的扩展名改为nw,变为 app.nw

QQ截图20140210135428

 

然后下载一个windows版本的node-webkit,解压后得到一个文件夹:

QQ截图20140210135428

 

之后我们之前得到的app.nw这个文件就可以用nw.exe来执行了,直接把app.nw拖到nw.exe上就可以了。运行结果如下:

QQ截图20140210135428

跟在chrome中打开index.html这个页面的效果差不多,当然你可以通过配置package.json这个文件,来隐藏浏览器的工具栏或边框,来使它更像是一个桌面软件。

 

因为nw文件的运行需要node-webkit环境的支持,所以我们还需要把app.nw这个文件跟node-webkit的环境文件一起打包成一个可执行文件。

首先打开windows的cmd,然后输入如下命令:

copy /b nw.exe+app.nw app.exe

注意文件路径要根据你的实际情况进行变动,这里假设app.nw放在了node-webkit的主文件夹里,然后输出的app.exe也会在这个文件夹里。

执行命令后我们得到了 app.exe 这个可执行文件。

QQ截图20140210135428

 

到了这步,我们已经得到了app.exe这个文件,但如果只有app.exe这个文件还是不够的,这个可执行文件的运行还需要几个dll文件的支持。

其中 nw.pak 与 icudt.dll 这个两个文件是必须要的。

ffmpegsumo.dll 文件是媒体支持文件,如果你的html页面中用到了<video>或<audio>或其它与媒体相关的东西,则必须带上这个文件。

libEGL.dll 和 libGLESv2.dll 这个两个文件则是使用webGL或GPU必须要的

 

最后我们得到的就是这样一个文件夹:

QQ截图20140210135428

执行app.exe就可以运行我们的demo了。

 

但我们大多数人想的是给用户一个exe文件,用户就可以使用了,不用再附带一些其他文件。

嗯,所以我们还可以把app.exe跟其他的文件再打包一次,把上图中的所有文件变成一个可执行文件,用户只要得到这个文件,就能运行我们的应用了。

做这步我们需要一个软件叫Enigma Virtual Box,首先下载和安装这个软件,然后打开它。

然后在Enter Input File Name那里输入我们的app.exe的路径,在Enter Output File Name那里填写我们要把打包出来的可执行文件输出到哪里。最后是把除app.exe外的其它文件拖入到Files那里,遇到提示的话默认就可以了。

QQ截图20140210135428

 

最后点击右下角的Process按钮,就大功告成了。

QQ截图20140210135428

 

最后我们得到了一个 app_boxed.exe 的文件,只要把这个文件交给用户,用户就可以运行了。

node-webkit虽然方便,但有个很大的缺点是得到的可执行文件有点大,大家在可以在衡量利弊后决定使不使用。

[转载]Android SQLite编程详解 - IF_ONLY - 博客园

mikel阅读(1027)

[转载]Android SQLite编程详解 – IF_ONLY – 博客园.

数据库功能非常强大,使用起来也非常方便,SQLite数据库的一般操作包括:创建数据库、打开数据库、创建表、向表中添加数据、从表中删除数据、修改表中的数据、关闭数据库、删除指定表、删除数据库和查询表中的某条数据。下面我们分别来学习这些基本操作。

1.创建和打开数据库

Android 中创建和打开一个数据库都可以使用openOrCreateDatabase 方法来实现,因为它会自动去检测是否存在这个数据库,如果存在则打开,不过不存在则创建一个数据库;创建成功则返回一个 SQLiteDatabase对象,否则抛出异常FileNotFoundException。下面我们来创建一个名 为”Examples_06_05.db”的数据库,并返回一个SQLiteDatabase对象 mSQLiteDatabase。

1
mSQLiteDatabase = this.openOrCreateDatabase("Example_06_05.db", MODE_PRIVATE, null);

2.创建表

一个数据库中可以包含多个表,我们的每一条数据都保存在一个指定的表中,要创建表可以通过execSQL 方法来执行一条SQL语句。execSQL能够执行大部分的SQL语句,下面我们来创建一个名为table1 且包含3个字段的表。 具体代码如下:

1
2
String CREATE_TABLE = "CREATE TABLE table1 (_id INTEGER PRIMARY KEY, num INTEGER,  data TEXT)";
mSQLiteDatabase.execSQL(CREATE_TABLE);

3.向表中添加一条数据

可以使用insert 方法来添加数据,但是 insert 方法要求把数据都打包到 ContentValues 中, ContentValues 其实就是一个Map, key值是字段名称, Value值是字段的值。通过 ContentValues 的 put 方法就可以把数据放到ContentValues中,然后插入到表中去。具体实现如下:

1
2
3
4
5
6
7
8
ContentValues  cv  =  new ContentValues();
cv.put(TABLE_NUM, 1);
cv.put(TABLE_DATA, "测试数据");
mSQLiteDatabase.insert(TABLE_NAME, null, cv);

  //这样同样可以使用execSQL方法来执行一条“插入”的SQL语句,代码如下:
String  INSERT_DATA = "INSERT INTO table1 (_id, num, data) values (1, 1, '通过SQL语句插入')" ;
mSQLiteDatabase.execSQL(INSERT_DATA);

4.从表中删除数据

要删除数据可以使用delete 方法,下面我们删除字段 “_id” 等于1的数据,具体代码如下:

1
2
3
4
mSQLiteDatabase.delete("Examples_06_05.db", " where_id="+0, null);
通过 execSQL方法执行SQL语句删除数据如下:
String  DELETE_DATA = "DELETE FROM table1 WHERE _id=1";
mSQLiteDatabase.execSQL(DELETE_DATA);

5.修改表中的数据

如果添加了数据后发现数据有误,这时需要修改这个数据,可以使用updata方法来更新一条数据。下面我们来修改 “num” 值为0的数据,具体代码如下:

1
2
3
4
ContentValues cv = new ContentValues();
cv.put(TABLE_NUM, 3);
cv.put(TABLE_DATA, "修改后的数据");
mSQLiteDatabase.update("table1" cv, "num " + "=" + Integer.toString(0), null);

6.关闭数据库

关闭数据库很重要,也是大家经常容易忘记的。关闭的方法很简单,直接使用SQLiteDatabase 的 close 方法。具体代码如下:

1
mSQLiteDatabase.close();

7.删除指定表

这里我们使用execSQL方法来实现,具体代码如下:

1
 mSQLiteDatabase.execSQL("DROP TABLE table1");

8.删除数据库

要删除一个数据库,直接使用deleteDatabase 方法即可,具体代码如下:

1
     this.deleteDatabase("Examples_06_05.db");

9.查询表中的某条数据

Android中查询数据是通过Cursor类来实现的,当我们使用SQLiteDatabase.query()方法时,会得到一个Cursor对象,Cursor指向的就是每一条数据。它提供了很多有关查询的方法,具体方法如下:

方法 说明
move 以当前的位置为参考,将Cursor移动到指定的位置,成功返回true, 失败返回false

moveToPosition 将Cursor移动到指定的位置,成功返回true,失败返回false

moveToNext 将Cursor向前移动一个位置,成功返回true,失败返回false

moveToLast 将Cursor向后移动一个位置,成功返回true,失败返回 false。

movetoFirst 将Cursor移动到第一行,成功返回true,失败返回false

isBeforeFirst 返回Cursor是否指向第一项数据之前

isAfterLast 返回Cursor是否指向最后一项数据之后

isClosed 返回Cursor是否关闭

isFirst 返回Cursor是否指向第一项数据

isLast 返回Cursor是否指向最后一项数据

isNull 返回指定位置的值是否为null

getCount 返回总的数据项数

getInt 返回当前行中指定的索引数据

下面我们就是用Cursor来查询数据库中的数据,具体代码如下:

1
2
3
4
5
6
7
8
9
Cursor cur = mSQLiteDatabase.rawQuery("SELECT * FROM table", null);
if( cur != null ){
   if( cur.moveToFirst() ){
       do{
                  int numColumn = cur.getColumnIndex("num");
                  int num            = cur.getInt(numColumn);
            }while( cur.moveToNext());
      }
 }

[转载]LuManager中的Nginx让支持pathinfo - 帮助中心 - LuManager(LUM)官方授权代理商[双赢网络]

mikel阅读(997)

[转载]LuManager中的Nginx让支持pathinfo – 帮助中心 – LuManager(LUM)官方授权代理商[双赢网络].

1、网站管理中找到要支持PATHINFO的网站,然后点击右边的“修改”。
2、找到 Nginx扩展设置(location段).
3、在location中填入下列:


    location ~* \.(php[3-9]?|phtm[l]?)(\/.*)*$ {
    fastcgi_index index.php;
    fastcgi_pass 127.0.0.1:8999;
    include      fastcgi_params;
    set $path_info "";
    set $real_script_name $fastcgi_script_name;
    if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
    set $real_script_name $1;
    set $path_info $2;
    }
    fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
    fastcgi_param SCRIPT_NAME $real_script_name;
    fastcgi_param PATH_INFO $path_info;
    }

4、保存并重启Nginx服务即可。
测试代码:


    正常情况下,你可以看到it works

    如果您点击下面的链接还是可以看到上面的文字而不是404,说明支持pathinfo

    index.php/home

    PATH_INFO:
            echo $_SERVER['PATH_INFO'];
    ?>

[转载]让Nginx支持ThinkPHP的URL重写和PATHINFO - 潺莪 - 博客园

mikel阅读(910)

[转载]让Nginx支持ThinkPHP的URL重写和PATHINFO – 潺莪 – 博客园.

ThinkPHP支持通过PATHINFO和URL rewrite的方式来提供友好的URL,只需要在配置文件中设置 ‘URL_MODEL’ => 2 即可。在Apache下只需要开启mod_rewrite模块就可以正常访问了,但是Nginx中默认是不支持PATHINFO的,所以我们需要修改 nginx.conf文件。

网上搜了很多方法都不奏效,研究了一天,发现通过以下的配置可以完美支持 ‘URL_MODEL’ => 2 的情况了

location /project/ {
    index  index.php;
    if (!-e $request_filename) { 
        rewrite  ^/project/(.*)$  /project/index.php/$1  last;
        break;
    }
}

location ~ .+\.php($|/) {
    set $script    $uri;
    set $path_info  "/";
    if ($uri ~ "^(.+\.php)(/.+)") {
        set $script     $1;
        set $path_info  $2;
     }
         
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index  index.php?IF_REWRITE=1;
    include /APMServ/nginx/conf/fastcgi_params;
    fastcgi_param PATH_INFO $path_info;
    fastcgi_param SCRIPT_FILENAME  $document_root/$script;
    fastcgi_param SCRIPT_NAME $script;
}

这里先把project下的请求都转发到index.php来处理,亦即ThinkPHP的单一入口文件;然后把对php文件的请求交给fastcgi来处理,并且添加对PATH_INFO的支持。

重启Nginx以后,http://localhost/project/Index/insert, http://localhost/project/index.php/Index/delete 这样的URL都可以正确访问了。

还有一个地方需要注意的是,Nginx配置文件里 if 和后面的括号之间要有一个空格,不然会报unknown directive错误。

[转载]android ExpandableListView实现不同的布局 - 上风华 - 博客园

mikel阅读(863)

[转载]android ExpandableListView实现不同的布局 – 上风华 – 博客园.

最近有一个需求要实现listview的不同布局!因为有好几上header,就想到了ExpandableListView!

这个是我的需求模型:看图(自己画的)

然后百度~google~发帖~总算有点效果了!其他的就不多说了。直接主要代码讲解–

 

主要是适配器的部分:ExpandableListAdapter.jave

 

public class ExpandableListAdapter extends BaseExpandableListAdapter {
    // Client Status
    private String mClient_id;
    private String mClient_name;
    private String mClient_realid;
    private String mClient_totally;
    // Stocks's product
    private String mStocks;
    private String mStocks_name;
    private String mStocks_counts;
    private String mStocks_cost;
    private String mStocks_now;
    private String mStocks_mark;
    // Moreprofit's product
    private String mMoreprofit;
    private String mMoreprofit_name;
    private String mMoreprofit_counts;
    private String mMoreprofit_rate;
    private String mMoreprofit_years;
    private String mMoreprofit_mark;
 
    // Pes's product
    private String mPes;
    private String mPes_projects;
    private String mPes_invest_amount;
    private String mPes_mark;
 
    private Context mContext;
 
    private final int VIEW_TYPE = 3;
    private final int TYPE_1 = 0;
    private final int TYPE_2 = 1;
    private final int TYPE_3 = 2;
 
    private LayoutInflater mLayoutInflater;
 
    // private HandleClick mHandleClick;
    private String[] mProduct_what = new String[] { "xx类产品", "xx收益类产品", "xx类投资" };
    private String[][] mProduct_what_items = {
            { "产品名称", "持有数量", "买入成本", "当前净值", "备注" },
            { "产品名称", "持有数量", "年收益率", "期限", "备注" }, { "项目", "投资金额", "备注" } };
 
    public ExpandableListAdapter(Context mContext) {
        mLayoutInflater = LayoutInflater.from(mContext);
        this.mContext = mContext;
    }
 
    public ExpandableListAdapter(Context mContext, String mClient_id,
            String mClient_name, String mClient_realid, String mClient_totally,
            String mStocks, String mStocks_name, String mStocks_counts,
            String mStocks_cost, String mStocks_now, String mStocks_mark,
            String mMoreprofit, String mMoreprofit_name,
            String mMoreprofit_counts, String mMoreprofit_rate,
            String mMoreprofit_years, String mMoreprofit_mark, String mPes,
            String mPes_projects, String mPes_invest_amount, String mPes_mark) {
        // super();
        this.mClient_id = mClient_id;
        this.mClient_name = mClient_name;
        this.mClient_realid = mClient_realid;
        this.mClient_totally = mClient_totally;
        this.mStocks = mStocks;
        this.mStocks_name = mStocks_name;
        this.mStocks_counts = mStocks_counts;
        this.mStocks_cost = mStocks_cost;
        this.mStocks_now = mStocks_now;
        this.mStocks_mark = mStocks_mark;
        this.mMoreprofit = mMoreprofit;
        this.mMoreprofit_name = mMoreprofit_name;
        this.mMoreprofit_counts = mMoreprofit_counts;
        this.mMoreprofit_rate = mMoreprofit_rate;
        this.mMoreprofit_years = mMoreprofit_years;
        this.mMoreprofit_mark = mMoreprofit_mark;
        this.mPes = mPes;
        this.mPes_projects = mPes_projects;
        this.mPes_invest_amount = mPes_invest_amount;
        this.mPes_mark = mPes_mark;
        this.mContext = mContext;
 
        mLayoutInflater = LayoutInflater.from(mContext);
    }
 
    @Override
    public Object getChild(int arg0, int arg1) {
        return null;
    }
 
    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return 0;
    }
 
    public int getItemViewType(int groupPosition) {
        int p = groupPosition;
        if (p == 0) {
            return TYPE_1;
        } else if (p == 1) {
            return TYPE_2;
        } else if (p == 2) {
            return TYPE_3;
        } else {
            return TYPE_1;
        }
    }
 
    @Override
    public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {
        int type = getItemViewType(groupPosition);
        switch (type) {
        case TYPE_1:
            convertView = mLayoutInflater.inflate(R.layout.item_table, null);
            TextView mProduct_name_1 = (TextView) convertView
                    .findViewById(R.id.product_name);
            TextView mProduct_counts_1 = (TextView) convertView
                    .findViewById(R.id.product_count);
            TextView mProduct_cost_1 = (TextView) convertView
                    .findViewById(R.id.product_cost);
            TextView mProduct_status_1 = (TextView) convertView
                    .findViewById(R.id.product_status);
            TextView mProduct_mark_1 = (TextView) convertView
                    .findViewById(R.id.product_mark);
            //这里是自定义一个子item的,当position==0时显示标题栏
            switch (childPosition) {
            case 0:
                mProduct_name_1.setText(mProduct_what_items[0][0]);
                mProduct_counts_1.setText(mProduct_what_items[0][1]);
                mProduct_cost_1.setText(mProduct_what_items[0][2]);
                mProduct_status_1.setText(mProduct_what_items[0][3]);
                mProduct_mark_1.setText(mProduct_what_items[0][4]);
                break;
 
            default:
                mProduct_name_1.setText("888");
                mProduct_counts_1.setText("888");
                mProduct_cost_1.setText("888");
                mProduct_status_1.setText("888");
                mProduct_mark_1.setText("888");
                break;
 
            }
            break;
 
        case TYPE_2:
            convertView = mLayoutInflater.inflate(R.layout.item_table, null);
            TextView mProduct_name_2 = (TextView) convertView
                    .findViewById(R.id.product_name);
            TextView mProduct_counts_2 = (TextView) convertView
                    .findViewById(R.id.product_count);
            TextView mProduct__rate_2 = (TextView) convertView
                    .findViewById(R.id.product_cost);
            TextView mProduct__years_2 = (TextView) convertView
                    .findViewById(R.id.product_status);
            TextView mProduct_mark_2 = (TextView) convertView
                    .findViewById(R.id.product_mark);
            //这里是自定义一个子item的,当position==0时显示标题栏
            switch (childPosition) {
            case 0:
                mProduct_name_2.setText(mProduct_what_items[1][0]);
                mProduct_counts_2.setText(mProduct_what_items[1][1]);
                mProduct__rate_2.setText(mProduct_what_items[1][2]);
                mProduct__years_2.setText(mProduct_what_items[1][3]);
                mProduct_mark_2.setText(mProduct_what_items[1][4]);
                break;
 
            default:
                mProduct_name_2.setText("888");
                mProduct_counts_2.setText("888");
                mProduct__rate_2.setText("888");
                mProduct__years_2.setText("888");
                mProduct_mark_2.setText("888");
                break;
            }
 
            break;
        case TYPE_3:
            convertView = mLayoutInflater.inflate(R.layout.item_table_p, null);
            TextView mProject_name_3 = (TextView) convertView
                    .findViewById(R.id.project_name);
            TextView mProject_invest_amount_3 = (TextView) convertView
                    .findViewById(R.id.project_invest_amount);
            TextView mProject_mark = (TextView) convertView
                    .findViewById(R.id.project_mark);
             
            //这里是自定义一个子item的,当position==0时显示标题栏
            switch (childPosition) {
            case 0:
                mProject_name_3.setText(mProduct_what_items[2][0]);
                mProject_invest_amount_3.setText(mProduct_what_items[2][1]);
                mProject_mark.setText(mProduct_what_items[2][2]);
                break;
            default:
 
                mProject_name_3.setText("888");
                mProject_invest_amount_3.setText("888");
                mProject_mark.setText("888");
                break;
            }
 
            break;
        }
 
        return convertView;
    }
 
    @Override
    public int getChildrenCount(int groupPosition) {
        return 1;
    }
 
    @Override
    public Object getGroup(int groupPosition) {
        return null;
    }
 
    @Override
    public int getGroupCount() {
        return mProduct_what.length;
        // return 0;
    }
 
    @Override
    public long getGroupId(int groupPosition) {
        return 0;
    }
 
    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {
        int type = getItemViewType(groupPosition);
        switch (type) {
        case TYPE_1:
            convertView = mLayoutInflater.inflate(R.layout.header_table, null);
            TextView mProduct_what_1 = (TextView) convertView
                    .findViewById(R.id.product_what_1);
 
            mProduct_what_1.setText(mProduct_what[groupPosition]);
 
            break;
 
        case TYPE_2:
            convertView = mLayoutInflater
                    .inflate(R.layout.header_table_f, null);
            TextView mProduct_what_2 = (TextView) convertView
                    .findViewById(R.id.product_what_2);
 
            mProduct_what_2.setText(mProduct_what[groupPosition]);
 
            break;
        case TYPE_3:
            convertView = mLayoutInflater
                    .inflate(R.layout.header_table_p, null);
            TextView mProject_what_3 = (TextView) convertView
                    .findViewById(R.id.project_what_3);
 
            mProject_what_3.setText(mProduct_what[groupPosition]);
 
            break;
        }
        return convertView;
    }
 
    @Override
    public boolean hasStableIds() {
        return false;
    }
 
    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return false;
    }
 
}

[转载]把JSON数据载入到页面表单的两种思路(对easyui自带方法进行改进) - p2227 - 博客园

mikel阅读(1208)

[转载]把JSON数据载入到页面表单的两种思路(对easyui自带方法进行改进) – p2227 – 博客园.

背景

项目中经常需要把JSON数据填充到页面表单,一开始我使用easyui自带的form load方法,觉得效率很低,经常在载入数据的时候有假死现象(实际项目中的表单一般都100-200个字段以上),而且不能处理 radio/checkbox的情况。(easyui的思路是把它们都用combo去处理)

思路

问题可以转化为,现在有一堆JSON数据,有一个表单,可能是一一对应的,要把这个数据填写到表单上,一般说来有两种思路

  1. 方案一针对数据,一个个选择元素进行填充
  2. 方案二先选择所有的元素,再针对数据进行填充

到底哪种比较优呢?

测试验证

可能也有人大概想到较优方案,但是对于实事求是的我,还是要写些代码去测试验证

我的测试例子

效果截图:

效果截图

结果

方案二的思路明显要比方案一的优,而且查看原代码后发现,easyui自带的form load方案是以方案一为基准去处理的,再加上一些细节的处理,效率非常的慢.

改进

实际上我们还要处理radio/checkbox的情况,以及处理其他一些细节,故最后整理封装的代码如下

    !function($){
    $.fn.extend({
    /*
    把JSON数据填充进表单,兼容easyui渲染过的表单
    * 20140203 reconstructed by p2227
    * 参数:
    * relateTable:关系表,key-value对象,即JSON数据与表单有不对应时的另外对照表
    * data:要填充的JSON数据
    * callBack:填充完数据后的回调函数,一般说来填充完数据要进行表单验证
    *
    * 用法:
    * $('form').loadForm({data:{key,value}});
    * */
    loadForm:function(conf){
    conf = conf || {};
    conf.relateTable = conf.relateTable || {};
    var rt = conf.relateTable;
    var formObj = this;
    var jsonData = conf.data;
    var newData = {};
    function fill1EasyUI(dom,data1){ //填充值到一个easyUI表单对象上
    //目测针对combobox和datebox,其他表单对象 建议调用 easyUI本身的 form.load方法
    var eDom = $("[comboName='" + dom.name + "']",formObj); //找到easyUI起作用的dom元素(不带name)
    if(eDom.length<=0) return;
    var type = eDom[0].className.match(/(\w*?)-f/); //该dom的类上第一个带 "任意字母-f"的类
    if(type && type.length>0){
    type = type[1];
    if(/datebox/i.test(type)){
    data1 = flitDate(data1);
    }
    if (eDom[type]("options").multiple){
    eDom[type]("setValues", data1.replace(/\s*,\s*/g,",").split(","));
    } else {
    eDom[type]("setValue", data1);
    }
    }else{
    if(eDom.next("span.datebox").length>0){ //for IE7 IE6
    eDom.datebox("setValue", flitDate(data1));
    }
    }
    }
    /* 输入:2012-04-04 00:00:00,2012.2.2,2012/4/7
    * 输出:2012-04-04
    * */
    function flitDate(dStr){
    if(dStr){
    var dreg = /(\d{4})([-\/.])(\d{1,2})\2(\d{1,2})/;
    var sval = dStr.match(dreg)[0].replace(dreg,"$1-$3-$4");
    return sval;
    }else{
    return dStr;
    }
    }
    function fill1Simple(dom,data1){
    if(dom == undefined){ return;}
    if(dom.className.match(/combo-value/i)){
    fill1EasyUI(dom,data1); //按照easyUI的法则填充数据
    }else{
    var $dom = $(dom);
    if($dom.is("span.om-combo>input")){
    $dom.omCombo('value',data1)
    }else{
    dom.value = data1; //普通的html元素赋值
    }
    }
    }
    //把网页上需要额外对照的数据也加到填充数据中
    $.each(rt,function(key,value){
    if(jsonData[key]){
    jsonData[value.replace(/\\*/g,'')]=jsonData[key];
    }
    });
    /* 填充数据的主函数
    *
    * 是用表单为主循环还是数据为主循环快???要做测试。
    * 测试结果:以表单为主循环,必需将EasyUI和一般表单项分开处理
    *
    * 必须要把radio,checkbox放在同一起处理,因为你也不清楚对照表里面的项目是text还是radio
    * */
    var nameflag="";//name标记 如果找到有name相同的 data,那就设置标记,以便循环只运行一次
    $("input[name],textArea[name],select[name]",formObj).each(function(){
    //在实际项目中,有这样的需要:JSON数据key总是大写,也要填充到页面;按表单中属性为fillBack的去填充,故在此进行扩充
    var filldata1 = jsonData[this.name] || jsonData[this.name.toUpperCase()] || jsonData[this.getAttribute("fillBack")];
    if(jsonData[this.name] === 0 || jsonData[this.name.toUpperCase()] === 0 || jsonData[this.getAttribute("fillBack")] === 0){
    filldata1 = 0;
    }
    if(filldata1 === undefined || filldata1 === "" || filldata1 === null|| filldata1 === "null"){
    return;
    }else{
    if(/radio/i.test(this.getAttribute("type"))){
    if(this.name==nameflag){ return; }
    nameflag = this.name;
    $("input[name='"+ nameflag +"'][value=" + $.trim(filldata1) + "]").prop("checked",true);
    }else if(/checkbox/i.test(this.getAttribute("type"))){
    if(this.name==nameflag){ return; }
    nameflag = this.name;
    $("input[name='"+ nameflag +"']").prop("checked",false)//首先要清空原有数据
    $.each(filldata1.split(','),function(k,v){
    $("input[name='"+ nameflag +"'][value='" + $.trim(v) + "']").prop("checked",true);
    })
    }else{
    this.value = "";//首先要清空原有数据
    fill1Simple(this,filldata1);
    }
    }
    });
    if(typeof conf.callBack == "function"){
    conf.callBack(jsonData);
    }
    }
    });
    }(jQuery);

[转载]【Android UI设计与开发】第07期:fragment相关知识-Android UI设计开发资源-eoe Android开发者社区_Android开发论坛 - Powered by Discuz!

mikel阅读(975)

[转载](转)【Android UI设计与开发】第07期:fragment相关知识-Android UI设计开发资源-eoe Android开发者社区_Android开发论坛 – Powered by Discuz!.

由 于TabActivity在Android4.0以后已经被完全弃用,那么我就不再浪费口水继续讲解它了,取而代之的是Fragment。 Fragment是Android3.0新增的概念,Fragment翻译成中文是碎片的意思,不过却和Activity十分的相似,这一篇我花大量的篇 幅来详细的讲解Fragment的介绍和使用方法。

一、Fragment的基础知识介绍

 

1.1概述

 

1.1.1 特性

 

        Fragment是activity的界面中的一部分或一种行为。可以把多个Fragment组合到一个activity中来创建一个多界面

并且可以在多个activity中重用一个Fragment。可以把Fragment任务模块化的一段activity,它具有自己的生命周期,

接收它自己的事件,并可以在activity运行时被添加或删除。

       Fragment不能独立存在,它必须嵌入到activity中,而且Fragment的生命周期直接受所在的activity的影响。例

如:当activity暂停时,他拥有的所有的Fragment都暂停了,当activity销毁时,他拥有的所有Fragment都被销毁。然

而,当activity运行时(在onResume()之后,onPause()之前),可以单独地操作每个Fragment,比如添加或删除它

们。当中执行上述针对Fragment的事务时,可以将事务添加到一个栈中,这个栈被activity管理,栈中的每一条都是一

个Fragment的一次事务。有了这个栈,就可以反向执行Fragment的事务,这样就可以在Fragment级支持“返回”键

(向后导航)。

        当向activity中添加一个Fragment时,它须置于ViewGroup控件中,并且需定义Fragment自己的界面。可以在

layout.xml布局文件中声明Fragment,元素为:<fragment>;也可以在代码中创建Fragment,然后把它加入到

ViewGroup控件中。然而,Fragment不一定非要放在activity的界面中,它可以隐藏在后台为activity工作。

 

1.1.2 生命周期

 

onCreate():

     当创建fragment时系统调用此方法。在其中必须初始化fragment的基础组件们。可参考activity的说明;


onCreateView():

     系统在fragment要画自己的界面时调用(在真正显示之前)此方法,这个方法必须返回fragment的layout的根控

件,如果这个fragment不提供界面,那它应返回null;


onPause():

     大多数程序应最少对fragment实现这三个方法,当然还有其它几个回调方法可应该按情况实现之,所有的声明周期

回调函数在“操控fragment的生命周期”一节中有详细讨论。


下图为fragment的生命周期(它所在的activity处于运行状态)

Activity和Fragment生命周期对比图如下:

两个的生命周期很类似,也息息相关。

 

1.1.3 派生类

 

DialogFragment

    显示一个浮动的对话框。使用这个类创建对话框是替代activity创建对话框的最佳选择。因为可以把fragmentdialog

放入到activity的返回栈中,使用户能再返回到这个对话框。


ListFragment

    显示一个列表控件,就像ListActivity类,它提供了很多管理列表的方法,比如onListItemClick()方法响应click事件。


PreferenceFragment

    显示一个由Preference对象组成的列表,与PreferenceActivity相同。它用于为程序创建“设置”activity。


1.2 范例

 

     写一个读新闻的程序,可以用一个fragment显示标题列表,另一个fragment显示选中标题的内容,这两个fragment

都在一个activity上,并排显示。那么这两个fragment都有自己的生命周期并响应自己感兴趣的事件。于是,不需要再

像手机上那样用一个activity显示标题列表,用另一个activity显示新闻内容;现在可以把两者放在一个activity上同时显

示出来。如下图:

         

       Fragment必须被写成可重用的模块。因为fragment有自己的layout,自己进行事件响应,拥有自己的生命周期和

行为,所以可以在多个activity中包含同一个Fragment的不同实例。这对于让世界在不同的屏幕尺寸下都能给用户完美

的体验尤其重要。比如可以在程序运行于大屏幕中时启动包含很多fragment的activity,而在运行小屏幕时启动一个包

含少量fragment的activity。

        刚才读新闻的程序,当检测到程序运行于大屏幕时,启动activityA,将标题列表和新闻内容这两个fragment都放

在activityA中;当检测到程序运行于小屏幕时,还是启动activityA,但此时A中只有标题列表fragment,当选中一个标

题时,activityA启动activityB,B中含有新闻内容fragment。

 

1.3 创建Fragment

 

         要创建fragment,必须从Fragment或Fragment的派生类派生出一个类。Fragment的代码写起来有些像activity。

它具有跟activity一样的回调方法,比如onCreate(),onStart(),onPause()和onStop()。实际上,如果想把老的程序改为

使用fragment,基本上只需要把activity的回调方法的代码移到fragment中对应的方法即可。


1.3.1添加有界面的Fragment

 

       Fragment一般作为activity的用户界面的一部分,把它自己layout嵌入到activity的layout中。一个要为fragment提

供layout,必须实现onCreateView()回调方法,然后在这个方法中返回一个View对象,这个对象时fragment的layout的

根。

       注意:如果fragment是从ListFragment中派生的,就不需要实现onCreateView()方法了,因为默认的实现已经返

回了ListView控件对象。

       要从onCreateView()方法中返回layout对象,可以从layout.xml布局文件中生成layout对象。为了帮助这样做,

onCreateView()提供了一个layoutInflater对象。举例:以下代码展示了一个Fragment的子类如何从layout.xml布局文件

example_fragment.xml中生成对象。

  • <span style=”font-size:10px;”>public static ExampleFragment extends Fragment {
  • @Override
  • publicView onCreateView(LayoutInflater inflater, ViewGroup container,
  • Bundle savedInstanceState) {
  • returninflater.inflate(R.layout.example_fragment, container, false);
  • }
  • }</span>


复制代码
onCreateView()参数中的container是存放fragment的layout的ViewGroup对象。 saveInstanceState参数是一个Bundle,跟activity的onCreate()中Bundle差不多,用于状态恢复。但是 fragment的onCreate()中也有Bundle参数,所以此处的Bundle中存放的数据与onCreate()中存放的数据还是不同的。 Inflate()方法中有三个参数:  <1> layout的资源ID;  <2> 存放fragment的layout的ViewGroup;  <3> 布尔数据表示是否在创建fragment的layout期间,把layout附加到container上(在这个例子中,因为系统已经把layout插入 到container中了,所以值为false,如果为true会导致在最终的layout中创建多余的ViewGroup)。      下面讲述如何把它添加到activity中。把fragment添加到activity一般情况下,fragment把它的layout作为 activity的layout的一部分合并到activity中,有两种方法将一个fragment添加到activity中:
方法一:在activity的layout.xml文件中声明fragment

  • <?xmlversionxmlversion=”1.0″ encoding=”utf-8″ ?>
  • <LinearLayoutxmlns:androidLinearLayoutxmlns:android=” http://schemas.android.com/apk/res/android”
  • android:orientation=”horizontal”
  • android:layout_width=”match_parent”
  • android:layout_height=”match_parent” >
  • <fragmentandroid:namefragmentandroid:name=”com.android.cwj.ArticleListFragment”
  • android:id=”@+id/list”
  • android:layout_weight=”1″
  • android:layout_width=”0dp”
  • android:layout_height=”match_parent” />
  • <fragmentandroid:namefragmentandroid:name=”com.android.cwj.ArticleReaderFragment”
  • android:id=”@+id/viewer”
  • android:layout_weight=”2″
  • android:layout_width=”0dp”
  • android:layout_height=”match_parent” />
  • </LinearLayout>


复制代码
以上代码中,<fragment>中声明一个fragment。当系统创建上例中的layout时,它实例化每一个fragment,然后调 用它们的onCreateView()方法,以获取每个fragment的layout。系统把fragment返回的view对象插入 到<fragment>元素的位置,直接代替<fragment>元素。注:每个fragment都需要提供一个ID,系统在 activity重新创建时用它来恢复fragment,也可以用它来操作fragment进行其它的事物,比如删除它。有三种方法给fragment提 供ID:  <1> 为Android:id属性赋一个数字;  <2> 为Android:tag属性赋一个字符串。如果没有使用上述任何一种方法,系统将使用fragment的容器的ID。

方法二:在代码中添加fragment到一个ViewGroup        这种方法可以在运行时,把fragment添加到activity的layout中。只需指定一个要包含fragment的ViewGroup。为 了完成fragment的事务(比如添加,删除,替换等),必须使用FragmentTransaction的方法。可以从activity获取 FragmentTransaction,如下:

  • FragmentManager fragmentManager = getFragmentManager();
  • FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();


复制代码
然后可以用add()方法添加一个fragment,它有参数用于指定容纳fragment的ViewGroup。如,Add()的第一个参数是容器 ViewGroup,第二个是要添加的fragment。一旦通过FragmentTransaction对fragment做出了改变,必须调用方法 commit()提交这些改变。不仅在无界面的fragment中,在有界面的fragment中也可以使用tag来作为唯一的标志,这样在需要获取 fragment对象时,要调用findFragmentTag()。 1.3.2 添加没有界面的Fragment         上面演示了如何添加fragment来提供界面,然而,也可以使用fragment为activity提供后台的行为而不用显示fragment的界 面。要添加一个没有界面的fragment,需要在activity中调用方法add(Fragment,String)(它支持用一个唯一的字符串做为 fragment的“tag”,而不是viewID)。这样添加的fragment由于没有界面,所以在实现它时不需要调用实现 onCreateView()方法。        使用tag字符串来标示一个fragment并不是只能用于没有界面的fragment上,也可以把它用于有界面的fragment上,但是,如果 一个fragment没有界面,tag字符串将成为它唯一的选择。获取以tag表示的fragment,需使用方法 findFragmentByTab()。
1.4 Fragment管理      要管理fragment,需使用FragmentManager,要获取它,需在activity中调用方法 getFragmentManager()。可以用FragmentManager来做以下事情:      <1> 使用方法findFragmentById()或findFragmentByTag(),获取activity中已存在的fragment;      <2> 使用方法popBackStack()从activity的后退栈中弹出fragment(这可以模拟后退键引发的动作),用方法 addOnBackStackChangedListenner()注册一个侦听器以监视后退栈的变化;      <3> 还可以使用FragmentManager打开一个FragmentTransaction来执行fragment的事务,比如添加或删除 fragment。       在activity中使用fragment的一个伟大的好处是能根据用户的输入对fragment进行添加、删除、替换以及执行其他动作的能力。提交的一 组fragment的变化叫做一个事务。事务通过FragmentTransaction来执行。还可以把每个事务保存在activity的后退栈中,这 样就可以让用户在fragment变化之间导航(跟在activity之间导航一样)。
可以通过FragmentManager来取得FragmentTransaction的实例,如下:

  • FragmentManager fragmentManager = getFragmentManager();
  • FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();


复制代码
一个事务是在同一时刻执行的一组动作(很像数据库中的事务)。可以用add(),remove(),replace()等方法构成事务,最后使用 commit()方法提交事务。在调用commit()之前,可以用addToBackStack()把事务添加到一个后退栈中,这个后退栈属于所在的 activity。有了它,就可以在用户按下返回键时,返回到fragment执行事务之前的状态。如下例:演示了如何用一个fragment代替另一个 fragment,同时在后退栈中保存被代替的fragment的状态。

  • //创建一个fragment
  • Fragment newFragment = new ExampleFragment();
  • //实例化fragment事务管理器
  • FragmentTransaction transaction = getFragmentManager().beginTransaction();
  • //用新创建的fragment来代替fragment_container
  • transaction.replace(R.id.fragment_container,newFragment);
  • //添加进栈中
  • transaction.addToBackStack(null);
  • //提交事务
  • transaction.commit();


复制代码
解释:newFragment代替了控件ID R.id.fragment_container所指向的ViewGroup中所含的任何fragment。然后调用addToBackStack(), 此时被代替的fragment就被放入后退栈中,于是当用户按下返回键时,事务发生回溯,原先的fragment又回来了。如果向事务添加了多个动作,比 如多次调用了add(),remove()等之后又调用了addToBackStack()方法,那么所有的在commit()之前调用的方法都被作为一 个事务。当用户按返回键时,所有的动作都被反向执行(事务回溯)。
事务中动作的执行顺序可随意,但要注意以下几点:<1> 必须最后调用commit();
<2> 如果添加了多个fragment,那么它们的现实顺序跟添加顺序一致(后显示的覆盖前面的)<3> 如果在执行的事务中有删除fragment的动作,而且没有调用addToBackStack(),那么当事务提交时,那些被删除的fragment就被 销毁了。反之,那些fragment就不会被销毁,而是处于停止状态。当用户返回时,它们会被恢复。
<4> 但是,调用commit()后,事务并不会马上执行。它会在activity的UI线程(其实就是主线程)中等待直到现成能执行的时候才执行。如果必要, 可以在UI线程中调用executePendingTransactions()方法来立即执行事务。但一般不需要这样做,除非有其它线程在等待事务的执 行。     注意:只能在activity处于可保存状态的状态时,比如running中,onPause()方法和onStop()方法中提交事务,否则会引 发异常。这是因为fragment的状态会丢失。如果要在可能丢失状态的情况下提交事务,请使用commitAllowingStateLoss()。 1.5 Fragment与Activity通讯            尽管fragment的实现是独立于activity的,可以被用于多个activity,但是每个activity所包含的是同一个fragment 的不同的实例。Fragment可以调用getActivity()方法很容易的得到它所在的activity的对象,然后查找activity中的控件 们(findViewById())。                有时,可能需要fragment与activity共享事件。一个好办法是在fragment中定义一个回调接口,然后在activity中实现之。例 如,还是那个新闻程序的例子,它有一个activity,activity中含有两个fragment。fragmentA显示新闻标 题,fragmentB现实标题对应的内容。fragmentA必须在用户选择了某个标题时告诉activity,然后activity再告诉 fragmentB,fragmentB就显示出对应的内容。  

MyFragment02.zip

1.39 MB, 下载次数: 17, 下载积分: e币 -5 元

 

MyFragment01.zip

153.64 KB, 下载次数: 22, 下载积分: e币 -5 元