中国领先的IT技术网站
|
|

symbian 杂谈,小技巧

实现了首先以listbox列表的形式列出了收件箱中的所以彩信,选择某一条彩信后可以显示出它的发送端号码和彩信的文本信息;现在我想让它显示发送端号码和彩信图片

作者:佚名来源:|2012-12-24 15:07

Tech Neo技术沙龙 | 11月25号,九州云/ZStack与您一起探讨云时代网络边界管理实践


如何枚举出正在运行的App
结合RApaLsSession和TApaTaskList应该可以做到.
RApaLsSession:
GetAppIcon()
GetAppInfo()
TApaTaskList:
FindApp()
从收件箱读取彩信图片
mmslist实现了首先以listbox列表的形式列出了收件箱中的所以彩信,选择某一条彩信后可以显示出它的发送端号码和彩信的文本信息;现在我想让它显示发送端号码和彩信图片(假设我的彩信都是图片格式);请教两位应该怎么才能实现读彩信图片并显示的功能。
下面是读彩信文本信息的代码,你们参考一下:
void CMmslController::GetMessageL( const TDesC& aItem,
TDes& aMessageText ) const
{
//Read the message Uid from aItem
TUint32 id = 0;
TLex lexer( aItem );
lexer.SkipSpace();
TChar ch( lexer.Get() );
while ( ( ch != ‘\t’ ) && ( ch != 0 ) ) // Finding end of 1.st line
{
ch = lexer.Get();
}
lexer.SkipSpace();
lexer.Val( id, EHex );
if( iCurEntries->Find( id ) == KErrNotFound )
{
return;
}
CMsvEntry* msvEntry = iSession->GetEntryL( id );
CleanupStack::PushL( msvEntry );
const TMsvEntry& msgEntry = msvEntry->Entry();
CBaseMtm* clientMtm = iMtmReg->NewMtmL( msgEntry.iMtm );
CleanupStack::PushL( clientMtm );
clientMtm->SwitchCurrentEntryL( msvEntry->EntryId() );
// An instance of the TDesOverflow derived class used to suppress
// the panic that would be generated if buffer length was exceeded
// in calls to AppendFormat
TOverrideOverFlow noOflo;
// Text is located in iDescription field.
aMessageText.AppendFormat( msgEntry.iDescription, &noOflo );
//aMessageText.AppendFormat( msgEntry.iDetails );
CleanupStack::PopAndDestroy( 2 ); // clientMtm, msvEntry
}

如何让程序在安装后自动运行
如何让一个程序(或是一个server)在安装后自动运行于手机中,这是非常容易的,只需在你的PKG文件中,在包含你的app或exe文件的那行末尾加上“FR,RI”。
“FR”表示“File Run”,而“RI”则表示“Run during Installation”。请注意,务必要先开始rsc,aif,mbm文件的安装,然后才能是APP等(也就是在pkg文件的末尾进行app的安装)
举例:
“\Symbian.1\Series60\Epoc32\release\thumb\urel\MyApp.rsc” -
“!:\system\apps\MyApp\MyApp.rsc”
“\Symbian.1\Series60\Epoc32\release\thumb\urel\MyApp_caption.rsc” -
“!:\system\apps\MyApp\MyApp_caption.rsc”
“\Symbian.1\Series60\Epoc32\release\thumb\urel\MyApp.aif” -
“!:\system\apps\MyApp\MyApp.aif”
“\Symbian.1\Series60\Epoc32\release\thumb\urel\MyApp.app” -
“!:\system\apps\MyApp\MyApp.app”,FR,RI
文件类型和从属关系
下图显示了在一个典型的Symbian程序中各文件的从属关系。

.hrh文件中包含所有要在.rss、.h和.cpp中使用的枚举类型。它们主要使用在应用程序的菜单、工具栏等地方,下面展示了一个典型的例子:
//MyApp.hrh
//
enum{
EMyAppCmdOpenFile = 0×6000,
EMyAppCmdEdit,
};
按照惯例这些命令ID值的范围应该从0×6000开始向上。
.rss文件中是资源文件,这些文件包括所有静态字符串、按钮、菜单和列表等的定义,都使用在应用程序UI中。此外,Nokia Series 60向导还可能生成一个.loc文件,这个文件同.rss文件很相似但只用于描述你程序中的静态字符串,利用它你可以很容易的将程序变成多语言版本。
.rsg是生成的资源文件。它们是在编译时刻由资源编译器产生的,.cpp文件将包含它们以便处理资源。
.mbm是symbian位图文件,它里面可以存储几个位图。
.mbg是在创建.mbm时生成的。这些文件一般包含在那些使用位图的RSS文件中,一个mbg文件包括在.mbm中各位图的ID。
网络通讯中正确显示中文
1。经过对照GB2312/GBK编码表,在程序中定义_LIT8(KTest, “中文测试”);是GB2312/GBK编码
2。直接从输入框取出的字符串,经过按照byte分析并比较中文和unicode对照表,发现是UTF-16LE(Sixteen-bit UCS Transformation Format, little-endian byte order)编码
3,中文对服务器的传输建议统一处理成UTF8编码进行,从对话框获得的也一样处理,服务器需要对应识别过来的字符串并做处理。
如何动态更改CEikLabel 的text
CEikLabel* iLabelStatus;
…..
iLabelStatus = new (ELeave) CEikLabel;
iLabelStatus->SetContainerWindowL( *this );
iLabelStatus->SetTextL( this->iStatusStr );
….
//动态在这里更改
iLabelStatus->SetTextL(iStatusStr);
iLabelStatus->DrawNow();
如果初始化时就无法显示,请对照helloworld代码检查自己label是否设置正确;如果是进度进行中无法显示,请检查cactive是否正确执行,单步DrawNow是否被正确调用。
在listbox中怎么处理所选项的事件
触发事件并不是很复杂的事情,
TKeyResponse CXXContainer::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
{
TInt code = aKeyEvent.iCode;
switch(code)
{
// is navigator button pressed
case EKeyOK:
{
// pass the key press event to view,
// then view will pass it to ui class’s handler
iXXView->ProcessListEvent(iListBox->CurrentItemIndex()) ;
}
return (EKeyWasConsumed);
case EKeyLeftArrow :
case EKeyRightArrow :
return (EKeyWasConsumed);
default:
// Let Listbox take care of its key handling
return iListBox->OfferKeyEventL(aKeyEvent, aType) ;
}
}
这个iXXView的ProcessListEvent()函数就是传入当前用户选择的那个list item的index。


