//------------------------------------------------------------------------------------------------------------
// unit_ScrollDrawText.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "unit_ScrollDrawText.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TScrollDrawText *)
{
new TScrollDrawText(NULL);
}
//---------------------------------------------------------------------------
namespace Unit_scrolldrawtext
{
void __fastcall PACKAGE Register()
{
TComponentClass classes[1] = {__classid(TScrollDrawText)};
RegisterComponents("My Component", classes, 0);
}
}
//---------------------------------------------------------------------------
__fastcall TScrollDrawText::TScrollDrawText(TComponent* Owner)
: TPaintBox(Owner)
{
SourceStringList = new TStringList; // 初始化来源字符串列表
ReleaseStringList = new TStringList; // 初始化发布列表
ShowControl = new TShowControl(true); // 初始化多线程控制
OutTextWidth = 20; // 设定默认行宽
}
//---------------------------------------------------------------------------
__fastcall TScrollDrawText::~TScrollDrawText()
{
ShowControl->Done(); // 设置关闭标记
InitReleaseStringList(); //
InitSourceStringList(); // 清空 StringList 对象
delete SourceStringList;
delete ReleaseStringList;
delete ShowControl;
}
//---------------------------------------------------------------------------
void __fastcall TScrollDrawText::InitSourceStringList()
{
for ( int i = 0; i < SourceStringList->Count; i++)
{
if ( SourceStringList->Objects[i] != NULL )
{
delete (TFont*)SourceStringList->Objects[i]; // 删除表内 TFont 对象
SourceStringList->Objects[i] = NULL;
}
}
SourceStringList->Clear();
}
//---------------------------------------------------------------------------
void __fastcall TScrollDrawText::InitReleaseStringList()
{
// 发布字符串的对象指针全部来自 SourceStringList
// 清除指针对象只需要由 SourceStringList 完成即可
ReleaseStringList->Clear();
}
//---------------------------------------------------------------------------
void __fastcall TScrollDrawText::AddString(const String InsertString, const TColor Color)
{
// 插入数据,也就是外部接口之一
TFont* Font = new TFont; // 创建一个对象用于保存字体信息
Font->Charset = DEFAULT_CHARSET;
Font->Color = Color;
Font->Name = "宋体";
Font->Size = 10;
SourceStringList->AddObject(InsertString, Font);
ReBuileReleaseStringList(); // 重新构建布字符串
}
//---------------------------------------------------------------------------
void __fastcall TScrollDrawText::ReBuileReleaseStringList()
{
// 新字符串进入,先清空发布字符串
// 重新往原字符串中添加
InitReleaseStringList();
for (int i = 0; i < SourceStringList->Count; i++)
{
CutInsertString
(
SourceStringList->Strings[i],
ReleaseStringList,
SourceStringList->Objects[i]
);
/*CutInsertString // 每行插入一个回车符
(
"/n",
ReleaseStringList,
SourceStringList->Objects[i]
);*/
}
}
//---------------------------------------------------------------------------
void __fastcall TScrollDrawText::CutInsertString
(const String InsertString, TStringList* ReleaseStringList, TObject* Object)
{
// 裁剪来源字符串达到额定宽度,再插入发布字符串
WideString wdStr = InsertString;
if ( wdStr.Length() <= 0 )
{
return;
}
String NewString = "";
for ( int Index = 1; ; Index++ ) // 搜索字符串,将每个字符追加到 wdStr
{
// 单字符累加,双字节由 WideString 自动处理
NewString = NewString + wdStr.SubString( Index, 1 );
if ( NewString == "" || NewString == NULL ) // 字符不存在
{
break;
}
if ( Index == ( InsertString.Length() ) ) // 循环出口,最后一个字符串
{
ReleaseStringList->AddObject(NewString, Object);
NewString = "";
break;
}
else if ( NewString.Length() <= OutTextWidth ) // 个字节一行,将进来的字符串分行
{
continue;
}
else
{
ReleaseStringList->AddObject ( NewString, Object ); // 向发布字符串输入新的对象
NewString = "";
}
}
}
//---------------------------------------------------------------------------
void __fastcall TScrollDrawText::Suspend()
{
ShowControl->Suspend(); // 启动多线程
}
//---------------------------------------------------------------------------
bool __fastcall TScrollDrawText::Suspended()
{
return ShowControl->Suspended; // 察看多线程状态
}
//---------------------------------------------------------------------------
void __fastcall TScrollDrawText::Resume()
{
/*String temp = "";
for ( int i = 0; i < ReleaseStringList->Count; i++ ) // 测试代码
{
temp = ReleaseStringList->Strings[i];
}*/
ShowControl->SetScreenText(this, ReleaseStringList); // 设置输出宽度
ShowControl->Resume(); // 开始滚动运行
}
//---------------------------------------------------------------------------
void __fastcall TScrollDrawText::SetScrollSpeed(const int ScrollSpeed)
{
ShowControl->SetScrollSpeed(ScrollSpeed); // 设置速度 20~100 为宜
}
//---------------------------------------------------------------------------
void __fastcall TScrollDrawText::SetOutTextWidth(const int OutTextWidth)
{
this->OutTextWidth = OutTextWidth; // 设置宽度
ShowControl->Suspend();
ReBuileReleaseStringList(); // 重新根据宽度生成发布字符串
ShowControl->Resume();
}
//---------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------------------
// unit_ScrollDrawText.h
//---------------------------------------------------------------------------
#ifndef unit_ScrollDrawTextH
#define unit_ScrollDrawTextH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <Controls.hpp>
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------------
#include "unit_ShowControl.h"
//---------------------------------------------------------------------------
class PACKAGE TScrollDrawText : public TPaintBox
{
__published:
void __fastcall AddString(const String InsertString, const TColor Color);
void __fastcall Resume();
void __fastcall Suspend();
bool __fastcall Suspended();
void __fastcall SetScrollSpeed(const int ScrollSpeed);
void __fastcall SetOutTextWidth(const int OutTextWidth);
private:
TStringList* SourceStringList; // 近来的字符串列
TStringList* ReleaseStringList; // 过滤后的字符串列
int OutTextWidth; // 输入宽度字节数
TShowControl* ShowControl; // 多线程控制器
void __fastcall CutInsertString
(const String InsertString, TStringList* ReleaseStringList, TObject* Object);
void __fastcall InitSourceStringList();
void __fastcall InitReleaseStringList();
void __fastcall ReBuileReleaseStringList();
protected:
public:
__fastcall TScrollDrawText(TComponent* Owner);
__fastcall ~TScrollDrawText();
};
//---------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------------------------------------
// unit_ShowControl.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "unit_ShowControl.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(&UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall TShowControl::UpdateCaption()
// {
// Form1->Caption = "Updated in a thread";
// }
//---------------------------------------------------------------------------
__fastcall TShowControl::TShowControl(bool CreateSuspended)
: TThread(CreateSuspended)
{
OnClose = false;
ScrollSpeed = 20; // 默认微秒每像素滚动
pBitmap = new Graphics::TBitmap(); // 创建缓冲区
}
//---------------------------------------------------------------------------
void __fastcall TShowControl::Execute()
{
//---- Place thread code here ----
Go();
}
//---------------------------------------------------------------------------
__fastcall TShowControl::~TShowControl()
{
delete pBitmap; // 释放缓冲区
}
//---------------------------------------------------------------------------
void __fastcall TShowControl::SetScreenText(TPaintBox* Image, TStringList* StringList)
{
ScreenImage = Image; // ScreenImage 指针指向窗体上的 Image
this->StringList = StringList; // 指向处理好可以发布的字符串
if ( pBitmap->Canvas->LockCount == 0 )
{
// 设置缓冲区尺寸
pBitmap->Canvas->Lock();
pBitmap->Height = Image->Height;
pBitmap->Width = Image->Width;
pBitmap->Canvas->Unlock();
}
}
//---------------------------------------------------------------------------
void __fastcall TShowControl::Done()
{
OnClose = true; // 关闭标记
}
//---------------------------------------------------------------------------
inline void __fastcall TShowControl::Drow()
{
// 对显示区进行 Draw 操作
if ( ScreenImage->Canvas->LockCount == 0 )
{
ScreenImage->Canvas->Lock();
ScreenImage->Canvas->Draw(0,0,pBitmap);
ScreenImage->Canvas->Unlock();
}
}
//---------------------------------------------------------------------------
void __fastcall TShowControl::Go()
{
const int RowHeight = 20; // 设定行高
const LeftSpace = 4; // 设定左间距
for ( int OutLine = pBitmap->Height * (1-0.618) ; OutLine >= - RowHeight ; OutLine -- )
{
// 循环条件描述, height*(1-0.618) 为起始位置,-20为回滚位置
if ( OnClose ) // 判断是否关闭
break;
Synchronize(&InitImage); // 初始化 Bitmap
for (int ChildIndex = 0; ChildIndex < StringList->Count; ChildIndex ++ )
{
if ( pBitmap->Canvas->LockCount == 0 )
{
pBitmap->Canvas->Lock();
/*if ( StringList->Objects[ChildIndex] != NULL )
{
pBitmap->Canvas->Font->Assign((TFont*)StringList->Objects[ChildIndex]);
}*/
// 对缓冲区输出内容
pBitmap->Canvas->Font->Assign((TFont*)StringList->Objects[ChildIndex]);
pBitmap->Canvas->TextOutA (
LeftSpace, OutLine + ChildIndex * RowHeight , StringList->Strings[ChildIndex]);
// 左边距,高度,内容
pBitmap->Canvas->Unlock();
}
if ( ChildIndex * RowHeight > pBitmap->Height )
{
// 发布行数过多不对其进行绘画,只需超过 Height 即可
break;
}
}
Synchronize(&Drow); // 缓冲区输出到显示区
//pBitmap->SaveToFile("jjj.bmp"); // 作为测试
if ( GetSleep() == -1 ) // 设置滚动速度,同时侦测是否需要退出
break;
if ( OutLine == - RowHeight ) // 回滚控制,当升至顶端 -20 的位置,把 0 移动到 最后
{
StringList->AddObject(StringList->Strings[0],StringList->Objects[0]); // 复制 0 至末尾
StringList->Delete(0); // 删除 0
OutLine = 0 ; // 总体位置回移 20 个像素
}
}
}
//---------------------------------------------------------------------------
inline int __fastcall TShowControl::GetSleep()
{
int ScrollSpeedTemp = ScrollSpeed;
while ( ScrollSpeedTemp > 0 ) // 作为封闭循环的调处条件
{
if ( OnClose ) // 但完成标记为真
return -1;
Sleep(1); // 延时
ScrollSpeedTemp --;
}
return 0;
}
//---------------------------------------------------------------------------
inline void __fastcall TShowControl::InitImage()
{
// 初始化缓冲区
if ( pBitmap->Canvas->LockCount == 0 )
{
pBitmap->Canvas->Lock();
pBitmap->Canvas->Brush->Style = bsClear;
pBitmap->Canvas->Brush->Color = clWhite;
pBitmap->Canvas->FillRect(TRect(0, 0, pBitmap->Width, pBitmap->Height));
pBitmap->Canvas->Unlock();
}
}
//---------------------------------------------------------------------------
void __fastcall TShowControl::SetScrollSpeed(int ScrollSpeed)
{
// 设置滚动速度
this->ScrollSpeed = ScrollSpeed;
}
//---------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
// ShowControl.h
//-------------------------------------------------------------------------------------------------------
#ifndef unit_ShowControlH
#define unit_ShowControlH
//---------------------------------------------------------------------------
#include <Classes.hpp>
//---------------------------------------------------------------------------
class TShowControl : public TThread
{
private:
Graphics::TBitmap *pBitmap; // 缓冲
TPaintBox* ScreenImage; // 来源
TStringList* StringList;
bool OnClose;
int ScrollSpeed; // 默认微秒每像素滚动
inline int __fastcall GetSleep();
inline void __fastcall Drow();
void __fastcall Go();
inline void __fastcall InitImage();
protected:
void __fastcall Execute();
public:
__fastcall TShowControl(bool CreateSuspended);
__fastcall ~TShowControl();
void __fastcall SetScreenText(TPaintBox* Image, TStringList* StringList);
void __fastcall Done();
void __fastcall SetScrollSpeed(int ScrollSpeed);
};
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------------------------------------
// 使用示范
//---------------------------------------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
LabeledEdit1->Text = 20;
LabeledEdit2->Text = 20;
ScrollDrawText1->AddString("This is new message 1", clGreen);
ScrollDrawText1->AddString("This is new message 2", clBlue);
ScrollDrawText1->AddString("This is new message 3", clBlack);
ScrollDrawText1->AddString("This is new message 4", clSkyBlue);
ScrollDrawText1->AddString("This is new message 5", clYellow);
ScrollDrawText1->AddString("This is new message 6", clTeal);
ScrollDrawText1->AddString("This is new message 7", clPurple);
ScrollDrawText1->AddString("This is new message 8", clAqua);
ScrollDrawText1->AddString("This is new message 9", clSkyBlue);
ScrollDrawText1->AddString("This is new message 0", clHotLight);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ScrollDrawText1->AddString(LabeledEdit3->Text, clHotLight);
ScrollDrawText1->Resume();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
ScrollDrawText1->SetScrollSpeed(LabeledEdit1->Text.ToInt());
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
ScrollDrawText1->SetOutTextWidth(LabeledEdit2->Text.ToInt());
}
//---------------------------------------------------------------------------