您的位置:首页 > 其它

Symbian中大段文本显示控件,使用系统滚动条,可自动换行

2010-02-21 11:19 483 查看
有些时候我们想显示一个大段的文本内容,但是我们去找不到合适的控件。或者觉得系统控件太单调,无法满足需求是,我们需要自定义控件,来实现我们自己想要的效果。我这个自定义控件实现了,文本的自动换行,添加了系统的滚动条和一些简单的文本显示,

废话不多说了,直接贴出代码吧!!

.h文件

/*
============================================================================
Name : TextDisplay.h
Author : Barrett
Version :
Copyright : Your copyright notice
Description : CTextDisplay declaration
============================================================================
*/

#ifndef TEXTDISPLAY_H
#define TEXTDISPLAY_H

// INCLUDES
#include <COECNTRL.H> //Link against:cone.lib
#include <fbs.h>//Link against:fbscli.lib
#include <gulicon.h>
#include <aknutils.h>
#include <avkon.hrh>
// CLASS DECLARATION

/**
* CTextDisplay
*
*/
class CTextDisplay : public CCoeControl
{
public: // Constructors and destructor

/**
* Destructor.
*/
~CTextDisplay();

/**
* Two-phased constructor.
*/
static CTextDisplay* NewL(const TRect &aRect,CCoeControl* aParent);

/**
* Two-phased constructor.
*/
static CTextDisplay* NewLC(const TRect &aRect,CCoeControl* aParent);
TKeyResponse OfferKeyEventL(const TKeyEvent &aKeyEvent, TEventCode aType);

private:

/**
* Constructor for performing 1st stage construction
*/
CTextDisplay();

void Draw( const TRect& aRect ) const;

/**
* EPOC default constructor for performing 2nd stage construction
*/
void ConstructL(const TRect &aRect,CCoeControl* aParent);
private:
// display content
RPointerArray<HBufC> *iDisplayContent;
// 起始位置为第几行
TInt iStartLine;
//字体颜色
TRgb iFontColour;
//文字总行数
TInt iTotalLine;
//文字显示区域
TRect iRect;
//文字字体
CFont *iFont;
//滚动条宽度
TInt iScrollBarWidth;
//控件背景色
TRgb iBackGround;
//文字显示开始位置
TPoint iStartPoit;
//每行文字间的间距
TInt iLineToLineSpace;
//一屏幕显示的最大行数
TInt iMaxDisplayLine;

CCoeControl *iParent;

//系统滚动条
CEikScrollBarFrame* iSBFrame;
TEikScrollBarModel iModel;

//创建系统滚动条
void CreateScrollBars(TInt aCunt);
public:
//计算文字中行数
void AccountTotalLine();
//计算一屏幕显示的最大行数
TInt GetMaxDisplay();
void SetScrollBarWidth(TInt aWidth);
//设置背景颜色
void SetBackground(TRgb aRgb);
//设置显示的文字
void SetDisplayContent(const TDesC& aContent,TBool aUseFlag = EFalse);
//设置文字显示字体
void SetFont(CFont *aFont);
//设置文字显示颜色
void SetFontColour(TRgb aRgb);

};

#endif // TEXTDISPLAY_H

.cpp文件

/*
============================================================================
Name : TextDisplay.cpp
Author : Barrett
Version :
Copyright : Your copyright notice
Description : CTextDisplay implementation
============================================================================
*/

#include "TextDisplay.h"
//#include "AuditionContainer.h"

_LIT(KLineStart,"<Line>");
_LIT(KLineEnd,"</Line>");
#define MAXDISPLAYLINE 10
#define LINESPACE 3
#define LASTSPACE 25

CTextDisplay::CTextDisplay()
{
// No implementation required
// iBackGroundBitmap = NULL;
iStartLine = 0;
iTotalLine = 0;
iFontColour = KRgbBlack; // default
iStartPoit = TPoint(3,5);
iLineToLineSpace = LINESPACE;
iScrollBarWidth = 10;
}

CTextDisplay::~CTextDisplay()
{

if (iDisplayContent)
{
iDisplayContent->ResetAndDestroy();
delete iDisplayContent;
iDisplayContent = NULL;
}
if(iSBFrame)
{
delete iSBFrame;
iSBFrame = NULL;
}
}