pkg文件中指定多个操作系统版本
pkg file定义了安装文件(sis)的内容,它包括应用程序的UID,一个支持的语言列表,目标产品的UID和打包在sis的一组文件:
; MyGame.pkg
; Specifies an installation file for MyGame
;Languages
&EN
;Header
#,(0×1000ABCD),1,0,0
; Required line for Series 60 devices. Defines the target product
; UID.
(0×101F6F88), 0, 0, 0,
“\epoc32\release\thumb\urel\MyGame.app”-“!:\system\apps\MyGame\MyGame.app”
“\epoc32\release\thumb\urel\MyGame.rsc”-“!:\system\apps\MyGame\MyGame.rsc”
“\epoc32\release\thumb\urel\MyGame.mbm”-“!:\system\apps\MyGame\MyGame.mbm”
“\epoc32\release\thumb\urel\MyGame.aif”-“!:\system\apps\MyGame\MyGame.aif”
“..\MyGame\MyGameSample.wav”-“!:\system\apps\MyGame\MyGameSample.wav”
Product UID定义了应用程序的目标环境,大部分的s60版本是向下兼容的。
参见下表:
Nokia 7650 0×101F6F87
Nokia 3650 0×101F7962
Nokia 9210/9290 0×10005E33
Nokia N-gage 0×101F8A64
Siemens SX1 0×101F9071
Series 60 Platform v0.9 0×101F6F88
Series 60 Platform v1.0 0×101F795F
Series 60 Platform v1.1 0×101F8201
Series 60 Platform v1.2 0×101F8202
Series 60 Platform v2.0 0×101F7960
如果程序需要依据各不同的平台来进行安装,那就可以使用条件语句块来处理,这时pkg里的语句如下:
;
; Files to install
;
IF MachineUID=0×101fb3dd
; Nokia 6600 specific files
“..\MyFiles\FileFor6600.dat”-“!:\system\apps\MyGame\MyData.dat”
ELSEIF MachineUID=0×101f466a
; Nokia 3650 specific files
“..\MyFiles\FileFor3650.dat”-“!:\system\apps\MyGame\MyData.dat”
ELSE
; Files for other devices
“..\MyFiles\FileForOthers.dat”-“!:\system\apps\MyGame\MyData.dat”
ENDIF
就可以生成一个支持多平台的安装文件,除了机器UID外,还有很多属性,如内存和CPU的标识:
注意,机器UID和Product UID是不同的,见下:
Nokia 7650 0×101F4FC3
Nokia 3650 0×101F466A
Nokia 6600 0×101FB3DD
Nokia 9210/9290 0×10005E33
Nokia N-Gage 0×101F8C19
Win32 Emulator 0×10005F62
可以使用如下的代码来找出该设备的机器UID:
#include //and link with hal.lib
TInt machineUid = 0;
HAL::Get(HALData::EmachineUid, machineUid);
如何按字节读取文件
1.RFile::Read()
TInt Read(TDes8& aDes,TInt aLength) const;
Description
Reads specified number of bytes of binary data from file — synchronous overload.
2.Typedef TText8
typedef unsigned char TText8;
如何取出Symbian手机中的信
方法有两个:
1 确定出他们的路径,用文件的方式读;
2 用系统给这两个部分提供的API
通讯录方面的(别人的代码网上找的):
_LIT(KNameLabel,”Name”);
_LIT(KMobileLabel,”Mobile”);
_LIT(KName,”Steve”);
_LIT(KMobile,”+8613900000000″);
// Open the default contacts database:
CContactDatabase* contactsDb = CContactDatabase::OpenL();
CleanupStack::PushL(contactsDb);
// Create a contact card and add some fields:
CContactItem* contact = CContactCard::NewLC();
CContactItemField* field = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldFamilyName);
field->SetMapping(KUidContactFieldVCardMapUnusedN);
field->SetLabelL(KNameLabel);
field->TextStorage()->SetTextL(KName);
contact->AddFieldL(*field);
CleanupStack::Pop();
field = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldPhoneNumber);
field->SetMapping(KUidContactFieldVCardMapTEL);
field->SetLabelL(KMobileLabel);
field->TextStorage()->SetTextL(KMobile);
contact->AddFieldL(*field);
CleanupStack::Pop();
// Add the new contact to the database and set it as the own card:
contactsDb->AddNewContactL(*contact);
contactsDb->SetOwnCardL(*contact);
CleanupStack::PopAndDestroy(2); // contact contactsDb
短信的:
CMsvEntry或 CMsvServerEntry
怎么使用BUTTON 类创建一个 BUTTON
S60里面好像没有BUTTON的类吧
1.好像没有必要做BUTTON,触发事件使用MENU就可以了
2.如果非要做的话,可以尝试的下面的简单方法
2.1 使用一个LABEL(设置一下边框属性可以使这个LABEL像一个所谓的BUTTON)
2.2 可以在该LABEL的所处CONTAINER的
OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType);
处理KEY事件(判断该LABEL拥有FOCUS)
图标资源的读取与储存结构
可以在AknView类中定义如下的图标数组进行储存图标数据结构,这种结构有图表位图和蒙板(mask)
CArrayPtr* iIconArray;
具体实现方法:
iIconArray->AppendL(CEikonEnv::Static()->CreateIconL(iMbmFile, EMbmFile1, EMbmFile1_mask));
在需要贴图标的地方用这个数组句柄引用即可
一段左软键菜单的控制代码
要求:1点了左软键之后,就相当与点了ok键。
2 :把左软键菜单的地方由option改为select
// My.rss
RESOURCE EIK_APP_INFO
{
menubar = r_bmpmanip_menubar;
// cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT;
cba = R_AVKON_SOFTKEYS_SELECT_BACK; // see “epoc32\include\avkon.rsg”
}
// MyAppUi.cpp
void CMyAppUi::HandleCommandL(TInt aCommand)
{
switch(aCommand)
{
case EAknSoftkeySelect: // see “epoc32\include\avkon.hrh”
{
// left softkey is pressed…
}

}
}
}
如何在CAknGrid上绘制背景图
从CAknGrid派生自己的子类,然后自己draw,如:
void CYourGrid:raw(const TRect& aRect) const
{
CWindowGc& gc = SystemGc();
gc.DrawBitmap(aRect, aYourBitmap);
CAknGrid:raw(aRect);
}


