/*本練習用於工作視窗(window)之螢幕上顯示大小寫英文字母,繁簡漢字,其他文字,數字及符號所組成的字串
並可使該字串能針對視窗大小來手動, 或用較精準的字體尺寸計算方式以進行自動換行
對於非漢字的其他語系文字部分(P.S. 本例使用英文與西里爾字母做為測試), 為免造成辨識錯誤
故採整個字詞跳行, 而非使用斷字之連字符號(-,連字號/減號(U+002D/0x002D))的方式
作業環境: Windows XP/Vista/Win7
C++編譯工具: Code::Blocks 12.11
函式庫: SDL(Simple DirectMedia Layer)及SDL_ttf
編寫者: 永吉
編寫日期: 20130724(Wed.)
先決條件:
1. 視窗須夠大
2. 字串內的所有字數不能超過字串顯示之範圍空間, 否則要有可進入下一頁或字幕捲動的設計(P.S. 本例皆無此設計)
3. 在編寫程式時, 讓使用者可在字串中自由選擇適當的位置預設強制跳行代號(連續兩個重音符號"`"(0x0060)),
使程式執行時遇到該代號便進行跳行
*/
//寫入相關的標頭檔
#include "SDL/SDL.h"
#include "SDL/SDL_ttf.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//工作視窗之螢幕尺寸及像素位元比之設定
const int SCREEN_WIDTH = 1000;
const int SCREEN_HEIGHT = 650;
const int SCREEN_BPP = 32;
//宣告畫面變數
SDL_Surface *MyMessage = NULL;//文字訊息
SDL_Surface *MyScreen = NULL;//螢幕
//宣告事件結構變數
SDL_Event MyEvent;
//宣告字體變數
TTF_Font *MyFont = NULL;
/*宣告字色變數
R255 G255 B255為白色, R0 G0 B0為黑色*/
SDL_Color MyTextColor = { 255, 255, 255 };//此處使用白色
//讓字串顯示於螢幕上
void ApplySurface( int x, int y, SDL_Surface* Source, SDL_Surface* Destination, SDL_Rect* Clip = NULL )
{
//宣告字串顯示於螢幕的起始座標變數
SDL_Rect Offset;
//取得位置座標
Offset.x = x;
Offset.y = y;
//張貼字串
SDL_BlitSurface( Source, Clip, Destination, &Offset );
}
bool Init()//初始化之功能確認
{
//SDL函式庫之初始化
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return false;
}
//設定螢幕
MyScreen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
//螢幕設定出錯之跳出機制
if( MyScreen == NULL )
{
return false;
}
//SDL_ttf之初始化
if( TTF_Init() == -1 )
{
return false;
}
//顯示工作視窗的標題
SDL_WM_SetCaption( "My String Test", NULL );
//所有設定正常之回報機制
return true;
}
bool LoadMyFiles( int MyFontSize )//載入字體檔
{
/*開啟ttf字體檔與設定字體大小
目前尚未取得本字體檔的版權, 故僅能進行測試使用*/
MyFont = TTF_OpenFont( "C:/Windows/Fonts/kaiu.ttf", MyFontSize);
//標楷體, 該檔位於C:/Windows/Fonts資料夾內, 理想可視字體尺寸參數(ptsize)建議設為18以上
//未能正確開啟ttf字體檔之跳出機制
if( MyFont == NULL )
{
return false;
}
//所有設定正常之回報機制
return true;
}
int SAKL(int MyStringX, int MyStringY, int MyFontSize, wchar_t MyString[])//字串長度自動調整段落函式
{
//載入字體相關檔案
if( LoadMyFiles(MyFontSize) == false )
{
return 1;
}
//計算一個文字的寬度, 做為設定邊框間距的基準數值
wchar_t MyWordSize[]=L"佛";//選用一測試文字, 以漢字為基準
int MySL = wcslen(MyWordSize);//計算字串總共的字數長度, 作為迴圈參數使用
char MyDTH[20];//宣告一個字元變數, 用作將數值轉換成字元
Uint16 MyPM[MySL];//宣告一個十六位元無記號數值變數, 用作存放字串的十六進制數值
//進行資料內容之轉換
for (int i = 0; i < MySL; i++)
{
itoa(MyWordSize[i],MyDTH,16);//將變數內的十進制數值轉換成十六進制的字元, 並儲存於字元變數
MyPM[i]= strtol(MyDTH,NULL,16);//將變數內的字元變成十六進制的數值, 並儲存於變數
}
MyPM[MySL]={0};//讓字串的結尾加上結束符號, 如此可避免列印出字串以外的無用資料
MyMessage = TTF_RenderUNICODE_Solid( MyFont, MyPM, MyTextColor );//顯示跳行前的文字
int MyStringLengh = wcslen(MyString),
PSAreaWidth = SCREEN_WIDTH - (MyMessage -> w + MyStringX),//顯示字串區域之寬度, 單位:pixel
SCFlag = 0;//字串內字元顯示指標之數值變數
char DecToHex[20];//宣告一個字元變數, 用作將數值轉換成字元
Uint16 PrintMyString[MyStringLengh];//宣告一個十六位元無記號數值變數, 用作存放字串的十六進制數值
for (int i = 0; i < MyStringLengh; i++)
{
itoa(MyString[i],DecToHex,16);//將變數MyString內的十進制數值轉換成十六進制的字元, 並儲存於字元變數DecToHex
PrintMyString[SCFlag]= strtol(DecToHex,NULL,16);//將變數DecToHex內的字元變成十六進制的數值, 並儲存於變數PrintMyString
PrintMyString[SCFlag+1]= {0};
MyMessage = TTF_RenderUNICODE_Solid( MyFont, PrintMyString, MyTextColor );
if (PrintMyString[SCFlag] == 0x0060 && PrintMyString[SCFlag-1] == 0x0060)
{
if (SCFlag == 1)//避免形成空字串而造成執行錯誤
{
PrintMyString[SCFlag-1]= {0x0020};//空格
PrintMyString[SCFlag]= {0};
}
else PrintMyString[SCFlag-1]= {0};
MyMessage = TTF_RenderUNICODE_Solid( MyFont, PrintMyString, MyTextColor );
ApplySurface( MyStringX, MyStringY, MyMessage, MyScreen );//在螢幕開始顯示字串
MyStringY += MyMessage -> h;//跳行
SCFlag = -1;
}
if (MyMessage -> w >= PSAreaWidth && PrintMyString[SCFlag] != 0x0060)//判斷因字數過長而必須跳行時
{
/*判斷該字元是否為數字, 符號@(編碼: 0x0040), 大寫或小寫英文字母, 西里爾字母
Ref. https://zh.wikipedia.org/wiki/Unicode%E5%AD%97%E7%AC%A6%E5%88%97%E8%A1%A8*/
bool NH = false;//非漢字判斷變數
//忽略字母數目超過25的英文單字
int Ri = i,
RS = SCFlag;
//此處進行完整字詞的跳行處理
while (PrintMyString[SCFlag] == 0x0027//引號
|| PrintMyString[SCFlag] >= 0x0030 && PrintMyString[SCFlag] <= 0x003F //數字
|| PrintMyString[SCFlag] >= 0x0040 && PrintMyString[SCFlag] <= 0x005A //符號@與大寫英文字母
|| PrintMyString[SCFlag] >= 0x0061 && PrintMyString[SCFlag] <= 0x007A //小寫英文字母
|| PrintMyString[SCFlag] >= 0x0400 && PrintMyString[SCFlag] <= 0x04FF) //西里克字母
{
SCFlag --;
i --;
NH = true;
}
if (NH == true && (Ri-i) < 26)//以字母長度不超過25個為限 如此可避免程式無法執行
{
PrintMyString[SCFlag+1]= {0};
NH = false;
}
else //若字母長度超過25時 就不予以進行整字詞跳行處理
{
i = Ri-1;
PrintMyString[RS] = 0;
NH = false;
}
MyMessage = TTF_RenderUNICODE_Solid( MyFont, PrintMyString, MyTextColor );
ApplySurface( MyStringX, MyStringY, MyMessage, MyScreen );
MyStringY += MyMessage -> h;
SCFlag = 0;
}
else //顯示出字串最後不滿一行的所有字元
{
if (i == MyStringLengh-1)
{
MyMessage = TTF_RenderUNICODE_Solid( MyFont, PrintMyString, MyTextColor );
ApplySurface( MyStringX, MyStringY, MyMessage, MyScreen );
}
else SCFlag ++; //若沒有滿足任何跳行或顯示文字條件時
}
}
}
void CleanUp()//清空或關閉所佔用之資源
{
//清除顯示於螢幕上的內容
SDL_FreeSurface( MyMessage );
//關閉所開啟之ttf字體檔
TTF_CloseFont( MyFont );
//離開SDL_ttf
TTF_Quit();
//離開SDL
SDL_Quit();
}
int main( int argc, char* args[] )
{
//結束程式
bool Quit = false;
//執行初始化之功能確認
if( Init() == false )
{
return 1;
}
/*輸入欲於螢幕上顯示字串, 此處的寬字元變數MyString會儲存該字串的十進制數值
在Code::Blocks編輯環境裡, 可利用backslash(反斜線:\)來做為斷句的符號, 之後再按下Enter,
如此以利編輯字串時的閱讀, 且此斷句符號不會在螢幕出現, 同時也不會對字串產生實質跳行效果
以下字串如編輯正常則為藍色文字, 不正常則出現黑色文字
下列有兩個測試方法, 可擇一執行之*/
//測試法一-起點:
SAKL(10, 10, 26, L"雜阿含經卷第一 宋天竺三藏求那跋陀羅譯``\
(Ref. http://www.cbeta.org/result/normal/T02/0099_001.htm)``\
如是我聞:一時,佛住舍衛國祇樹給孤獨園。爾時,世尊告諸比丘:「當觀色無常。\
如是觀者,則為正觀。‧‧‧(餘略)``\
Saṃyukta-āgama(Miscellaneous Agama Sutra) Discourses 1 Bhikkhu Anālayo``\
(Ref. http://www.ddbc.edu.tw/zh/downloads/download_document.html?gid=3751)``\
Thus have I heard. At one time the Buddha was staying at Sāvatthī in Jeta's Grove, Anāthapiṇḍika's \
Park. At that time the Blessed One said to the monks: “You should contemplate form as impermanent. \
One who contemplates like this has right insight. ...(others to omit)````\
Hello, 我是`台灣人永吉(Цолмoн), 爱与和平!! \
poettw人間學社(poettw's Society of World)E-mail: poettw2010@gmail.com``\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
//測試法一-終點
/*
//測試法二-起點:
wchar_t MyString[] = L"雜阿含經卷第一 宋天竺三藏求那跋陀羅譯``\
(Ref. http://www.cbeta.org/result/normal/T02/0099_001.htm)``\
如是我聞:一時,佛住舍衛國祇樹給孤獨園。爾時,世尊告諸比丘:「當觀色無常。\
如是觀者,則為正觀。‧‧‧(餘略)``\
Saṃyukta-āgama(Miscellaneous Agama Sutra) Discourses 1 Bhikkhu Anālayo``\
(Ref. http://www.ddbc.edu.tw/zh/downloads/download_document.html?gid=3751)``\
Thus have I heard. At one time the Buddha was staying at Sāvatthī in Jeta's Grove, Anāthapiṇḍika's \
Park. At that time the Blessed One said to the monks: “You should contemplate form as impermanent. \
One who contemplates like this has right insight. ...(others to omit)````\
Hello, 我是`台灣人永吉(Цолмoн), 爱与和平!! \
poettw人間學社(poettw's Society of World)E-mail:poettw2010@gmail.com``\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
//讓字串在下列三種不同字體大小(14,15,18)及顏色的變化下顯示
MyTextColor = { 86, 200, 240 };//此處使用藍色
SAKL(10, 10, 14, MyString);
MyTextColor = { 0, 255, 0 };//此處使用綠色
SAKL(10, 190, 15, MyString);
MyTextColor = { 255, 0, 0 };//此處使用紅色
SAKL(10, 400, 18, MyString);
//測試法二-終點
*/
//更新螢幕畫面
if( SDL_Flip( MyScreen ) == -1 )
{
return 1;
}
//使用者關閉執行程式
while( Quit == false )
{
//於事件功能運作狀態下
while( SDL_PollEvent( &MyEvent ) )
{
//當使用者執行關閉視窗之動作時
if( MyEvent.type == SDL_QUIT )
{
//結束程式
Quit = true;
}
}
}
//清空或關閉所有已開啟的資源
CleanUp();
return 0;
}