CTextDisplay* CTextDisplay::NewLC(const TRect &aRect,CCoeControl* aParent)
{
CTextDisplay* self = new (ELeave)CTextDisplay();
CleanupStack::PushL(self);
self->ConstructL(aRect,aParent);
return self;
}

CTextDisplay* CTextDisplay::NewL(const TRect &aRect,CCoeControl* aParent)
{
CTextDisplay* self=CTextDisplay::NewLC(aRect,aParent);
CleanupStack::Pop(); // self;
return self;
}

void CTextDisplay::ConstructL(const TRect &aRect,CCoeControl* aParent)
{
// SetRect(aRect);
iRect = aRect;

TFontSpec fontSpec = iEikonEnv->DenseFont()->FontSpecInTwips();
fontSpec.iHeight *= 1;
iCoeEnv->ScreenDevice()->GetNearestFontInTwips(iFont,fontSpec);
iMaxDisplayLine = GetMaxDisplay();
iParent = aParent;

}

TKeyResponse CTextDisplay::OfferKeyEventL(const TKeyEvent &aKeyEvent, TEventCode aType)
{
if((aType == EEventKeyDown) && (aKeyEvent.iScanCode == EStdKeyDownArrow))
{
if(iTotalLine >= iStartLine+iMaxDisplayLine)
{
++iStartLine;
}
}
else if((aType == EEventKeyDown) && (aKeyEvent.iScanCode == EStdKeyUpArrow))
{
if(iStartLine > 0)
{
--iStartLine;
}
}
iSBFrame->MoveVertThumbTo(iStartLine);//绝对坐标
iSBFrame->DrawScrollBarsNow();
DrawNow();
return EKeyWasConsumed;
}

void CTextDisplay::SetDisplayContent(const TDesC& aContent,TBool aUseFlag)
{
if(aContent.Length() == 0)
{
return ;
}
if (iDisplayContent)
{
iDisplayContent->ResetAndDestroy();
delete iDisplayContent;
iDisplayContent = NULL;
}

iDisplayContent = new RPointerArray<HBufC>;

HBufC *CopyText = aContent.Alloc();

if(aUseFlag)
{
TBuf<6> bufBeginTag(KLineStart);
TBuf<7> bufEndTag(KLineEnd);

while(CopyText->Length())
{
TInt posBegin = CopyText->Find(bufBeginTag)+bufBeginTag.Length();
TInt posEnd = CopyText->Find(bufEndTag);
if(posBegin!=KErrNotFound&&posEnd!=KErrNotFound)
{
TPtrC ptrPerson = CopyText->Mid(posBegin,posEnd-posBegin);
HBufC *HText = ptrPerson.Alloc();
iDisplayContent->Append(HText);
if(CopyText->Length() > posEnd+bufEndTag.Length()+1)
{
CopyText->Des().Copy(CopyText->Des().Right(CopyText->Length()-posEnd-bufEndTag.Length()));
}
else
{
break;
}
}
}
delete CopyText;
}
else
{
iDisplayContent->Append(CopyText);
}
//获取一屏幕显示的行数
//计算文字显示总行数
AccountTotalLine();
CreateScrollBars(iTotalLine-iMaxDisplayLine+2);
}