两种从资源文件中读取常量的方法
第一种 是老的方法了 要先 #include 才可以用
TBuf<64> buf;
CEikonEnv::Static()->ReadResource(buf,R_APP_LABEL);
R_APP_LABEL 就是我们在资源文件中定义的常量
第二种 新方法 要先 #include
HBufC* buf;
buf=StringLoader::LoadLC(R_APP_LABEL);
在此之前要求先把资源文件给加进来噢, 格式 #include < 项目名.rsg>
如何取得imei
#ifndef __WINS__
TPlpVariantMachineId imei;
PlpVariant::GetMachineIdL(imei);
aImei.Copy(imei);
#else
如何在Series 60窗体上绘制标签
这是一种在Series 60窗体上显示标签的方法。你可以在电量图标或信号图标旁边显示一个标签,为此需要用程序实现。我使用了从CCoeControl继承的CIndicatorIcon 这个类。你需要象这样创建ConstructL():
void CIndicatorIcon::ConstructL()
{
iMyWindowGroup = RWindowGroup(iCoeEnv->WsSession());
User::LeaveIfError(iMyWindowGroup.Construct((TUint32)&iMyWindowGroup));
iMyWindowGroup.SetOrdinalPosition(0, ECoeWinPriorityAlwaysAtFront);
iMyWindowGroup.EnableReceiptOfFocus(EFalse);
CreateWindowL(&iMyWindowGroup);
// 默认设置指示标签静止
SetIndicatorIconL(EIndicatorIconAppActive);
ActivateL();
}
在ConstructL()中,我调用了另一个函数 SetIndicatorIconL()设置标签:
void CIndicatorIcon::SetIndicatorIconL(TIndicatorIcon aIndicatorIconType, TBool aRedraw)
{
switch(aIndicatorIconType)
{
case EIndicatorIconEmpty:
iIndicator = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_empty);
iIndicatorMask = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_empty_mask);
break;
case EIndicatorIconAppActive:
iIndicator = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_bt_connect_on);
iIndicatorMask = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_bt_connect_on_mask);
break;
case EIndicatorIconAppInactive:
iIndicator = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_bt_audio);
iIndicatorMask = CEikonEnv::Static()->CreateBitmapL(KSysIconFile, EMbmAvkonQgn_prop_bt_audio_mask);
break;
default:
break;
}
SetRect(TRect(TPoint(KIndicatorPosX, KIndicatorPosY),iIndicator->SizeInPixels()));
// 如果 aRedraw == ETrue 从新绘制画布
if(aRedraw)
{
DrawNow();
}
}
你需要跳过CCoeControl的Draw()函数代码如下 :
void CIndicatorIcon::Draw(const TRect& aRect) const
{
CWindowGc& gc = SystemGc();
gc.Clear();
gc.SetBrushStyle(CGraphicsContext::ENullBrush);
gc.BitBltMasked(TPoint(aRect.iTl.iX, aRect.iTl.iY),
iIndicator,
TRect(TPoint(0, 0), iIndicator->SizeInPixels()),
iIndicatorMask,
ETrue);
}
现在把这些行加入到程序AppUi类的ConstructL()中:
iIndicatorIcon = CIndicatorIcon::NewL();
// 下一行将画标签并绘制到屏幕上
iIndicatorIcon->SetIndicatorIconL(CIndicatorIcon::EIndicatorIconAppInactive, ETrue);
判断E盘是否可用
TDriveInfo driveInfo;
TInt error = fs.Drive(driveInfo, EDriveE);
User::LeaveIfError(error);
if (driveInfo.iDriveAtt == KDriveAbsent)
{
// drive E is absent
}
Reference: “How to retrieve drive and volume information”
http://www.symbian.com/developer ... eExample.guide.html
读取symbian上文件的例子
RFile igpFile;
RFs fs;
TInt aSeek = 0;
TInt aFileSize;
TBuf16 igpName16;
TParse parse ;
parse.Set(CEikonEnv::Static()->EikAppUi()->Application()->AppFullName(), NULL, NULL);
TBuf16<128> igpFullName ;
igpFullName.Copy (parse.DriveAndPath()) ;
igpFullName.Append (_L(”dice1.igp”));
fs.Connect();
// Write to file for later usage
igpFile.Open( fs,
igpFullName,
EFileRead | EFileStream );
igpFile.Seek( ESeekEnd, aSeek );
aFileSize = aSeek;
aSeek = 0;
igpFile.Seek( ESeekStart, aSeek );
aFileBuffer = HBufC8::NewL( aFileSize );
igpFile.Read( aFileBuffer->Des (), aFileSize );
igpFile.Close();
fs.Close();


