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

来源:互联网 发布:阿里云服务器空间不足 编辑:程序博客网 时间:2024/05/20 20:17

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

 

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

 

.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,这个是我自己的理解也不知道对不对。希望知道的大婶,指点下~~

原创粉丝点击