void CTextDisplay::Draw( const TRect& aRect ) const
{
CWindowGc& gc = SystemGc();

gc.SetBrushColor(iBackGround);
gc.Clear(aRect);

gc.UseFont(iFont);
gc.SetPenColor(iFontColour);
//起点
TPoint point = iStartPoit;
//记录上一段的位置
TPoint Mark = TPoint(0,-(iStartLine*iFont->HeightInPixels()+iLineToLineSpace));
TPoint point2;
if(iDisplayContent == NULL)
{
gc.DrawText(_L("No content!"),TPoint(aRect.Width()/3,aRect.Height()/3));
return ;
}
for(TInt i=0;i<iDisplayContent->Count();i++)
{
TInt nStringMaxDisplayLine = iFont->TextWidthInPixels((*iDisplayContent)[i]->Des())/(iRect.Width() - iScrollBarWidth) + iMaxDisplayLine;

TBidiText* bidi = TBidiText::NewL((*iDisplayContent)[i]->Des(), nStringMaxDisplayLine);
bidi->WrapText(iRect.Width()-iScrollBarWidth, *iFont, NULL);
TInt lines = bidi->NumberOfLinesInDisplayText();
for(TInt i=0; i<lines; i++)
{
point2 = TPoint (point.iX,point.iY+Mark.iY + iFont->HeightInPixels()*(i+1)+iLineToLineSpace*i);
TInt width = 0;
TPtrC text = bidi->LineOfDisplayText(i, width);
gc.DrawText(text, point2);
}
Mark = point2;
delete bidi;
}
//画个小三角
if(Mark.iY > iRect.Height() - LASTSPACE || iStartLine > 0)
{
gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
gc.SetPenStyle(CGraphicsContext::ENullPen);
gc.SetBrushColor(KRgbBlue);
gc.DrawRect(TRect(TPoint(0,iRect.Height()-LASTSPACE),TSize(iRect.Width(),LASTSPACE)));
gc.SetBrushColor(KRgbBlack);
TInt nTrigonWidth = 12; //默认三角宽12个像素
TInt nTrigonHeight = 12; //默认三角高12个像素
//三角形第一的点的横纵坐标
TInt PointX = aRect.Width()/2;
TInt PointY = aRect.Height() - LASTSPACE + (LASTSPACE- 2*nTrigonHeight - 1)/2;
if(iTotalLine >= iStartLine + iMaxDisplayLine && iTotalLine > iMaxDisplayLine)
{
CArrayFixFlat<TPoint>* ArrPoint = new (ELeave) CArrayFixFlat<TPoint>(10);
ArrPoint->AppendL(TPoint(PointX-nTrigonWidth/2,PointY + 1 + nTrigonHeight)); // +1表示 两个三角的间距
ArrPoint->AppendL(TPoint(PointX+nTrigonWidth/2,PointY + 1 + nTrigonHeight)); // +1表示 两个三角的间距
ArrPoint->AppendL(TPoint(PointX,PointY+2*nTrigonHeight));
gc.DrawPolygon(ArrPoint);
delete ArrPoint;
}
if(iStartLine > 0)
{
CArrayFixFlat<TPoint>* ArrPoint = new (ELeave) CArrayFixFlat<TPoint>(10);
ArrPoint->AppendL(TPoint(PointX,PointY));
ArrPoint->AppendL(TPoint(PointX-nTrigonWidth/2,PointY+nTrigonHeight));
ArrPoint->AppendL(TPoint(PointX+nTrigonWidth/2,PointY+nTrigonHeight));
gc.DrawPolygon(ArrPoint);
delete ArrPoint;
}
gc.SetBrushStyle(CGraphicsContext::ENullBrush);
}

}
void CTextDisplay::SetFontColour(TRgb aRgb)
{
iFontColour = aRgb;
}

void CTextDisplay::SetFont(CFont *aFont)
{
iFont = aFont;
iMaxDisplayLine = GetMaxDisplay();
}

void CTextDisplay::SetBackground(TRgb aRgb)
{
iBackGround = aRgb;
}

void CTextDisplay::AccountTotalLine()
{
for(TInt i=0;i<iDisplayContent->Count();i++)
{
TInt nStringMaxDisplayLine = iFont->TextWidthInPixels((*iDisplayContent)[i]->Des())/(iRect.Width() - iScrollBarWidth) + iMaxDisplayLine;
TBidiText* bidi = TBidiText::NewL((*iDisplayContent)[i]->Des(), nStringMaxDisplayLine);
bidi->WrapText(iRect.Width()-iScrollBarWidth, *iFont, NULL);
TInt lines = bidi->NumberOfLinesInDisplayText();
iTotalLine += lines;
delete bidi;
}
}

TInt CTextDisplay::GetMaxDisplay()
{
return (iRect.Height() - LASTSPACE - iStartPoit.iY)/(iFont->HeightInPixels() + iLineToLineSpace);
}

void CTextDisplay::SetScrollBarWidth(TInt aWidth)
{
iScrollBarWidth = aWidth;
}

//创建系统滚动条
void CTextDisplay::CreateScrollBars(TInt aCunt)
{
//构造
iSBFrame=new(ELeave) CEikScrollBarFrame(iParent, NULL,ETrue);
iSBFrame->CreateDoubleSpanScrollBarsL(ETrue, EFalse,ETrue,ETrue);
iSBFrame->SetTypeOfVScrollBar(CEikScrollBarFrame::EDoubleSpan);
iSBFrame->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff,
CEikScrollBarFrame::EAuto);

