启动正确的viewer应用程序
细描述:
如果某文件(内容)类型被系统支持,那它的viewer可以通过CDocumentHandler作为一个内嵌应用程序来显示。
#include <DocumentHandler.h> // link against commonui.lib #include <apmstd.h> // link against apmime.lib void TTestEmbedApp::EmbedLaunchFileL( const TDesC& aFile ) { // iDocHandler is a pointer to CDocumentHandler if( !iDocHandler ) { // On S60 3rd Edition, CDocumentHandler constructor no longer requires // a CEikProcess pointer as a parameter #ifdef __SERIES60_3X__ iDocHandler = CDocumentHandler::NewL(); #else iDocHandler = CDocumentHandler::NewL( iEikonEnv->Process() ); #endif } TDataType empty; iDocHandler->OpenFileEmbeddedL( aFile, empty ); }
上面这个示例将启动正确的程序来显示该特殊文件。因为使用了一个空白的数据类型(MIME),这样document handler会试图将文件传递到system recognizers以解决文件类型的问题。例如,如果文件(aFile)是一个.txt文件,那记事本程序将被启动,如果文件是.jpg图片,那多媒体程序将被启动,以用来打开该文件。
在S60设备上调用getHeaderField("Location")返回nll的问题
详细描述:
为了获得URL转向,你需要通过getHeaderField方法获得http头中有关location的内容。但这个方法有时无法返回任何值。
这个问题在S60第三版向后不会再发生了。
因此建议如果需要location,在1st/2nd中可用socket来直接操作获取。
如何更换当前主题
详细描述:
S60第三版SDK并未提供给第三方程序一个方法来更换主题。
但我们可以在
Extensions plug-in package for S60 3rd Edition SDK
http://www.forum.nokia.com/info/sw.n...Pack1.zip.html
获取到我们需要的API.
解决方案
如何更换主题:
1、连接Skin Server
#include <AknSSrvClient.h> // link against aknskinsrv.lib RAknsSrvSession skinsSession; User::LeaveIfError( skinsSession.Connect( this ) ); CleanupClosePushL( skinsSession );
2、获取当前skin的package ID
#include <centralrepository.h> // link against centralrepository.lib #include <AknSkinsInternalCRKeys.h> void CMyThemeManager::StoreCurrentSkinIdL() { TAknsPkgIDBuf pidBuf; CRepository* repository = CRepository::NewL(KCRUidPersonalisation ); TInt retVal = repository->Get( KPslnActiveSkinUid, pidBuf ); delete repository; repository = NULL; iOriginalSkinPid.SetFromDesL( pidBuf ); // iOriginalSkinPid is of type TAknsPkgID }
3、获得已安装skin packages列表
CArrayPtr<CAknsSrvSkinInformationPkg>* skinInfoArray = skinsSession.EnumerateSkinPackagesL(); CleanupStack::PushL( skinInfoArray );
4、查询已安装的主题,确认第一个有效新主题
TInt retValue( KErrNone ); if ( skinInfoArray->Count() > 0 ) { for ( TInt i = 0; i < skinInfoArray->Count(); i++ ) { TAknsPkgID pkgId = skinInfoArray->At( i )->PID(); if ( pkgId != iOriginalSkinPid ) { // Activates a complete skin package retValue = skinsSession.SetAllDefinitionSets( pkgId ); if ( retValue == KErrNone ) { SetNewSkinIdL( pkgId ); } break; } } }
5、在Central Repository中存储新主题id
void CMyThemeManager::SetNewSkinIdL( TAknsPkgID aPkgId ) { TAknsPkgIDBuf pidBuf; aPkgId.CopyToDes( pidBuf ); CRepository* repository = CRepository::NewL( KCRUidPersonalisation ); TInt retVal = repository->Set( KPslnActiveSkinUid, pidBuf ); // KPslnActiveSkinLocation value needs to be updated // if the new skin resides on memory card and the // previous one resided in phone memory (and vice versa) delete repository; repository = NULL; }
如何获取功能键上的文字
详细描述:
==描述==
下列代码演示了如何获取当前control pane(CBA)上左、中、右功能键的文字。
我们可以通过CCoeControl::ComponentControl()获取每个功能键的label(CEikLabel),它是功能键上第一个控件。
解决方案
CEikButtonGroupContainer* cba = CEikButtonGroupContainer::Current(); if( cba ) { MEikButtonGroup* buttonGroup = cba->ButtonGroup(); for( TInt pos = 0; pos < 3; pos++ ) { TInt cmdId = buttonGroup->CommandId( pos ); CCoeControl* button = buttonGroup->GroupControlById( cmdId ); if( button && buttonGroup->IsCommandVisible( cmdId )) { CEikLabel* label = static_cast<CEikLabel*>( button->ComponentControl(0) ); const TDesC* txt = label->Text(); } } }
==注意==
1、上述代码总是返回完整的lable text,即使显示在屏幕上的label是缩短过文字的。
2、CEikCommandButton类中提供了Label()方法以完成该项功能,但目前CBA的实现并没支持该类。CEikButtonGroupContainer::CommandButtonOrNull()总是会返回NULL。
如何在S60第三版设备上设置麦克风无声或取消无声
详细描述:
现在我们可以通过Phone Client Extension API(其为S60第三版扩展插件包的一部分)来控制手机麦克风无声或取消无声。
Extensions plug-in package for S60 3rd Edition SDK for Symbian OS, for C++, MR
http://www.forum.nokia.com/info/sw.n...Pack1.zip.html
Extensions plug-in package for S60 3rd Edition SDK for Symbian OS, for C++, supporting FP1
http://www.forum.nokia.com/info/sw.n...g-In_Pack.html
解决方案:
下列代码显示了通过加载PhoneClientExt这个Dll,来构造一个command handler(CPhCltCommandHandler)以设置无声或取消无声。
需要功能:WriteDeviceData
/*** Header file ***/ #include <RPhCltServer.h> // link against PhoneClient.lib #include <PhCltExt.h> // link against PhoneClientExt.lib ... RPhCltServer iPhoneClientServer; RLibrary iLibrary; CPhCltCommandHandler* iPhCommandHandler; /*** Source file ***/ _LIT(KPhoneCltExDllName, "PhoneClientExt.dll"); User::LeaveIfError( iPhoneClientServer.Connect() ); User::LeaveIfError( iLibrary.Load(KPhoneCltExDllName) ); TInt res = iLibrary.Lookup(1)(); CPhCltExtFactory* phCltExtFactory = reinterpret_cast<CPhCltExtFactory*>( res ); iPhCommandHandler = phCltExtFactory->CPhCltCommandHandlerLD(); User::LeaveIfError( iPhCommandHandler->Open( iPhoneClientServer ) ); // Mute the microphone. This should be done inside an active object // (a class derived from CActive) iPhCommandHandler->MuteMicrophone( iStatus, ETrue ); SetActive();
详细描述
如果你试图在S60 3rd Edition, Feature Pack 1设备上用如下语句来初始化OCR(Optical Character Recognition)引擎,将会得到-5 (KErrNotSupported) 错误
static MOCREngineInterface* CreateOCREngineL( MOCREngineObserver& aObserver, const TOcrEngineEnv aEngineEnv, TEngineType aEngineType );
如何演示该问题
我们可以通过编译S60 3rd Edition, Feature Pack 1 SDK中的OCR example application (S60Ex/ORCExample),来演示这个问题。
这个程序可以运行在模拟器上,但在真机运行时就会报告"Initializing OCR Engine Failed: -5"错误。
解决方案
目前暂未有解决方案。尽管S60第三版FP1的SDK文档上已有记载。但第三版FP1设备还尚未支持它。
如何防止editor中出现遮行的现象
详细描述
如果editor的高度不能满足多行文本显示的高度,那最下面一行可能只能显示部分内容,出现遮行的现象。根据实际内容动态的计算editor高度并不一定可行。
例如,插入图片或改变字体大小时,可能上述方法就无效了。这时我们可以通过调用RestrictScrollToTopsOfLines()来解决这个问题(加入EFalse参数):
iEditor->TextLayout()->RestrictScrollToTopsOfLines( EFalse );
注意:
RestrictScrollToTopsOfLines()使用时要小心,在某些情况下鼠标可能会出现在屏幕外面。
如何隐藏status和control panes
详细描述:
描述
我们可以通过隐藏status和control panes来生成一个全屏效果的应用程序。
解决方案
将程序切换为全屏最简单的方法,就是:
SetExtentToWholeScreen();
在(CCoeControl-derived)window-owning控件中,这个方法可以将窗口尺寸调整到整个屏幕大小,程序绘制时即可覆盖status和control panes了。
我们也可准确指名对panes的隐藏的操作。
如何隐藏status pane:
CEikStatusPane* statusPane = CEikonEnv::Static()->AppUiFactory()->StatusPane(); statusPane->MakeVisible(EFalse);
还有一种可选的方法是在程序资源文件中将status pane设置为empty layout.
RESOURCE EIK_APP_INFO { ... status_pane = R_AVKON_STATUS_PANE_LAYOUT_EMPTY; ... }
如何隐藏control pane:
CEikButtonGroupContainer* cba = CEikButtonGroupContainer::Current(); cba->MakeVisible( EFalse );
详细描述:
描述
在S60第二版上,我们可以通过CAPAlbImageUtil类提供的GetThumbnailL()方法获取存放在多媒体文件夹中的图片的缩略图,但在第三版中,Photo Album API已经被新的Media Gallery API取代了,而它并没有提供直接方法来获取图片的缩略图。
解决方案
一般说来,我们可以通过扫描存放图片的文件夹来获取缩略图。
存放缩略图的文件目录一般格式如下:
<DRIVE>:\ Data \ Images \ _PAlbTN \
<DRIVE>:\ Data \ Images \ <YearMonth> \ _PAlbTN \ <R1XR2> \
其中R1和R2是设备指定的,这样同个缩略图可能有多个版本呢。
注意,_PAlbTN目录一般为隐藏。
要在S60第三版上完成这些工作,找出图片缩略图,需要采用递归搜索的方式来处理这些图片目录。
一般来说,缩略图和主图片的名称是一致的,不过有个不一样的后缀,例如,某图片名称为some_picture.jpg,那其缩略图的名字就可能为some_picture.jpg_170x128.
下列这个实例简要的说明图片/缩略图的递归搜索方式:
RFs fs; User::LeaveIfError(fs.Connect()); CleanupClosePushL(fs); // assumes phone memory is used for storing images _LIT( KImagesPath, "C:\\Data\\Images\\" ); // to list known image file(s) and thumbnail(s), use imagename.ext* // to list thumbnail(s) only for a known image, use imagename.ext_* // to list all available images and thumbnails, use *.* _LIT(KImageName,"some_picture.jpg*"); CDirScan* scan = CDirScan::NewLC( fs ); scan->SetScanDataL( KImagesPath, KEntryAttNormal|KEntryAttHidden, ESortNone, CDirScan::EScanDownTree ); FOREVER { CDir* dirlis = 0; TRAPD(error, scan->NextL(dirlis)); if (error || !dirlis) { break; } delete dirlis; FindFile( fs, scan->FullPath(), KImageName ); }; CleanupStack::PopAndDestroy(2); // scan, fs void FindFile( RFs& aFs, const TDesC& aDir, const TDesC& aImageWild ) { CDir* dirList; TFindFile FindObj( aFs ); TInt j = FindObj.FindWildByDir( aImageWild, aDir, dirList ); if( j == KErrNone ) { for ( TInt i = 0; i < dirList->Count() ; i++ ) { TFileName fullname(aDir); fullname.Append((*dirList)[i].iName); // fullname now contains path and name of image/thumbnail } } }
怎么通过程序锁定键盘
我们可以通过RAknKeyLock类来锁定键盘
#include <aknkeylock.h> // link against avkon.lib RAknKeyLock keyLock; if( keyLock.Connect() == KErrNone ) { keyLock.EnableKeyLock(); keyLock.Close(); }
如何检测拨出电话的类型和状态
详细描述:
我们可以使用Publish & Subscribe keys来检测拨出电话的类型和状态。有三个PS keys可用来获取相关属性值。
const TUid KPSUidTelephonyCallHandling = { 0x101f8787 }; const TUint32 KTelephonyCallState = 0x00000004; const TUint32 KTelephonyCallType = 0x00000005;
获取电话类型:
[code cpp]
RProperty iProperty;
iProperty.Get(KPSUidTelephonyCallHandling, KTelephonyCallType, calltype);
[/code]
电话呼叫的类型(TPSTelephonyCallType)值:
EPSTelephonyCallTypeUninitialized = 0, EPSTelephonyCallTypeNone, EPSTelephonyCallTypeCSVoice, EPSTelephonyCallTypeFax, EPSTelephonyCallTypeData, EPSTelephonyCallTypeHSCSD, EPSTelephonyCallTypeH324Multimedia, EPSTelephonyCallTypeVoIP
如何获得呼叫状态信息:
iProperty.Get(KPSUidTelephonyCallHandling, KTelephonyCallState , callstate);
电话呼叫的状态(TPSTelephonyCallState)值:
EPSTelephonyCallStateUninitialized = 0,
EPSTelephonyCallStateNone,
EPSTelephonyCallStateAlerting,
EPSTelephonyCallStateRinging,
EPSTelephonyCallStateDialling,
EPSTelephonyCallStateAnswering,
EPSTelephonyCallStateDisconnecting,
EPSTelephonyCallStateConnected,
EPSTelephonyCallStateHold
PS Keys for Call Status & Indicators API 并非官方S60 SDK的一部分,但可以通过
Extensions plug-in package for S60 3rd Edition SDK for Symbian OS, for C++, MR
http://www.forum.nokia.com/info/sw.n...Pack1.zip.html
获得
注意,Nokia没有承诺这些API在各平台或平台内可以二进制兼容。
如何在S60中动态改变功能键并置之为无效
详细描述:
可以通过如下方法来动态改变功能键:
在.rss文件中定义一个新的CBA资源
RESOURCE CBA r_custom_cba1 { buttons = { CBA_BUTTON { id = ECba1Button1; txt = "Button1"; }, CBA_BUTTON { id = ECba1Button2; txt = "Button2"; } }; }
在.hrh文件中定义一个新的command ID
enum TMyMenuCmdIDs { // ... ECba1Button1, ECba1Button2 };
在代码中调用SetCommandSetL():
#include <eikbtgpc.h> CEikButtonGroupContainer* cba = CEikButtonGroupContainer::Current(); cba->SetCommandSetL(R_CUSTOM_CBA1); cba->DrawNow();
如果要将CBA改变为Options/Cancel,可以参考avkon.rsg中的预先定义:
cba->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_CANCEL);
如果要置之无效的话,可以使用预先定义的资源名R_AVKON_SOFTKEYS_EMPTY
如何在列表框项中响应动作
详细描述:
描述
下面的代码示例演示了如何响应用户选定的列表框项。
这里介绍一下如何生成一个简单列表框 [[How to create a simple listbox]]
我们可以捕捉任何键盘事件借以产生各种响应(如弹出一个对话框),我们可以通过OfferKeyEventL()方法来处理
解决方案
TKeyResponse CMyExampleAppView::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType) { if(aType != EEventKey) { return EKeyWasNotConsumed; } switch(aKeyEvent.iCode) { case EKeyUpArrow: case EKeyDownArrow: { // Forward up and down key press events to the list box return iListBox->OfferKeyEventL( aKeyEvent, aType ); } case EKeyOK: // display an information note when item is selected { _LIT(KFormatMessage, "Selected item: %d"); TInt idx = iListBox->CurrentItemIndex(); TBuf<32> message; message.Format(KFormatMessage, idx); CAknInformationNote* Note = new (ELeave) CAknInformationNote; Note->ExecuteLD(message); return EKeyWasConsumed; } default: break; } return EKeyWasNotConsumed; }
注意要加上这行代码:
AddToStackL( iAppView );