正确响应FORM的OK和BACK事件
TBool CMyForm::OkToExitL ( TInt aButtonId )
{
if (aButtonId == EAknSoftkeyOk )
{
…..
}
else if( aButtonId == EAknSoftkeyBack )
{
……
}
}
流读取windows编写的txt文件
// Open file1
_LIT(KMyFile,”c:\\documents\\file1″);
RFile myFile;
User::LeaveIfError(myFile.Open(fs,KMyFile,EFileShareExclusive|EFileWrite
));
// Write to current file position: start of file
_LIT8(KWriteBuf,”write data”);
myFile.Write(KWriteBuf);
// Read from position 0: start of file
TBuf8<6> readBuf1;
myFile.Read(0,readBuf1); // readBuf1 is now “write ”
// Read from current position
TBuf8<4> readBuf2;
myFile.Read(readBuf2); // readBuf2 is now “data”
得到CEikEdwin输入的数据
TBuf<128> buf;
CEikEdwin* edwin = STATIC_CAST(CEikEdwin*, Control);
edwin->GetText(buf);
Symbian生成随机数的方法
无论开发什么程序,尤其是类似纸牌类游戏和拼图类,以及俄罗斯方块之类的游戏,
随机数发生器是必不可少的。标准c语言里面有seed()和rand()用来生成种子和数值
在symbian平台下面,用什么方法呢?下面就是一个例子
TTime theTime( KAknExNoteInitializeTime );
theTime.UniversalTime();
TInt64 randSeed( theTime.Int64() ); // 采用时间初始化随机数种子
TInt number( Math::Rand( randSeed ) % KAknExNoteRandomNumberRange ); // 这里就是调用了
生成的结果放在number中。
Symbian中把字符串变成数字的方法
我们知道C语言中又很方便的函数,很多种方法可以把字符串变成数字,
比如
char * p = “100″ ;
int a;
a = atoi(p) ; // 此时a的值就是100了。
或者用这种办法也可以,就是慢点:
sscanf(p, “%d”, &a) ; 这样也可以达到同样的效果。
但是symbian开发环境中遇到这种情况,我们该怎么做呢?
我们可以考虑采用TLex类,来实现同样的功能。
TBufC buffer = _L(”124″) ;
TLex8 lex;
TInt value;
lex.Assign((const unsigned char*) buffer.Ptr());
if(lex.Val(value) == KErrNone) {
// 证明转换没有问题,你可以在value中使用buffer里面的字符串格式的数据了。
}


Symbian应用程序中如何备份和载入
在S60 3rd中,默认情况下将不被支持。支持备份将使你的应用程序用户界面更加友好,做备份的用户(或者只有一小部分)期望自己的所有应用程序可以被备份。让我们来满足这些用户的需求,大多数情况下,这是非常容易的……
使应用程序可以备份文件的另一个原因是Symbian Signed。它不是一个强制的,但是,你的应用程序没有意识到备份的问题,你必须通知Test House 或者他们可能认为你的备份功能失败。再说一次,大多数情况下,备份是非常简单的。
程序备份基础
如果你想使应用程序具备备份功能,以下是最起码要做到的(也就是说,只能执行和相应的资源文件,没有数据可以被支持):
1. 写一个backup_registration.xml文件,内容如下:
CODE:

2. 添加它到你的PKG文件
CODE:
“backup_registration.xml”-”!:\private\\backup_registration.xml”
添加私有数据到你的备份文件
另外一个常见的需求就是保存数据内容到你的私有文件夹(位置在\private\)。添加以下申明到你的backup_registration.xml 文件中(使用标签):
CODE:
你也可以保存所有内容到”nobackup” 私有目录:
CODE:
你也可以指定些文件代替文件夹:
CODE:
添加公共文件到备份文件中
在前面的内容中,“\”目录被指定为应用程序的私有目录。如何保存那些在私有数据以外的数据呢?这个也很简单,你可以使用另外的一个XML标签。可以用
标签来替换
,路径相对于你手机的根目录(不需要指定驱动器):
CODE:
所知到的Bug
不幸的是,包含一些bug会影响备份和重新载入特性:
1. 位于C:\System 的数据不被支持:非工作区,除非指定数据到其他位置……
2. 使用开发证书(developer certificate),应用程序的备份和载入会失败。这一点是很可怕的:你测应用程序的试备份恢复仅仅只能在你注册了自产生证书(self- generated certificate)的时候。如果你使用开发证书(developer certificate)是不行的,你的应用程序将能够备份,但是恢复的时候会失败。
作者不能计算在第二点上到底花费了多少时间,作者说至少花费了一个下午的时间去尝试用开发证书(developer certificate)测试它。
Symbian程序中的观察者模式
Symbian程序中的观察者模式
在这个站点上有很多关于Symbian程序外表的文章,很少有关于架构设计的观点。在以下的文中中,我介绍一下在Symbian应用程序中的观察者模式,我会用一些有意义的类名来代表整个Symbian程序的设计流程。在这个应用程序中,将告诉你在一个Symbian程序中如何使用 Engine和前台,UI接口,和用户直接的交互。在文章中,我已经给了一种解决的方案。在接下来的文章种,我将介绍另外一种方法,通过内嵌类。让我们开始应用程序的引擎类和它的观察者,我们创建了一个观察者接口 MObserver,定义如下:
CODE:
class MObserver
{
public:
virtual void CallbackFunction1() = 0;
};
接口,它有一个纯虚函数,它必须被一个创建类实现。在我们的例子中,Engine(引擎类)将实现它:
CODE:
class Engine : public MObserver
{
public: Engine(CAppUi& aAppUi);
void CallbackFunction1();//From MObserver
void DoSomething();
Subject& GetSubject();
private: Subject* iSubject;
CAppUi& iAppUi;
};
从名字可以清晰的看出,Engine类有一个Subject类,他是实际上在后台工作的类;CAppUi 类是核心与视图的用户接口。引擎创建一个Subject类,通常在Symbian程序中,CAppUi 类是通过veiw类表现数据到用户接口的(UI)。
Subject类申明如下:
CODE:
class Subject
{
public:
Subject(MObserver& aObserver);
void DoSomething();
private:
MObserver& iObserver;
};
很明显,Subject类链接了它的观察者iObserver。Symbian程序在一般情况下,在后台通过一些异步函数,Subject类将继承至 CActive类而工作。这里有一个 DoSomething()将调用一些异步函数,这个函数也将调用MObserver中的CallbackFunction1()。 CallbackFunction1 函数将更新AppUi 应用程序或引擎和UI中相关的表现形式。因此让我们来看看CAppUi类的申明:
CODE:
class CAppUi
{
public:
CAppUi();
Engine& GetEngine();
void PrintToUI(char* msg);
virtual ~CAppUi();
private:
Engine* iEngine;
};
AppUi类的作用是,创建应用程序的引擎。记住,应用程序和Engine已经循环的引用,整个的流程如下:
AppUi将创建引擎;
Engine创建Subject;
AppUi通过一些菜单命令调用Engine中的DoSometing函数;
Engine将委派一些任务通过Subject类的DoSometing函数;
Subject的DoSometing函数将通知通过CallbackFunction1创建Observer;
Subject的DoSometing函数看上去如下:
CODE:
void Subject::DoSomething()
{ //Call the Asynchronous function
//Now Notify the Observer regarding this.
iObserver.CallbackFunction1();
}
Observer中的这个回调函数将打印AppUi中消息通过函数PrintToUi。这个函数将呈现从Engine得到的消息到Veiw中。
希望这篇文章能讲清楚一些Symbian入门者对于如何使用UI的疑惑。
IMPORT_C关键字释义
在Symbian程序中我们经常会看到IMPORT_C这个关键字,它是C:\Symbian\8.0a\S60_2nd_FP2_SC\epoc32\include下e32def.h文件里面定义的一个宏.
原定义如下:
#define IMPORT_C __declspec(dllexport)
那么__declspec(dllexport)又是什么东东呢?
先看代码:
以下是在dev-c++里建立自已的dll时的dll.h里面的代码,这里面有一个_declspec(dllexport)
#ifndef _DLL_H_
#define _DLL_H_ //防重复定义
#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */
DLLIMPORT void HelloWorld (void);
#endif /* _DLL_H_ */
上面代码里面的_delcspce(dllexport)被定义为宏,这样可以提高程序的可读性!这个的作用是将函数定义为导出函数,也就是说这个函数要被包含这个函数的程序之外的程序调用!本语句中就是:void Helloword(void)
摘自msdn:在 32 位编译器版本中,可以使用 __declspec(dllexport) 关键字从 DLL 导出数据、函数、类或类成员函数。__declspec(dllexport) 将导出指令添加到对象文件
若要导出函数,__declspec(dllexport) 关键字必须出现在调用约定关键字的左边(如果指定了关键字)。例如:
__declspec(dllexport) void __cdecl Function1(void);
若要导出类中的所有公共数据成员和成员函数,关键字必须出现在类名的左边,如下所示:
class __declspec(dllexport) CExampleExport : public CObject{ … class definition … };
生成 DLL 时,通常创建一个包含正在导出的函数原型和/或类的头文件,并将 __declspec(dllexport) 添加到头文件中的声明。若要提高代码的可读性,请为 __declspec(dllexport) 定义一个宏并对正在导出的每个符号使用该宏:
#define DllExport __declspec( dllexport )
__declspec(dllexport) 将函数名存储在 DLL 的导出表中。


如何让程序支持皮肤功能


标题: Form UI component要支持皮肤
设备, 软件 版本: S60 2nd Edition, FP3, Nokia N70, Nokia N90 S60 3rd Edition
说明:
在S60第二版,FP3设备上使用CAknForm UI component时,如果程序不支持皮肤,则该控件将无法正确绘制。
详细描述:
如果一个运行在S60第二版,FP3设备上的程序,使用了form(CAknForm),那它必须要支持皮肤,否则程序将无法绘制该表单。
我们在程序UI类(从CAknAppUi中继承)的构造函数ConstructL()中通过传递EAknEnableSkin参数来让程序支持皮肤功能。
void CMyAppUi::ConstructL()
{
BaseConstructL(EAknEnableSkin);

}
这个form布局的问题在S60第二版FP3模拟器上不会出现。
情景重现:
比较一下设置及不设置EAknEnableSkin情况下我们使用CAknForm的情况。
这个我们可以通过使用CAknForm类的SDK示例程序(如Form, Popupfield example)来具体。
在S60第二版,FP2设备上获取电量状态
标题: 在S60第二版,FP2设备上获取电量状态
设备, 软件 版本: S60 2nd Edition, FP2
说明:
直到S60第二版,FP2,电量值都是通过RSystemAgent中如systAgent.GetState(KUidBatteryStrength)获得的,但现在方法返回错误代码-19。那在S60第二版,FP2设备上是否有其他方法可供使用呢?
解决方案:
这些值在新版中确实有所改变,而公开文档中却并未写上。
你可以通过使用下列值来查询电量状态。
Code:
// The current battery status information
const TInt KUidBatteryCStatusValue = 0×100052D8;
const TUid KUidBatteryCStatus = {KUidBatteryCStatusValue};
enum TSABatteryCStatus
{
ESACBatteryOk,
ESACBatteryLow,
ESACBatteryEmpty,
ESACPowerOff
};
// The amount of battery bars
const TInt KUidBatteryBarsValue = 0×100052D3;
const TUid KUidBatteryBars ={KUidBatteryBarsValue};
enum TSABatteryBars
{
ESABBars_0,
ESABBars_1,
ESABBars_2,
ESABBars_3,
ESABBars_4,
ESABBars_5,
ESABBars_6,
ESABBars_7
};
检查离线模式
在S60第三版中,我们通过读取Centrol Repository中的电话设置来检查离线模式是否启动。
要获得情景模式的设置,只有对Central Repository进行调用才行:
Code:
#include
#include
CRepository* cr = CRepository::NewLC( KCRUidProfileEngine );
TInt value;
// Get ID of current profile
User::LeaveIfError( cr->Get( KProEngActiveProfile, value ) );
// Check value to determine the active profile
if ( value == 5 )
{
// current profile is the offline profile
}
// …
要了解更多关于Profile Engine的信息,可阅读SDK的帮助文档和“Profiles Engine Active Profile Settings API.”
第三版中的ETel库
受争议的ETel库在第三版中已经去掉了,去掉的库包括ETel Core和ETel MM(etel.h和etelmm.h),在第三版中之后一个公共的电话API将被提供那就是CTelephony API(etel3rdparty.h和etel3rdparty.lib)
安全共享数据及数据库加密
从Symbian OS v9.x后就不再提供数据库加密机制了,保护你数据库不被其他程序访问的唯一方法就是将数据库文件存储在你的私人数据空间。不过这样其他程序也就没法访问到它了。
Symbian OS v9.x中所介绍的安全共享数据库的方法为,通过data caging机制保护并共享数据。
数据库是通过DBMS client-serve API来生成并被访问的。数据库文件被存储在DBMS server的data cage文件夹中。DBMS server根据与此数据库预先关联的安全法则允许其他客户端程序去访问它。这种安全法则可以规定客户端只能具有ReadDeviceData能力。为了向数据库写入东西,客户端得具有WriteDeviceData能力,和一个给定的Secure ID(SID)
不幸的是,安全法则目前只能存放在Z盘中。这意味着第三方开发者无法定义或安装他们自己的安全法则。同样,当第三方程序需要使用一个好的方法来同享数据库时,也没有能使用的预先配置的法则。
如果你的程序需要访问一个共享数据库,那下列选项是可以考虑的:
将数据库存放在一个共同目录下(如果不需要考虑安全性问题)
为你的服务提供一个API以访问存储在自己
If for your applications require access to a shared database, the options available are
- share a database stored in a public folder (if there are no security concerns)
- write your own server that provides an API to access a database stored in its own data cage folder.
If data encryption needs to be used, you must provide your own encryption mechanism in both cases.
S60第三版中对messaging components(MTM)的性能需求
S60第三版上,因为平台安全性的考虑,对公共DLL有很多要求。
这会在下列方面影响messaging component(MTM)的开发使用:
所有public-size MTM component都需要“ALL-TCB”属性,因为他们要被其他public-side application所加载(这些程序拥有设置其的能力)
Public-side MTM component主要为:Client MTM, UI MTM, 以及UI Data MTM.
而private-side MTM component既Server MTM,要和加载进程拥有一样的能力。你的server-side MTM component应该拥有下列能力:
ReadDeviceData, WriteDeviceData, ProtServ, NetworkControl, NetworkServices, LocalServices, ReadUserData.
Given these heavy capability requirements any MTM implementation has to go through the Symbian Signed process and will need to assign all needed UIDs from the protected UID range (0×00000000 - 0×7FFFFFFF).
实现Tab页
carbide.c++编程非常考验人的是所有的资源必须自己定义,然后在程序中引用这些自定义的资源。这让习惯了windows可视化编程的程序员非常的头痛。不过也好,这样更能让我们清楚地了解到symbian资源文件的结构和调用方法。
实现Tab页,首先要在.rss文件中定义Tab页所需要的资源,其中包括Tab页的数量,Tab页的Title。然后在***AppUI.cpp 文件的construct函数中生成该Tab页。其次,还要在***container.cpp文件的按键处理事件中编写相关的代码,以实现Tab页的切换。
带完整键盘的S60第三版设备上的按键映射
设备, 软件 版本: S60 3rd Edition
说明:
在一些S60第三版手机上有完整的键盘,其中一些键值只有通过FEP模式下编辑框才能获得
详细描述:
在Nokia E61以及E70等带全键盘的机器上运行的程序时,如果要捕捉CCoeControl派生类下的按键事件时,在FEP模式下的编辑框中是无法获取同样键值的(通过TKeyEvent::iCode)。
这是因为QWERTY键盘的映射是依赖于当前的语言和输入模式的。例如,在Nokia E61上,CCoeControl派生类在数字键盘被按下时总是获得1,2,3。。。。而只有在FEP模式下的编辑框中(如CEikEdwin)它才能获取字母键”r”,”t”,。。。等。
注意scan codes(TKeyEvent::iScanCode)是不会受当前语言或输入模式影响的。
解决方案:
应用程序在处理文本输入时,应该使用表示准的Avkon编辑框控件。


S60第三版SDK中MMF框架API的问题
详细描述:
S60第三版SDK中缺少MMF Controller Framework头文件和库,这样的话,我们将不会搜索到关于MMF的信息和媒体格式插件,这将导致一些MMF的相关引用。如 CVideoRecorderUtility在构造时就需要Controller和格式UIDs。
解决方案:
MMF Controller Framework的支持将有望在s60第三版后面加入
SymExpat 面向OS 9.x的端口
起初我认为把SyEpxpat应用于OS 9.x的端口将会引起一系列的变化。然而,结果却并非如此。 最简单的修订是针对xmlparse.c的. 看起来expat 开发人员把返回代码枚举和错误代码枚举混为一谈,因此对于主要expat 源编码来说更改它就足够了。
一个稍微有点欺骗性的问题是由GCCE带来的。看起来其似乎对XMLCALL进行了一些定义。似乎 GCCE认为它支持微软扩展,但实际上只在有些情况下可行。
我认为这一问题的根源是_MSC_EXTENSIONS。因此为了修订它,首先,我们需要确定expat-config.h 是在源文件中expat.h文件之前定义的,之后便是定义XML调用并且停止运行expat-external.h使之恢复默认设定。
唯一的改变是让SyExpat.cpp 文件在包含expat.h 之前包含expat-config 文件,因为它设立了一套定义,并具体说明了功能是怎样输出的,同时由此选出那些并没有被正确处理的输出申明。
因此,我们仅定义了空的XML调用并将其补充进入编译器主题。更多信息请查看expat_config.h。
现在便可为OS9.x充分的建立SyExpat, 并且仍旧保留其向后的兼容性。不幸的是我遇到一个关于Carbide.vs 和标准C库的糟糕问题,详细情况如下:
http://discussion.forum.nokia.com/forum/showthread.php?t=75575 因此,即使项目在维护期,目前看起来需要解决的重要问题首先是对OS9相关主题进行修订。
由HelloWorld想到的
对于一个symbian GUI应用程序,必须实现四个类:
(1)应用程序类(HelloWorldApp.cpp)
该类用于定义应用程序的属性,还用于生成新的空白文档,以及传递UID信息。
(2)文档类(HelloWorldDocument.cpp)
该类表示应用程序的数据模式,负责保存和恢复应用程序的数据,以及创建应用程序的用户UI接口。
(3)应用程序UI接口类(HelloWorldAppUi.cpp)
该类是完全不可见的,它创建一个应用程序视图,并且处理菜单等32位命令的相应手段。
(4)应用程序视图类(HelloWorldContainer.cpp)
这是一个具体的控件类,它的目的是在屏幕上显示应用程序数据,并允许用户交互。
通过这几个类的作用,可以得出一个程序的启动过程如下:
HelloWorldApp.cpp—–>HelloWorldDocument.cpp——>HelloWorldAppUi.cpp——>HelloWorldContainer.cpp
周期类: Cperiodic
CPeriodic* iPeriodicTimer;
iPeriodicTimer = CPeriodic::NewL( CActive::EPriorityStandard );//这条语句一般在ConstructL()中
void CGraphicsAppView::StartTimer()//开始启动时钟
{
if ( !iPeriodicTimer->IsActive() )
{iPeriodicTimer->Start( 1, 1,
TCallBack( CGraphicsAppView::Period, this ) );//TcallBack是一个方法回调函数,从使用来看,他只能回调类中的静态方法。
}
}
TInt CGraphicsAppView::Period( TAny* aPtr )//周期启动函数,注意,这是个静态函数,但static只在头文件中才做了申明。
{
( static_cast( aPtr ) )->DoPeriodTask();
return ETrue;
}
void CGraphicsAppView::DoPeriodTask()//周期真正在做的事情
{
// Update the screen
CWindowGc& gc = SystemGc();
gc.Activate( *DrawableWindow() );
UpdateDisplay();///////////////////这个函数是关键的关键
gc.Deactivate();
}
void CGraphicsAppView::StopTiem()//停止时钟
{
if ( iPeriodicTimer->IsActive() )
{
iPeriodicTimer->Cancel();
字符串类:
HBufC* textResource;
//两种字符串附值方法
textResource = StringLoader::LoadLC( R_HEWP_TIME_FORMAT_ERROR );
textResource =iEikonEnv->AllocReadResourceL(R_EXAMPLE_TEXT_HELLO);
TBuf<32> timeAsText;
timeAsText = *textResource;
编译命令
1. bldmake bldfiles
2. abld build wins udeb
3. abld makefile vc6
4. epoc
5. abld reallyclean
有了以上的基础,我们就可以编译sis文件了. 一共分为2步:
1. 进入到/group目录下, 输入bldmake bldfiles, 和以前讲过的作用一样, 然后: abld build thumb urel, “abld build”是编译命令, “thumb urel”是编译目标, 一般手机的格式都是thumb, 用命令行为windows编译的话,就可以用 abld build wins udeb (urel). “udeb” 代表debug build, “urel”代表release build, 前者用于开发,后者用于发行。
2. 进入/sis, 输入makesis Helloworldbasic.pkg, 然后Helloworldbasic.sis就被创建了。
怎么在一个view类中响应按键消息
TKeyResponse CAknExEditorContainer9::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
{
return iListBox->OfferKeyEventL(aKeyEvent, aType);
}
Panic的含义
原意是报错,异常,紧急状态。
也就是程序的意外情况,symbian中用于弹出系统的异常对话框,并结束程序。
举例
Most of the functions here return void because if they fail the server will panic the client.
大部分函数都返回void值,这是因为如果他们出错了,那server端会通知client出了意外情况。
S60和Symbian的头文件
#include
时会直接到系统包含路径下去寻找aknappui.h
(这不同于#include “aknappui.h”,还会到用户包含路径中去寻找)。
系统包含路径也就是在工程的.mmp文件中定义的:
SYSTEMINCLUDE \epoc32\include,
其真实的路径也就是:
%EPOCROOT%\epoc32\include,
在你的机器上如果系统变量EPOCROOT=\Symbian\9.1\S60_3rd\,那么它就是\Symbian\9.1\S60_3rd \Epoc32\include,也就是说本来是应该能找到的,但是依据你的错误,此时你的EPOCROOT=\Symbian\Symbian8.1b \bin\bak\,你可以试试把EPOCROOT设置成\Symbian\9.1\S60_3rd\。
另外工程文件夹最好放在%EPOCROOT%\Series60Ex下。
通过Uid来获取应用程序的路径
TFileName f = EikAppUi( ).Application( )->AppFullName( );//得到当前应用的全路径名
TParse parse;
parse.Set( f,NULL,NULL );
parse.DriveAndPath( );//得到最终的纯路径

【编辑推荐】

  1. Symbian“猝死”!
【责任编辑:冰凝儿 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

软件设计师考试全真模拟试题及解析

本书是按照全国计算机技术与软件专业技术资格(水平)考试《软件设计师考试大纲》的要求,参照《软件设计师教程》及近年来考试试题编写的,...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊
× CTO训练营(深圳站)