iModel = TEikScrollBarModel(aCunt, 1, 0);
//设置区域
TRect aRect;
aRect = TRect(TPoint(iRect.Width()-iScrollBarWidth,iRect.iTl.iY),TSize(iScrollBarWidth,iRect.Height()-LASTSPACE));
iSBFrame->Tile(&iModel,aRect);
//设置初始位置-绝对坐标
iSBFrame->MoveVertThumbTo(0);
iSBFrame->DrawScrollBarsNow();
}
// End of File

在container中的使用

第一步:在container中定义一个成员

CTextDisplay *iTextDisplay;

第二步:在constructl中初始化

代码如下: //这里是为了方便直接从文件中读出一段文本

_LIT(KAbout,"C://about.ini");

RFs fs = CEikonEnv::Static()->FsSession();
RFile fp;
TInt err = fp.Open(fs,KAbout,EFileRead);
if(err == 0)
{
TInt nFileSize = 0;
fp.Size(nFileSize);
HBufC8* fileInfo = HBufC8::NewLC(nFileSize);
TPtr8 file = fileInfo->Des();
fp.Read(file, nFileSize);
HBufC* fileInfo16 = HBufC::NewLC(file.Length());
TPtr16 ptr = fileInfo16->Des();

/*ptr.Copy(file);*/
ConvGbk2Uni(file, ptr);

iTextDisplay = CTextDisplay::NewL(aRect,this);
iTextDisplay->SetDisplayContent(fileInfo16->Des());
iTextDisplay->SetContainerWindowL(*this);
iTextDisplay->SetExtent(TPoint(0,0), TSize(240, 320));
CleanupStack::PopAndDestroy(2);
}
fp.Close();

在一段代码写在ActivateL函数之前,原因我就不说了。ConvGbk2Uni函数的代码我也贴出来。如下:

void ConvGbk2Uni(TDesC8& original, TDes& res) //这个函数不是我写的,从网上搜的
{
//RFs aFileServerSession = CEikonEnv::Static()->FsSession();
RFs aFileServerSession;
aFileServerSession.Connect();
// CleanupStack::Pop();
CCnvCharacterSetConverter* converter=CCnvCharacterSetConverter::NewLC();

if(converter->PrepareToConvertToOrFromL(KCharacterSetIdentifierGbk,aFileServerSession)!=CCnvCharacterSetConverter::EAvailable)
User::Leave(KErrNotSupported);

TInt state=CCnvCharacterSetConverter::KStateDefault;

TPtrC8 str( original );
HBufC* iInfoText = HBufC::NewL( str.Length() );

TPtr16 ptr = iInfoText->Des();

if(CCnvCharacterSetConverter::EErrorIllFormedInput == converter->ConvertToUnicode(ptr, str, state))
User::Leave(KErrArgument);

res.Zero() ;
res.Copy(ptr) ;
aFileServerSession.Close();
CleanupStack::PopAndDestroy();
delete iInfoText;
}

第二步:CountComponentControls函数加1,ComponentControl函数返回控件指针。

第三步:在OfferKeyEventL函数中添加。

return iTextDisplay->OfferKeyEventL(aKeyEvent,aType);

第四步:在析构函数中写好析构。

第五步:编译运行。

实现过程和使用过程还是比较简单的,使用过程和使用系统控件类似。在我这个控件中我提供了显示文本的两者方法。

第一种就是这里的这种,还有一种就是使用_LIT(KLineStart,"<Line>");
_LIT(KLineEnd,"</Line>");这对标签的。使用时把

iTextDisplay->SetDisplayContent(fileInfo16->Des());改成

iTextDisplay->SetDisplayContent(fileInfo16->Des(),ETrue);就可以了,这种显示的内容是<Line>你好吗</Line><Line>你好吗</Line>这种文本的。

在最后需要注意一个问题,在使用系统滚动条时,它需要窗口,这个窗口可以是共享父类的,也可以是控件自己定义的。如本文中的

//构造
iSBFrame=new(ELeave) CEikScrollBarFrame(iParent, NULL,ETrue); iParent就是共享的父类窗口,如果这里不使用这个而是直接使用this的话,在下一句iSBFrame->CreateDoubleSpanScrollBarsL(ETrue, EFalse,ETrue,ETrue);中会有KERN-EXEC 3的panic,这个是我自己的理解也不知道对不对。希望知道的大婶,指点下~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: