剛才又有人在我QQ里問到如何禁止用戶該表自己單文檔窗體的大小,修改標題等等問題,其實這些問題不難,那么我現在來講一下這個東西的實現。
首先找到單文檔程序中的PreCreateWindow(CREATESTRUCT& cs)這個函數,這個函數是用來設置我們窗體的一些特征的,現在,我們來仔細看一下這個函數,如下:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs
return TRUE; }
首先來看這個參數CREATESTRUCT& cs,是一個CREATESTRUCT結構的引用,那好,我們再來查詢下MSDN,看一下這個結構,如下:
typedef struct tagCREATESTRUCT { // cs LPVOID lpCreateParams; HINSTANCE hInstance; HMENU hMenu; HWND hwndParent; int cy; int cx; int y; int x; LONG style; LPCTSTR lpszName; LPCTSTR lpszClass; DWORD dwExStyle; } CREATESTRUCT;
我們來一個一個的看這些參數:
LPVOID lpCreateParams:這個參數用來指向將被用于創建窗口的數據的指針。
HINSTANCE hInstance: 這個參數標識了擁有新窗口的模塊的模塊實例的句柄。
HMENU hMenu:這個參數標識了要被用于新窗口的菜單。如果是子窗口,則包含整數ID。
HWND hwndParent:這個參數標識了擁有新窗口的窗口。如果新窗口是一個頂層窗口,這個參數可以為NULL。
int cy:這個參數指定了新窗口的高。
int cx:這個參數指定了新窗口的寬。
int y:這個參數這個參數指定了新窗口的左上角的Y軸坐標。如果新窗口是一個子窗口,則坐標是相對于父窗口的;否則坐標是相對于屏幕原點的。
int x:這個參數定了新窗口的左上角的X軸坐標。如果新窗口是一個子窗口,則坐標是相對于父窗口的;否則坐標是相對于屏幕原點的。
LONG style:這個參數指定了新窗口的風格。
LPCTSTR lpszName:這個參數指向一個以null結尾的字符串,指定了新窗口的名字。
LPCTSTR lpszClass:這個參數指向一個以null結尾的字符串,指定了新窗口的Windows類名(一個WNDCLASS結構;更多的信息參見Win32 SDK文檔)。
DWORD dwExStyle:這個參數指定了新窗口的擴展風格。
在這些參數里面我們一般經常用到的是cy、cx、y、x、style、lpszName這幾個,需要特別注意。
好了,現在開始在PreCreateWindow(CREATESTRUCT& cs) 加上代碼,實現禁止改變單文檔窗口大小:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs cs.hMenu = NULL;//去掉菜單 cs.style&=~WS_MAXIMIZEBOX; //禁用按動最大化按鈕 cs.style&=~WS_THICKFRAME;//禁止用戶改變窗口大小 cs.cx = 700;//窗口寬度 cs.cy = 500;//窗口高度
cs.style&=~FWS_ADDTOTITLE;//將FWS_ADDTOTITLE去掉
cs. lpszName = "標題"http://改變標題,替換自己的標題 return TRUE; }
這里我們要注意,給這些參數賦值的時候我們需要用&符號還有一個~符號,我來解釋一個:
cs.style&=~WS_MAXIMIZEBOX; //禁用按動最大化按鈕
這句的意思是將WS_MAXIMIZEBOX從style里去掉,是個反與的操作,其他的類同。
|
一.常見問題
a.可以編譯,不能執行的
AfxInitRichEdit();
b.升級默認的Riched版本(默認的有一些bug)
可在InitInstance中添加
LoadLibrary("RICHED20.DLL")
最后注意 FreeLibrary
如果是CRichEditView基類的可用
BOOL CXXXXXXView::PreCreateWindow(CREATESTRUCT& cs)
{
//裝入rich edit version 2.0
if (LoadLibraryA("RICHED20.DLL") == NULL)
{
AfxMessageBox(_T("Fail to load \"riched20.dll\"."),MB_OK | MB_ICONERROR);
PostMessage(WM_QUIT,0,0);
return FALSE;
}
m_strClass = RICHEDIT_CLASSA;//for 2.0 class
return CRichEditView::PreCreateWindow(cs);
}
c.最后追加行
richeditctrl.SetSel(-1, -1);
richeditctrl.ReplaceSel( (LPCTSTR)str );
顯示回車換行:
設屬性:"Multi lines"選為True。
設屬性:"want return "選為True。
d.字數限制
CRichEditCtrl::LimitText(long nChars)
e.換行切換
CRichEditView的OnInitialUpdate()函數中加入下面兩句:
m_nWordWrap = WrapNone;
WrapChanged();
WrapChanged實際上也是調用
ctrl.SetTargetDevice(NULL, 1); //m_nWordWrap == WrapNone
ctrl.SetTargetDevice(NULL, 0); //m_nWordWrap == WrapToWindow
還有不常用的 m_nWordWrap == WrapToTargetDevice
ctrl.SetTargetDevice(m_dcTarget, GetPrintWidth());
如果是在Dialog中,可使用SetTargetDevice,注意在屬性里面加上want return
f.有時候不希望帶格式的數據粘貼,可通過PasteSpecial選擇性粘貼
pmyRichEditCtrl->PasteSpecial(CF_TEXT);
g.隨著輸入隨著自動滾動條滾動到最后一行
int nFirstVisible = pmyRichEditCtrl->GetFirstVisibleLine();
if (nFirstVisible > 0)
{
pmyRichEditCtrl->LineScroll(-nFirstVisible, 0);
}
或
m_cRichEdit.PostMessage(WM_VSCROLL, SB_BOTTOM,0);
h.設置UNDO的次數(只能用在RICHED20以上,即默認不支持,必須升級)
SendMessage(EM_SETTEXTMODE,TM_MULTILEVELUNDO,0);
TM_MULTILEVELUNDO 支持多取消(默認值).可通過EM_SETUNDOLIMIT設置最大次數
SendMessage(EM_SETUNDOLIMIT,100,0);
i.響應OnChange
EM_SETEVENTMASK 設置 ENM_CHANGE
long lMask = GetEventMask();
lMask |= ENM_CHANGE;
lMask &= ~ENM_PROTECTED;
SetEventMask(lMask);
j.設置只讀
CRichEditCtrl::SetReadOnly( BOOL bReadOnly = TRUE );
通過設置PROTECTED實現選中的文本只讀,參見
http://www.codeguru.com/Cpp/controls/richedit/article.php/c2401/
二.函數應用
a.設置字體(主要是通過SetSelectionCharFormat)
CHARFORMAT cf;
ZeroMemory(&cf, sizeof(CHARFORMAT));
cf.cbSize = sizeof(CHARFORMAT);
cf.dwMask|=CFM_BOLD;
cf.dwEffects|=CFE_BOLD;//設置粗體,取消用cf.dwEffects&=~CFE_BOLD;
cf.dwMask|=CFM_ITALIC;
cf.dwEffects|=CFE_ITALIC;//設置斜體,取消用cf.dwEffects&=~CFE_ITALIC;
cf.dwMask|=CFM_UNDERLINE;
cf.dwEffects|=CFE_UNDERLINE;//設置斜體,取消用cf.dwEffects&=~CFE_UNDERLINE;
cf.dwMask|=CFM_COLOR;
cf.crTextColor = RGB(255,0,0);//設置顏色
cf.dwMask|=CFM_SIZE;
cf.yHeight =200;//設置高度
cf.dwMask|=CFM_FACE;
strcpy(cf.szFaceName ,_T("隸書"));//設置字體
rich.SetSelectionCharFormat(cf);
b.設置字體的行間距
要用richedit2.0以上
試試
PARAFORMAT2 pf;
pf.cbSize = sizeof(PARAFORMAT2);
pf.dwMask = PFM_NUMBERING | PFM_OFFSET;
pf.wNumbering = PFN_BULLET;//注意PFM_NUMBERING
pf.dxOffset = 10;
VERIFY(SetParaFormat(pf));
常用的dwMask有
PFM_NUMBERING 成員 wNumbering 才起作用,項目符號,默認用PFN_BULLET
2 使用阿拉伯數字 (1, 2, 3, ...).
3 使用小寫字母 (a, b, c, ...).
4 使用大寫字母 (A, B, C, ...).
5 使用小寫羅馬數字 (i, ii, iii, ...).
6 使用大寫羅馬數字 (I, II, III, ...).
7 自定義,字符見成員 wNumberingStart.
PFM_OFFSET 成員 dxOffset 才起作用,縮進,單位twips
PFM_STARTINDENT 成員 dxStartIndent 才起作用,首行縮進
PFM_SPACEAFTER 成員 dySpaceAfter 才起作用,段間距
PFM_LINESPACING 成員 dyLineSpacing 才起作用,行間距
c.設置CRichEditCtrl(2.0)背景透明
long style = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
style &= WS_EX_TRANSPARENT;
::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, style);
或 CreateEx,然后把WS_EX_TRANSPARENT樣式加上
e.得到內容有三種
1)GetWindowText
2)使用EM_GETTEXTEX
GETTEXTEX gt;
gt.cb = 200;
gt.flags = GT_DEFAULT;
gt.codepage = CP_ACP ;
gt.lpDefaultChar = NULL;
gt.lpUsedDefChar = NULL;
SendMessage(EM_GETTEXTEX,(WPARAM)>,(LPARAM)text);
3)StreamOut(主要用于RTF等格式輸出)
static DWORD CALLBACK
MyStreamOutCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
CFile* pFile = (CFile*) dwCookie;
pFile->Write(pbBuff, cb);
*pcb = cb;
return 0;
}
CFile cFile(TEXT("myfile.rtf"), CFile::modeCreate|CFile::modeWrite);
EDITSTREAM es;
es.dwCookie = (DWORD) &cFile;//設置用例參數,以便回調函數調用
es.pfnCallback = MyStreamOutCallback;
pmyRichEditCtrl->StreamOut(SF_RTF, es);
讀入可以此類推,SetWindowText,EM_SETTEXTEX,StreamIn
f.查找字符串
FINDTEXTEX ft;
ft.chrg.cpMin = 0;
ft.chrg.cpMax = -1;
ft.lpstrText = "|";
long lPos = FindText(0, &ft);
如果要繼續查找,修改cpMin,如
int nCount = 0;
do
{
long lPos = GetRichEditCtrl().FindText(0, &ft);
if( -1 == lPos) break;
ft.chrg.cpMin = lPos + strlen(ft.lpstrText);
++nCount;
}while(TRUE);
g.以Html格式保存
目前做法可先轉為RTF格式,再通過RTF-to-HTML Converter
http://www.codeguru.com/Cpp/controls/richedit/conversions/article.php/c5377/
h.重載OnProtected函數得到對應的消息,如粘貼等
void CMYichEditorView::OnProtected(NMHDR* pNMHDR, LRESULT* pResult)
{
ENPROTECTED* pEP = (ENPROTECTED*)pNMHDR;
switch (pEP->msg)
{
case WM_KEYDOWN://按鍵,判斷pEP->wParam
case WM_PASTE://粘貼
case WM_CUT://剪切
case EM_SETCHARFORMAT:
default:
break;
};
*pResult = FALSE;
}
三.聊天常用
a.LINK 鏈接功能
1. LoadLibrary(_T("Riched20.dll"));
2. 創建RichEdit2.0控件
CreateEx(0, _T("RichEdit20A"), NULL, WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP
|ES_READONLY|ES_WANTRETURN|ES_MULTILINE, rect.left, rect.top, cx, cy,
pParentWnd->m_hWnd, (HMENU)nID, NULL);
3. 設定選中的文字為鏈接顯示
CHARFORMAT2 cf2;
ZeroMemory(&cf2, sizeof(CHARFORMAT2));//
cf2.cbSize = sizeof(CHARFORMAT2);
cf2.dwMask = CFM_LINK;
cf2.dwEffects |= CFE_LINK;
m_cRichEdit.SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf2);
4.支持鏈接的點擊響應
m_cRichEdit.SetEventMask(ENM_LINK);
5.響應鏈接的點擊EN_LINK
BEGIN_MESSAGE_MAP(CMyRichEdit, CRichEditCtrl)
ON_NOTIFY_REFLECT(EN_LINK,OnURL)
END_MESSAGE_MAP()
......
void CMyRichEdit::OnURLClick(NMHDR *pNmhdr, LRESULT *pResult)
{
TCHAR LinkChar[512];
ENLINK *pLink = (ENLINK *)pNmhdr;
if (pLink->msg == WM_LBUTTONUP)
{
SetSel(penLink->chrg);//這是鏈接的文字范圍
long Res = GetSelText((char *)LinkChar);//這是鏈接文字
//后面是你的處理過程
......
}
}
b.插入位圖
http://www.codeguru.com/Cpp/controls/richedit/article.php/c2417/
http://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/
自定義在RichEdit中插入對象的圖標
http://www.blogcn.com/user3/jiangsheng/blog/1319738.html
方法基本同Knowledge Base文章Q220844 HOWTO: Insert a Bitmap Into an RTF Document Using the RichEdit Control
只是在最后插入之前調用一下IOleCache::SetData,用一個HGLOBAL作為參數,HGLOBAL里面的數據是一個METAFILEPICT結構,包含自己提供的圖片
使用CRichEditView::InsertFileAsObject就可以插入圖像。VC++帶有一個例子WordPad。
另外可以參考“Insert any HBITMAP (Bitmap) in your RichEdit Control”(http://www.codeguru.com/richedit/richeditrc.html)。
c.顯示GIF動畫
常用的是通過qq的imageole.dll(也有用Gif89.dll的)
http://www.xiaozhou.net/cooldog/blogview.asp?logID=82
http://www.codeproject.com/richedit/AnimatedEmoticon.asp
在richedit控件中插入動態GIF (Native C++版)
http://blog.joycode.com/jiangsheng/archive/2004/12/15/41209.aspx
d.IRichEditOleCallback的使用
http://61.186.252.131/Expert/topic/905/905844.xml?temp=.8379022
類似 MSN 信息發送框的制作(上)
http://www.vckbase.com/document/viewdoc/?id=1087
內容包含:實現右鍵菜單,圖片插入,讀取/寫入RTF格式字符串
自定義 CRichEditCtrl 控件
http://www.vckbase.com/document/viewdoc/?id=328
內容包含:鼠標右鍵消息,消息映射,字體變換
PS.richedit控件升級到2.0后,先把字體設為楷體,輸入漢字沒有問題,但輸入字母時,字母自動跳轉為Arial字體,而1.0卻沒有這個文題,仍然是用楷體顯示字母
是一個專門的設計 Dual-font, Smart font apply, 參見 http://61.186.252.131/Expert/topic/913/913807.xml?temp=.3753778
TrueType字體通常包含在單個TrueType字體文件中,其文件后綴為.TTF。OpenType字體是以類似 于TrueType字體的格式編碼的POSTSCRIPT字體。OPENTYPE字體使用.OTF文件后綴。OPENTYPE還允許把多個OPENTYPE字體組合在一個文件中以利于數據共享。這些字體被稱為TrueType字體集(TrueType colleCTion),其文件后綴為.TTC。
TrueType字體用machintosh的輪廓字體資源的格式編碼,有一個唯一的標記名"sfnt"。windows沒有macintosh的位圖字體資源格式,字體目錄 包含了字體格式的版本號和幾個表,每個表都有一個tableentry結構項,tableentry結構包含了資源標記、校驗和、偏移量和每個表的大小。下面是TrueType字體目錄的c語言定義:
typedef sturct
{
char tag[4];
ULONG checkSum;
ULONG offset;
ULONG length;
}TableEntry;
typedef struct
{
Fixed sfntversion; //0x10000 for version 1.0
USHORT numTables;
USHORT searchRange;
USHORT entrySelector;
USHORT rangeShift;
TableEntry entries[1];//variable number of TableEntry
}TableDirectory;
TrueType 字體中的所有數據都使用big-endian編碼,最高位字節在最前面(因為TrueType字體最初是由apple公司定義的,而apple公司的os運行在motorola的cpu上)。如果一人TrueType字體以00 01 00 00 ,00 17開頭,我們就可以知道它的格式是輪廓字體資源("sfnt")版本1.0的格式,有23個表。
TableDirectory結構的最后一個字段是可變長度的tableentry結構的數組,安體中的每個表對應其中一項。TrueType字體中的每個表都保存了不同的邏輯信息-----如圖元中數據、字符到圖元的映射、字距調整信息等等。有表是必須的,有些是可選的。下表列出了TrueType字體中常見的表。
head 字體頭 字體的全局信息
cmap 字符代碼到圖元的映射 把字符代碼映射為圖元索引
glyf 圖元數據 圖元輪廓定義以及網格調整指令
maxp 最大需求表 字體中所需內存分配情況的匯總數據
mmtx 水平規格 圖元水平規格
loca 位置表索引 把元索引轉換為圖元的位置
name 命名表 版權說明、字體名、字體族名、風格名等等
hmtx 水平布局 字體水平布局星系:上高、下高、行間距、最大前進寬度、最小左支撐、最小右支撐
kerm 字距調整表 字距調整對的數組
post PostScript信息 所有圖元的PostScript FontInfo目錄項和PostScript名
PCLT PCL 5數據 HP PCL 5Printer Language 的字體信息:字體數、寬度、x高度、風格、記號集等等
OS/2 OS/2和Windows特有的規格 TrueType字體所需的規格集
在TableDirectory結構中,所有的TableEntry結構都必須根據它們的標記名排序。比如,cmap必須出現在head前,而head必須在glyf前。但是實際的表可以出現在TrueType字體文件中的任意位置。
Win32API 提供了一個應用程序可用于查詢原始TrueType字體信息的函數:
DWORD GetFontData(HDC hDC,DWORD dwTable ,DWORD dwOffset, LPVOID lpbBuffer ,DWORD cbData);
GetFontData函數可以用于查詢設備上下文中當前邏輯字體所對應的TrueType字體,因此傳遞的不是邏輯字體句柄,而是設備上下文句柄。你可以查詢整個TrueType文件基是文件中的一個表。要查詢整個文件的話dwTable參數應該為0;否則,應該傳遞要查詢的表的四字符標記的DWORD格式。參數dwOffset是要查詢的表中的起始偏移,要查詢整個表的話應該為0;參數;pvBuffer是緩沖區的地址,cbData是緩沖區的大小。如果最后個參數為NULL和0,GetFontData函數返回字體文件或表的大小;就會把到的數據拷貝到應用程序所提供的緩沖區中。
下面的例和查詢整個TrueType字體的原始數據:
TableDirctory * GetTrueTypeFont (HDC hDC ,DWORD &nFontSize)
{
//query font size
nFontSize=GetFontData(hDC,0,0,NULL,0);
TableDirectory * pFont =(TableDirectory *)new BYTE(nFontSize);
if (pFont==NULL)
return NULL;
GetFontData(hDC,0,0,pFont,nFontSize);
return pFont;
}
GetFontData使得應用程序能夠在自己的文檔中內嵌TrueType字體,以確保這些文檔能在沒有相應字體的其他機器上顯示。它的做法是允許應用程序查詢字體數據,然后寫入到文檔中作為文檔的一部分,在文檔被打于時再安裝該字體以確保文檔能以創建時同樣的方式顯示。比如,Windows NT/2000的假脫機程序在打印到遠端服務器時會在假脫機文件中內嵌入TrueType字體以保證文檔能在另一臺機器上正確地打印。
一旦接受到TrueType字體的原始數據,它的頭中的TableDirectory結構很容易分析。需要檢查的只有版本號和表的數目,然后就可以檢查單個的表。我們來看一些重要的和有趣的表。
1.字體頭
字體頭表(head表)中包含了TrueType字體的全局信息。下面是字體頭表的結構。
typedef sturct
{
Fixed Table;//x00010000 ro version 1.0
Fixed fontRevision;//Set by font manufacturer.
ULONG checkSumAdjustment;
ULONG magicNumer; //Set to 0x5f0f3cf5
USHORT flags;
USHORT unitsPerEm; //Valid range is from 16 to 16384
longDT created; //International date (8-byte field).
longDT modified; //International date (8-byte field).
FWord xMin; //For all glyph bounding boxes.
FWord yMin; //For all glyph bounding boxes.
FWord xMax; //For all glyph bounding boxes.
FWord xMax; //For all glyph bounding boxes.
USHORT macStyle;
USHORT lowestRecPPEM; //Smallest readable size in pixels.
SHORT fontDirctionHint;
SHORT indexToLocFormat; //0 for short offsets ,1 for long.
SHORT glyphDataFormat; //0 for current format.
}Table_head;
字體的歷史記錄在三個字段中:字全版本號、字體最初創建時間和字體最后修改時間。有8 個字節用于記錄時間戳,記錄的是從1904年1月1日午夜12:00開始的秒數,因此我們不用擔心y2k問題,或是什么y2m問題。
字體設計時是針對一個參考網格設計的,該網格被稱為em-square,字體中的圖元用網格中的坐標表示。因此em-squrare的大小決定胃該字體的圖元被縮放的方式,同時也反映胃該字體的質量。字體頭中保存了每個em-square的格數和能 包含所有圖元的邊界框。Em-square的有效值是從16到16384,常見的值是2048、4096和8192。比如,Windings字體的em-square的格數是2048,圖元的邊界框是[0,-432,2783,1841]。
字體頭表中的其他信息包括最小可讀像素大小、字體方向、在位置表中圖元索引的格式和圖元數據格式等等。
最大需求表
TrueType字體是一種非常靈活的數據結構,它可以包含可變數目的圖元,每個圖元可以有不同數目的控制點,甚至還可以有數量可變的圖元指令。最大需求表的目的是告知字體柵格器(rasterizer)對內存的需求,以便 在出來字體前分配合適大小的內存。因為性能對字體柵格器非常重要,像MFC的CAarray那樣需要頻繁進行數據拷貝操作的動態增長的數據結構不合要求。下面是maxp表的結構。
typedef struct
{
Fixed Version;//0x00010000 for version 1.0.
USHORT numGlypha; //Number of glyphs in the font .
USHORT maxPoints; //Max points in noncomposite glyph .
RSHORT maxContours; //Max contours in noncomposite glyph.
USHORT maxCompositePoints;//Max points in a composite glyph.
USHORT maxCompositeContours; //Max contours in a composite glyph.
USHORT maxZones;// 1 if not use the twilight zone [Z0],
//or 2 if so use Z0;2 in most cases.
USHORT max TwilightPoints ;/ Maximum points used in Z0.
USHORT maxStorage; //Number of storage area locations.
USHORT maxFunctionDefs; //Number of FDEFs.
USHORT maxStackElements; //Number of depth.
USHORT maxSizeOfInstructions; //Max byte count for glyph inst.
USHORT maxComponentElements; //Max number top components refernced.
USHORT maxComponentDepth; //Max levels of recursion.
}Table_maxp;
numGlyphs字段保存了字體中圖元的總數,這決定了到位置表的圖元索引的數量,可以用于嚴正圖元索引的有效性。TrueType字體中的每個圖元都可以是合成圖元或簡單圖元。簡單圖元可以有一條或多大體上輪廓中國,條用一些控制點定義。合成圖元用幾個其他圖元的組合來定義。maxPoints\maxCountors\maxCompositePoints maxCompositeContours這幾個字段說明了圖元定義的復雜度。
除了圖元的定義,TrueType字體還使用了圖元指令用于提示字體掃描器如何對控制點進行調整以得到更均衡更漂亮的光柵化后的圖元。圖元指令也可以出現在字體程序表(fpgm表)以及控制值程序表(“prep”)的全局字體層中。TrueType圖元指令是一個偽計算機字節指令,該機類似于Java的虛擬機,這些指令可以用堆棧計算機執行。MaxStackElements maxSizeOfInstructions兩個字段同志堆棧計算機這些指令的復雜度。
以Windings字體為例,該字體有226個圖元,圖元最多有47條輪廓線,簡單圖元最多有268個點,合成圖元最多有141個點,合成圖元最多有14條輪廓線,最壞情況下需要492層堆棧,最長的指令有1119個字節。
字符到圖元索引的映射表(cmap表)定義了從不同代碼頁中的字符 代碼到圖元索引的映射關系,這是在TrueType字體中存取圖元信息的關鍵。cmap表包含幾個了表以支持不同的平臺和不同的字符編碼方案。
下面是cmap表的結構。
typedef struct
{
USHORT Platform; //platform ID
USHORT EncodingID; //encoding ID
ULONG TableOffset ;//offset to encoding table
typedef struct {
WCHAR wcLow;
USHORT cGlyphs;
}
typedef struct
{
DWORD cbThis; //sizeof (GLYPHSET)+sizeof(WCRANGE)+(cRanges-1)
DWORD flAccel;
DWORD cGlyphsSupported;
DWORD cRanges;
WCRANGE ranges[1]; //ranges[cRanges]
}GLYPHSET;
DWORD GetFontUnicodeRanges(HDC hDC,LPGLYPHSET lpgs);
DWORD GetGlyphIndices(HDC hDC,LPCTSTR lpstr,int c ,LPWORD pgi,DWORD fl);
通常一種字體只提供UNICODE字符集中的字符的一個子集。這些字符可以被分組為多個區域,cmap映射表中就是這么做的。GetFontUnicodeRanges函數在一個GLYPHSET結構中返回支持的圖元的數量、支持的UNICODE區域的數量以及設備上下文中字體的這些區域的詳細信息。GLYPHSET是一個可變長的結構 ,其大小取決于所支持的UNICODE區域的數量。因此,和Win32 API中支持可變長結構一樣, GetFontUnicodeRanges函數通常需要調用兩 次。第一次調用時得到以NULL指針作為最后一莜參數,GDI會返回所需窨的大小。調用者然后分配所需的內存,再次調用以得到真正的數據。這兩 種情況下,GetFontUnicodeRanges函數都會返回保存整個結構所需的數據大小。MSDN文檔可能還是錯誤地描述成了如果第二個參數是NULL,GetFontUnicodeRanges函數返回指向GLYPHSET結構的指針。
下面是用于查詢上下文中當前字體GLYPHSET結構的一個簡單函數。
GLYPHSET *QueryUnicodeRanges(HDC hDC)
{
//query for size
DWORD size=GetFontUnicodeRanges(hDC,NULL);
if (size==0) return NULL;
GLYPHSET *pGlyphSet=(GLYPHSET *)new BYTE(size);
//get real data
pGlyphSet->cbThis=size;
size=GetFontUnicodeRanges(hDC,pGlyphSet);
return pGlyphSet;
}
如果在一些Windows TrueType字體上試著調用GetFontUnicodeRanges函數,你會發現這些字體通常支持1000個以上的圖元,這些圖元被分成幾百個UNICODE區域。比如,“Times New Roman”有我143個圖元,分布在145個區域中,和一個區域是0x20到0x7f,即可打印的7位ASCII代碼區域。
GetFontUnicodeRanges函數只使用了TrueType字體“cmap”表的一部分部分信息,即從UNICODE到圖元索引的映射域。GetGlyphIndices函數則能真正使用這些映射關系把一個字符串轉換為一個圖元索引的數組。它接收一個設備上下文句柄、一個字符串指針、字符串長度、一個WORD數組的指針和一個標志。生成的圖元索引將保存在WORD數組中。如果標志為GGI_MASK_NONEXISTING_GLYPHS,找不到的字符的圖元索引會被標注成0xFFFF。此函數得到的圖元索引可以傳給其他GDI函數,如ExtTextOut函數。
2.位置索引
TrueType字體中最有用的信息是glyf表中的圖元數據。有了圖元索引,要找到相應的圖元,需要表(loca表)索引以把圖元索引轉換為圖元數據表內的偏移量。
位置索引表中保存了n+1個圖元數據表的索引,其中n是保存在最大需求表中的圖元數量。最后一個額外 的偏移量并不指向一個新圖元,而是指向最后一個圖元的偏移量和當前圖元的偏移量和當前圖元的偏移量間的差值得到圖元的長度。
位置索引表中的每一個索引以無符號短整數對齊的,如果使用了短整數格式,索引表實際存儲的是WORD偏移量,而不是BYTE偏移量。這合得短整數格式的位置索引表能 支持128KB大小的圖元數據表。
3.圖元數據
圖元數據(glyf表)是TrueType字體的核心信息,因此通常它是最大的表。因為的位置索引是一張單獨的表,圖元數據表就完全只是圖元的序列而已,每個圖元以圖元頭結構開始:
typedef struct
{
WORD numberOfContours; //contor number,negative if composite
FWord xMin; //Minimum x for coordinate data.
FWord yMin; //Minimum y for coordinate data.
FWord xMax; //Maximum x for coordinate data.
FWord yMax; //Maximum y for coordinate data.
}GlyphHeader;
對于簡單圖元,numberOfContours字段中保存的是當前圖元的輪廓線的樹木;對于合成圖元,numberOfContours字段是一個負值。后者的輪廓線的總數必須基于組成該合成圖元的所有圖元的數據計算得到。GlyphHeader結構中后四個字段記錄了圖元的邊界框。
對于簡單圖元,圖元的描述緊跟在GlyphHeader結構之后。圖元的描述由幾部分信息組成:所有輪廓線結束點的索引、圖元指令和一系列的控制點。每個控制點包括一個標志以x和y坐標。概念上而言,控制所需的信息和GDI函數PolyDraw函數所需的信息相同:一組標志和一組點的坐標。但TrueType字體中的控制點的編碼要復雜得多。下面是圖元描述信息的概述:
USHORT endPtsOfContours[n]; //n=number of contours
USHORT instructionlength;
BYTE instruction[i]; //i = instruction length
BYTE flags[]; //variable size
BYTE xCoordinates[]; //variable size
BYTE yCoordinates[]; //variable size
圖元可以包含一條或多條輪廓線。比如,字母"O"有兩 條輪廓線,一條是內部的輪廓,另一條是外部的輪廓。對于每一條輪廓線,endPtsOfContours數組保存了其終點的索引,從該索引中可以計算出輪廓線中點的數量。比如,endPtsOfContours[0]是第一休輪廓線上點的數量,endPtsOfContours[1]-endPtsOfContours[0]是第二條輪廓線上點的數量。
終點數組后是圖元指令通知度和圖元指令數組。我們先跳過它們,先來討論冬至點。圖元的控制點保存在三個數組中:標志獲得組、x坐標數組和y坐標數組。找到標志數組的起始點很簡單,但是標志數組沒有相應的長度字,也沒有直接其他兩個數組的方法,你必須先解碼標志數組才能解釋x和y坐標數組。
我們提到棕em-square被限制為最大為16384個網格,因此通常情況下需要各兩個字節來表示x坐標和y坐標。為了節省空間,圖元中保存的是相對坐標。第一個點的坐標是相對(0,0)記錄的,所有隨后的點記錄者是和上一個點的坐標差值。有些差值可以用一個字節表示,有些差值為0,另外一些差值則無法用耽擱字節表示。標志數組保存了每個坐標的編碼信息以及其他一些信息。下面是標志中各個位的含義的總結:
typedef enum
{
G_ONCURVE = 0x01, // on curve ,off curve
G_REPEAT =0x08, //next byte is flag repeat count
G_XMASK =0x12,
G_XADDBYTE =0x12, //X is positive byte
G_XSUBBYTE =0x12, //X is negative byte
G_XSAME =0x10, //X is same
G_XADDINT =0x00, //X is signed word
G_YMASK =0x24,
G_YADDBYTE =0x24, //Y is positive byte
G_YSUBBYTE =0x04, //Y is negative byte
G_YSAME =0x20 , //Y is same
G_YADDINT =0x00, //Y is signed word
};
在第8章中我們討論了直線和曲線,我們提到了一段三階Bezier曲線有四個控制點定義:位于曲線上(on-curve)的起始點、兩個不在曲線上(off-curve)的控制點和一個曲線上的結束點。TureType字體中的圖元輪廓是用二階Bezier曲線定義的,有三個點:一個曲線上的點,一個曲線外的點和另一個曲線上的點。多個連續的不在曲線上的點是允許的,但不是用來定義三階或更高階的Bezier曲線,而是為了減少控制點的數目。比如,對于on-off-off-on模式的四個點,會加入一個隱含的點使之成為on-off-on-off-on,因此定義的是兩段二階Bezier曲線。
如果設置了G_ONCURVE位,那么控制點在曲線上,否則不在曲線上。如果設置了G_REPEAT,標志數組中的下一字節表示重復次數,當前標志應該重復指定的次數。因此,標志數組中實際使用了某種類型的行程編碼。標志中的其他位用于描述相應 的x坐標和y坐標的編碼方式,它們可以表示當前相尋坐標是否和上一個相同、正的單字節值、負的單字節值或有符號兩字節值。
解碼圖元的描述是一個兩次掃描的起始點。然后再遍歷圖元定義中的每一個點把它轉換為更容易管理的格式。程序清單14-2列出了解碼TrueType圖元的函數,它是KTrueType類的一個方法。
int KTrueType::DecodeGlyph(int index, KCurve & curve, XFORM * xm) const
{
const GlyphHeader * pHeader = GetGlyph(index);
if ( pHeader==NULL )
{
// assert(false);
return 0;
}
int nContour = (short) reverse(pHeader->numberOfContours);
if ( nContour<0 )
{
return DecodeCompositeGlyph(pHeader+1, curve); // after the header
}
if ( nContour==0 )
return 0;
curve.SetBound(reverse((WORD)pHeader->xMin), reverse((WORD)pHeader->yMin),
reverse((WORD)pHeader->xMax), reverse((WORD)pHeader->yMax));
const USHORT * pEndPoint = (const USHORT *) (pHeader+1);
int nPoints = reverse(pEndPoint[nContour-1]) + 1; // endpoint of last contour + 1
int nInst = reverse(pEndPoint[nContour]); // instructon length
curve.m_glyphindex = index;
curve.m_glyphsize = (int) GetGlyph(index+1) - (int) GetGlyph(index);
curve.m_Ascender = m_Ascender;
curve.m_Descender = m_Descender;
curve.m_LineGap = m_LineGap;
GetMetrics(index, curve.m_advancewidth, curve.m_lsb);
if ( curve.m_glyphsize==0 )
return 0;
curve.m_instrsize = nInst;
const BYTE * pFlag = (const BYTE *) & pEndPoint[nContour] + 2 + nInst; // first byte in flag
const BYTE * pX = pFlag;
int xlen = 0;
for (int i=0; i<nPoints; i++, pX++)
{
int unit = 0;
switch ( pX[0] & G_XMASK )
{
case G_XADDBYTE:
case G_XSUBBYTE:
unit = 1;
break;
case G_XADDINT:
unit = 2;
}
if ( pX[0] & G_REPEAT )
{
xlen += unit * (pX[1]+1);
i += pX[1];
pX ++;
}
else
xlen += unit;
}
const BYTE * pY = pX + xlen;
int x = 0;
KTrueType類處理TrueType字體的裝入和解碼,隨書光盤中有它的完整源代碼。DecodeGlyph給出圖元索引和可選的變換矩陣,處理的是單個圖元的解碼。參數curve是KCurve類,用于把TrueType圖元定義保存為32位的點的贖罪以及一個標志數組,以梗用GDI進行顯示。這些代碼可以作為簡單TrueType字體編輯器的基礎。
代碼中調用了GetGlyph方法,該方法用位置表索引找到該圖元的GlyphHeader結構。從中得到圖元的輪廓線數目。注意必須反轉該值的字節序,因為TrueType字體用的是Big-Endian字節序。如果該值為負值,說明這是一個合成圖元,應該轉而調用DecodeCompositeGlyph方法。接下支的代碼定位了endPtsOfContours數組,找出點的總數,然后跳過指令找到標志數組的起始位置。
接下去需要長到的是x坐標數組的始位置和長度,這需要遍歷標志數組一次。對于每一個控制點,它在x坐標數組中所占空間可能為0到2個字節,這取決于它的相對坐標是0、單個字節還是兩個字節。
根據x坐標數組的地址和長度可以得到y坐標的地址。接下去的代碼遍歷所有的輪廓線,解碼其中的控制點,把相對坐標轉換為絕對坐標,然后把它加入到曲線對象中。如果需要的話,會對每個控制點做變換。
回想一下,TrueType使用的是二階Bezier曲線,允許在兩個曲線上的點之間有多個不在曲線上的點。為了簡化曲線繪制算法,KCurve::Add方法在每兩個不在曲線上的點之間加入一個額外的在曲線上的點。
處理了簡單圖元之后,我們來看看合成圖元。合成圖元用一個經變換的圖元序列定義。每個經變換的圖元的定義包括三個部分:一個標志、一個圖元索引和一個變換矩陣。標志字段決定了變換矩陣的編碼方式。編碼的目的也是為了節省一些空間,加外還說明了是否已到達序列的終點。一個完整的2D affine變換需要6個值。但如果只是平移的話,只需要兩個值(dx,dy),這兩個值可以保存為兩個字節或兩個字。如果x和y以相同的值縮放,加外還需要一個縮放值。取一般的情況下仍然需要6個值,但是很多時候可以節省幾個字節。用于變換的值以2.14的有符號定點格式保存,dx和dy值除外,這兩個值以整數形式保存。得到合成圖元的過程實際上是變換和組合幾個圖元的過程。比如,如果字體中的一個圖元是另一個圖元的精確鏡像,它只需定義為一個合成圖元,可以通過對另一個圖像做鏡像變換即可。程序清單14-3列出了解碼合成圖元的代碼。
int KTrueType::DecodeCompositeGlyph(const void * pGlyph, KCurve & curve) const
{
KDataStream str(pGlyph);
unsigned flags;
int len = 0;
do
{
flags = str.GetWord();
unsigned glyphIndex = str.GetWord();
// Argument1 and argument2 can be either x and y offsets to be added to the glyph or two point numbers.
// In the latter case, the first point number indicates the point that is to be matched to the new glyph.
// The second number indicates the new glyph's "matched" point. Once a glyph is added, its point numbers
// begin directly after the last glyphs (endpoint of first glyph + 1).
// When arguments 1 and 2 are an x and a y offset instead of points and the bit ROUND_XY_TO_GRID is set to 1,
// the values are rounded to those of the closest grid lines before they are added to the glyph.
// X and Y offsets are described in FUnits.
signed short argument1;
signed short argument2;
if ( flags & ARG_1_AND_2_ARE_WORDS )
{
argument1 = str.GetWord(); // (SHORT or FWord) argument1;
argument2 = str.GetWord(); // (SHORT or FWord) argument2;
}
else
{
argument1 = (signed char) str.GetByte();
argument2 = (signed char) str.GetByte();
}
signed short xscale, yscale, scale01, scale10;
xscale = 1;
yscale = 1;
scale01 = 0;
scale10 = 0;
if ( flags & WE_HAVE_A_SCALE )
{
xscale = str.GetWord();
yscale = xscale; // Format 2.14
}
else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE )
{
xscale = str.GetWord();
yscale = str.GetWord();
}
else if ( flags & WE_HAVE_A_TWO_BY_TWO )
{
xscale = str.GetWord();
scale01 = str.GetWord();
scale10 = str.GetWord();
yscale = str.GetWord();
}
if ( flags & ARGS_ARE_XY_VALUES )
{
XFORM xm;
xm.eDx = (float) argument1;
xm.eDy = (float) argument2;
xm.eM11 = xscale / (float) 16384.0;
xm.eM12 = scale01 / (float) 16384.0;
xm.eM21 = scale10 / (float) 16384.0;
xm.eM22 = yscale / (float) 16384.0;
len += DecodeGlyph(glyphIndex, curve, & xm);
}
else
assert(false);
}
while ( flags & MORE_COMPONENTS );
if ( flags & WE_HAVE_INSTRUCTIONS )
{
unsigned numInstr = str.GetWord();
for (unsigned i=0; i<numInstr; i++)
str.GetByte();
}
// The purpose of USE_MY_METRICS is to force the lsb and rsb to take on a desired value.
// For example, an i-circumflex (Unicode 00ef) is often composed of the circumflex and a dotless-i.
// In order to force the composite to have the same metrics as the dotless-i,
// set USE_MY_METRICS for the dotless-i component of the composite. Without this bit,
// the rsb and lsb would be calculated from the HMTX entry for the composite (or would need to be
// explicitly set with TrueType instructions).
// Note that the behavior of the USE_MY_METRICS operation is undefined for rotated composite components.
return len;
}
DecodeCompositeGlyph方法解碼每個圖元的標志、圖元索引和變換矩陣,然后調用DecodeGlypgh方法進行解碼。注意,對DecodeGlyph方法的調用包含一個有效的變換矩陣參數。當MORE_COMPONENTS標志結束時,該方法隨之結束。隨書光盤中有該方法完整的源代碼。
解碼后的TrueType字體的圖元要用GDI繪制還有一個小問題需要處理。GDI只繪制三階Bezier曲線,因此從圖元表解碼所得的二階Bezier曲線的控制點需要轉換為三階Bezier曲線的控制點。通過對Bezier曲線原始數學定義的研究,可以得到如下用GDI繪制二階Bezier曲線的簡單例程。
//draw a 2nd-degree Bezier curve segment
BOOL Bezier2(HDC hDC,int & x0,int & y0, int x1, int y1, int x2 ,int y2)
{
// p0 p1 p2 - > p0 (p0 + 2p1)/3 (2p1+p2)/3, p2
POINT P[3] = { { (x0+2*x1)/3,(y0+2*y1)/3},
{(2*x1+x2)/3,(2*y1+y2)/3},
{x2,y2} };
x0=x2;y0=y2;
return PolyBezierTo(hDC,P,3);
}
對于用三個控制點(p0,p1,p2)定義的二階Bezier曲線,相應的三階Bezier曲線的控制點為(p0,(p0+2*p1)/3,(2*p1+p2)/3,p2)。
4.圖元指令
程序清單14-2和14-3給人的印象是TrueType字體的柵格器可以通過掃描和轉換圖元的輪廓來輕松地實現,比如,用GDI和StrokeAndFillPath函數來填充圖元輪廓繪制出來的路徑。這種簡單的字體柵格器的實現并不是很有用,除非它只用于高分辨詣的設備如打印機等。
簡單柵格器得到的圖像筆畫粗細不一,有信息的遺漏,有字符特征的損失以及不對稱等缺陷。當點陣變小是,情況不會更糟。總之,簡單字體柵格器在小尺寸時會產生字跡模糊的結果。在大尺寸時會產生不好看的結果,只有在點陣增大時結果才會改善。
當在大的em-square(典型的是2048)中定義的圖元輪廓縮小為小得多的網格時(如32*32),不可避免會損失精度并引入誤差。
TrueType解決這個問題的方法是控制圖元輪廓從em-square到柵格網格的縮放過程,使得到的結果看起來效果更好,和原始圖元的設計盡量接近。這種技術被稱為網格調整(grid fitting),它想達到的目標有:
消除網格位置的可能影響,保證筆畫的粗細和網格的相對位置無關。
控制圖元中關鍵位置的尺寸
保持對稱性和襯線等 重要的圖元設計細節。
TrueType字體中網格調整的需求在兩個地方中編碼:控制值表(control value table)和每個圖元的網格調整指令。
控制值表("cvt"表)用于保存一個數組,這些值被稱為網格調整指令。比如,對于有襯線的字體,基線、襯線高度、大寫字母筆劃的寬度等值都或以是被控制的值。它們可以以字體設計者已知的次序保存在控制值表中,然后用它們的索引來引用。在字體光柵化過程中,控制值表中的值根據點陣的大小縮放。在網絡調整指令中引用這些值 可以保證使用的值與網枸的位置無關。比如,如果水平線[14,0,25,200]可以用CVT表中的兩個值定義為[14,0,14+CVT[stem_width],0+CVT[cap_height]],那 么該線的寬度和高度會和所在網格的相對位置無關,保持不變。
每一個圖元的定義中附加有一個指令序列,該指令序列被稱為圖元指令,該背景令序列用于控制此圖元的網格高速。圖元指令線用控制值表中的值,以保證在索引圖元中這些值相同。
圖元指令是一種基于堆棧的偽計算機的指令。堆棧計算機常用于計算機語言的解釋性實現。比如,Forth(用于嵌入式系統的一種強大而簡潔的語言)、RPL(HP計算器使用的語言)和Java虛擬機都是堆棧計算機。
堆棧計算機通常沒有寄存器,所有的計算都在堆棧上進行(有些堆棧計算機使用分開的控制堆棧和數據堆棧)。比如,壓入指令把一個值壓入堆棧,彈出指令從堆棧中彈出上面的值,二元加法指令彈出上面的兩 個值 ,然后把它們的和壓入堆棧。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/clq271520093/archive/2008/01/17/2048257.aspx
GB2312碼是中華人民共和國國家漢字信息交換用編碼,全稱《信息交換用漢字編碼字符集——基本集》,由國家標準總局發布,1981年5月1日實施,通行于大陸。新加坡等地也使用此編碼。
GB2312收錄簡化漢字及符號、字母、日文假名等共7445個圖形字符,其中漢字占6763個。GB2312規定“對任意一個圖形字符都采用兩個字節表示,每個字節均采用七位編碼表示”,習慣上稱第一個字節為“高字節”,第二個字節為“低字節”。
GB2312將代碼表分為94個區,對應第一字節;每個區94個位,對應第二字節,兩個字節的值分別為區號值和位號值加32(2OH),因此也稱為區位碼。01-09區為符號、數字區,16-87區為漢字區,10-15區、88-94區是有待進一步標準化的空白區。GB2312將收錄的漢字分成兩級:第一級是常用漢字計3755個,置于16-55區,按漢語拼音字母/筆形順序排列;第二級漢字是次常用漢字計3008個,置于56-87區,按部首/筆畫順序排列。故而GB2312最多能表示6763個漢字。
為了使每一個漢字有一個全國統一的代碼,1980年,我國頒布了第一個漢字編碼的國家標準:GB2312-80《信息交換用漢字編碼字符集》基本集,這個字符集是我國中文信息處理技術的發展基礎,也是目前國內所有漢字系統的統一標準。到了后來又公布了國家標準GB18030-2000《信息交換用漢字編碼字符集基本集的擴充》,簡稱GB18030。由于國標碼是四位十六進制,為了便于交流,大家常用的是四位十進制的區位碼。所有的國標漢字與符號組成一個94×94的矩陣。在此方陣中,每一行稱為一個"區",每一列稱為一個"位",因此,這個方陣實際上組成了一個有94個區(區號分別為0 1到94)、每個區內有94個位(位號分別為01到94)的漢字字符集。一個漢字所在的區號和位號簡單地組合在一起就構成了該漢字的"區位碼"。在漢字的區位碼中,高兩位為區號,低兩位為位號。在區位碼中,01-09區為682個特殊字符,16-87區為漢字區,包含6763個漢字 。其中16-55區為一級漢字(3755個最常用的漢字,按拼音字母的次序排列),56-87區為二級漢字(3008個漢字,按部首次序排列)。
從漢字到區位碼的轉換。區位碼是與漢字一一對應的編碼,用四位數字表示, 前兩位從01 到94稱區碼,后兩位從01到94稱位碼。 一個漢字的前一半為“160+區碼”的字符,后一半為“160+ 位碼”的字符。例如:“劉”的區位碼是 3385,其意為區碼33位碼85,它是由160+33=193和160+85=245的兩個字節組成。即 0xC1F5,它就是漢字的 gb2312 編碼。
下面程序將漢字 gb2312 轉為相應的區位碼:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
// temp[0] 為高字節,temp[1] 為低字節
// 當輸入單個 ascii 字符時,只存進 temp[0]
// 當輸入的不是中文或單個 ascii 字符時,程序退出
unsigned char temp[2];
cin >> temp;
while(temp[1])
{
cout << setw(2) << setfill('0') << temp[0] - 160; // 高 2 位
cout << setw(2) << setfill('0') << temp[1] - 160 << endl; // 低 2 位
// 輸入下一個字符前,先將 temp[1] 清零
temp[1] = 0;
cin >> temp;
}
return 0;
}
字符編碼簡介
Unicode是一種字符編碼規范。先從ASCII說起。ASCII是用來表示英文字符的一種編碼規范,每個ASCII字符占用1個字節(8bits)。因此,ASCII編碼可以表示的最大字符數是256,其實英文字符并沒有那么多,一般只用前128個(最高位為0),其中包括了控制字符、數字、大小寫字母和其他一些符號 。而最高位為1的另128個字符被成為“擴展ASCII”,一般用來存放英文的制表符、部分音標字符等等的一些其他符號。這種字符編碼規范顯然用來處理英文沒有什么問題。(實際上也可以用來處理法文、德文等一些其他的西歐字符,但是不能和英文通用),但是面對中文、阿拉伯文之類復雜的文字,255個字符顯然不夠用,于是,各個國家紛紛制定了自己的文字編碼規范,其中中文的文字編碼規范叫做“GB2312-80”,它是和ASCII兼容的一種編碼規范,其實就是利用擴展ASCII沒有真正標準化這一點,把一個中文字符用兩個擴展ASCII字符來表示。但是這個方法有問題,最大的問題就是,中文文字沒有真正屬于自己的編碼,因為擴展ASCII碼雖然沒有真正的標準化,但是PC里的ASCII碼還是有一個事實標準的(存放著英文制表符),所以很多軟件利用這些符號來畫表格。這樣的軟件用到中文系統中,這些表格符就會被誤認作中文字,破壞版面。而且,統計中英文混合字符串中的字數,也是比較復雜的,我們必須判斷一個ASCII碼是否擴展,以及它的下一個ASCII是否擴展,然后才“猜”那可能是一個中文字 。
總之當時處理中文是很痛苦的。而更痛苦的是GB2312是國家標準,臺灣當時有一個Big5編碼標準,很多編碼和GB是相同的,所以……,嘿嘿。這時候,我們就知道,要真正解決中文問題,不能從擴展ASCII的角度入手,也不能僅靠中國一家來解決。而必須有一個全新的編碼系統,這個系統要可以將中文、英文、法文、德文……等等所有的文字統一起來考慮,為每個文字都分配一個單獨的編碼,這樣才不會有上面那種現象出現。于是,Unicode誕生了。
Unicode有兩套標準,一套叫UCS-2(Unicode-16),用2個字節為字符編碼,另一套叫UCS-4(Unicode-32),用4個字節為字符編碼。以目前常用的UCS-2為例,它可以表示的字符數為2^16=65535,基本上可以容納所有的歐美字符和絕大部分的亞洲字符 。UTF-8的問題后面會提到。在Unicode里,所有的字符被一視同仁。漢字不再使用“兩個擴展ASCII”,而是使用“1個Unicode”,注意,現在的漢字是“一個字符”了,于是,拆字、統計字數這些問題也就自然而然的解決了。但是,這個世界不是理想的,不可能在一夜之間所有的系統都使用Unicode來處理字符,所以Unicode在誕生之日,就必須考慮一個嚴峻的問題:和ASCII字符集之間的不兼容問題。我們知道,ASCII字符是單個字節的,比如“A”的ASCII是65。而Unicode是雙字節的,比如“A”的Unicode是0065,這就造成了一個非常大的問題:以前處理ASCII的那套機制不能被用來處理Unicode了。另一個更加嚴重的問題是,C語言使用'\0'作為字符串結尾,而Unicode里恰恰有很多字符都有一個字節為0,這樣一來,C語言的字符串函數將無法正常處理Unicode,除非把世界上所有用C寫的程序以及他們所用的函數庫全部換掉。于是,比Unicode更偉大的東東誕生了,之所以說它更偉大是因為它讓Unicode不再存在于紙上,而是真實的存在于我們大家的電腦中。那就是:UTF。UTF = UCS Transformation Format UCS轉換格式。它是將Unicode編碼規則和計算機的實際編碼對應起來的一個規則。現在流行的UTF有2種:UTF-8和UTF-16。其中UTF-16和上面提到的Unicode本身的編碼規范是一致的,這里不多說了。而UTF-8不同,它定義了一種“區間規則”,這種規則可以和ASCII編碼保持最大程度的兼容。UTF-8有點類似于Haffman編碼,它將Unicode編碼為00000000-0000007F的字符,用單個字節來表示;00000080-000007FF的字符用兩個字節表示00000800-0000FFFF的字符用3字節表示。因為目前為止Unicode-16規范沒有指定FFFF以上的字符,所以UTF-8最多是使用3個字節來表示一個字符。但理論上來說,UTF-8最多需要用6字節表示一個字符。在UTF-8里,英文字符仍然跟ASCII編碼一樣,因此原先的函數庫可以繼續使用。而中文的編碼范圍是在0080-07FF之間,因此是2個字節表示(但這兩個字節和GB編碼的兩個字節是不同的),用專門的Unicode處理類可以對UTF編碼進行處理。
下面說說中文的問題。由于歷史的原因,在Unicode之前,一共存在過3套中文編碼標準。GB2312-80,是中國大陸使用的國家標準,其中一共編碼了6763個常用簡體漢字。Big5,是臺灣使用的編碼標準,編碼了臺灣使用的繁體漢字,大概有8千多個。HKSCS,是中國香港使用的編碼標準,字體也是繁體,但跟Big5有所不同。這3套編碼標準都采用了兩個擴展ASCII的方法,因此,幾套編碼互不兼容,而且編碼區間也各有不同。因為其不兼容性,在同一個系統中同時顯示GB和Big5基本上是不可能的。后來,由于各方面的原因,國際上又制定了針對中文的統一字符集GBK和GB18030,其中GBK已經在Windows、Linux等多種操作系統中被實現。GBK兼容GB2312,并增加了大量不常用漢字,還加入了幾乎所有的Big5中的繁體漢字。但是GBK中的繁體漢字和Big5中的幾乎不兼容。GB18030相當于是GBK的超集,比GBK包含的字符更多。
談談Unicode編碼,簡要解釋UCS、UTF、BMP、BOM等名詞
這是一篇程序員寫給程序員的趣味讀物。所謂趣味是指可以比較輕松地了解一些原來不清楚的概念,增進知識,類似于打RPG游戲的升級。整理這篇文章的動機是兩個問題:
問題一:
使用Windows記事本的“另存為”,可以在GBK、Unicode、Unicode big endian和UTF-8這幾種編碼方式間相互轉換。同樣是txt文件,Windows是怎樣識別編碼方式的呢?
Unicode、Unicode big endian和UTF-8編碼的txt文件的開頭會多出幾個字節,分別是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但這些標記是基于什么標準呢?
問題二:
最近在網上看到一個ConvertUTF.c,實現了UTF-32、UTF-16和UTF-8這三種編碼方式的相互轉換。對于Unicode(UCS2)、GBK、UTF-8這些編碼方式,我原來就了解。但這個程序讓我有些糊涂,想不起來UTF-16和UCS2有什么關系。
查了查相關資料,總算將這些問題弄清楚了,順帶也了解了一些Unicode的細節。寫成一篇文章,送給有過類似疑問的朋友。本文在寫作時盡量做到通俗易懂,但要求讀者知道什么是字節,什么是十六進制。
0、big endian和little endian
big endian和little endian是CPU處理多字節數的不同方式。例如“漢”字的Unicode編碼是6C49。那么寫到文件里時,究竟是將6C寫在前面,還是將49寫在前面?如果將6C寫在前面,就是big endian。若是將49寫在前面,就是little endian。
1、字符編碼、內碼,順帶介紹漢字編碼
字符必須編碼后才能被計算機處理。計算機使用的缺省編碼方式就是計算機的內碼。早期的計算機使用7位的ASCII編碼,為了處理漢字,程序員設計了用于簡體中文的GB2312和用于繁體中文的big5。
從ASCII、GB2312、GBK到GB18030,這些編碼方法是向下兼容的,即同一個字符在這些方案中總是有相同的編碼,后面的標準支持更多的字符。在這些編碼中,英文和中文可以統一地處理。區分中文編碼的方法是高字節的最高位不為0。按照程序員的稱呼,GB2312、GBK到GB18030都屬于雙字節字符集 (DBCS)。
有的中文Windows的缺省內碼還是GBK,可以通過GB18030升級包升級到GB18030。不過GB18030相對GBK增加的字符,普通人是很難用到的,通常我們還是用GBK指代中文Windows內碼。
在DBCS中,GB內碼的存儲格式始終是big endian,即高位在前。GB2312的兩個字節的最高位都是1。但符合這個條件的碼位只有128*128=16384個。所以GBK和GB18030的低字節最高位都可能不是1。不過這不影響DBCS字符流的解析:在讀取DBCS字符流時,只要遇到高位為1的字節,就可以將下兩個字節作為一個雙字節編碼,而不用管低字節的高位是什么。
2、Unicode、UCS和UTF
前面提到從ASCII、GB2312、GBK到GB18030的編碼方法是向下兼容的。而Unicode只與ASCII兼容(更準確地說,是與ISO-8859-1兼容),與GB碼不兼容。例如“漢”字的Unicode編碼是6C49,而GB碼是BABA。
Unicode也是一種字符編碼方法,不過它是由國際組織設計,可以容納全世界所有語言文字的編碼方案。Unicode的學名是"Universal Multiple-Octet Coded Character Set",簡稱為UCS。UCS可以看作是"Unicode Character Set"的縮寫。UCS規定了怎么用多個字節表示各種文字。怎樣傳輸這些編碼,是由UTF(UCS Transformation Format)規范規定的,常見的UTF規范包括UTF-8、UTF-7、UTF-16。
3、UTF編碼
UTF-8就是以8位為單元對UCS進行編碼。從UCS-2到UTF-8的編碼方式如下:
UCS-2編碼(16進制) UTF-8 字節流(二進制)
0000 - 007F 0xxxxxxx
0080 - 07FF 110xxxxx 10xxxxxx
0800 - FFFF 1110xxxx 10xxxxxx 10xxxxxx
例如“漢”字的Unicode編碼是6C49。6C49在0800-FFFF之間,所以肯定要用3字節模板了:1110xxxx 10xxxxxx 10xxxxxx。將6C49寫成二進制是:0110 110001 001001, 用這個比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。
UTF-16以16位為單元對UCS進行編碼。對于小于0x10000的UCS碼,UTF-16編碼就等于UCS碼對應的16位無符號整數。對于不小于0x10000的UCS碼,定義了一個算法。不過由于實際使用的UCS2,或者UCS4的BMP必然小于0x10000,所以就目前而言,可以認為UTF-16和UCS-2基本相同。但UCS-2只是一個編碼方案,UTF-16卻要用于實際的傳輸,所以就不得不考慮字節序的問題。
4、UTF的字節序和BOM
UTF-8以字節為編碼單元,沒有字節序的問題。UTF-16以兩個字節為編碼單元,在解釋一個UTF-16文本前,首先要弄清楚每個編碼單元的字節序。例如收到一個“奎”的Unicode編碼是594E,“乙”的Unicode編碼是4E59。如果我們收到UTF-16字節流“594E”,那么這是“奎”還是“乙”?Unicode規范中推薦的標記字節順序的方法是BOM。是Byte Order Mark。BOM是一個有點小聰明的想法:在UCS編碼中有一個叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的編碼是FEFF。而FFFE在UCS中是不存在的字符,所以不應該出現在實際傳輸中。UCS規范建議我們在傳輸字節流前,先傳輸字符"ZERO WIDTH NO-BREAK SPACE"。這樣如果接收者收到FEFF,就表明這個字節流是Big-Endian的;如果收到FFFE,就表明這個字節流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被稱作BOM。
UTF-8不需要BOM來表明字節順序,但可以用BOM來表明編碼方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8編碼是EF BB BF。所以如果接收者收到以EF BB BF開頭的字節流,就知道這是UTF-8編碼了。Windows就是使用BOM來標記文本文件的編碼方式的。
在處理圖形運算,特別是3D圖形生成運算時,往往要定義一個Fixed數據類型,我稱它為定點數,定點數其時就是一個整形數據類型,他的作用就是把所有數進行轉換,從而得到相應類型的整型表達,然后使用定點數進行整行運算,取到最終值并將其轉換回實際的基本數據類型。因此它是通過避免大量的浮點運算來加快圖形處理的一個方式。
現在來定義下定點數的轉換法則,定點數有8位單字節轉換或16位雙字節轉換:區別只是一個要8移位,一個要做16移位
8位
typedef long FIXED; // long型定點類型
#define itofx(i_x) ((i_x) << 8) // 整轉定點
#define ftofx(f_x) (long)((f_x) * 256) // 浮點轉定點
#define dtofx(d_x) (long)((d_x) * 256) // 雙精度轉定點
#define fxtoi(fx_x) ((fx_x) >> 8) // 定點轉整
#define fxtof(fx_x) ((float) (fx_x) / 256) // 定點轉浮點
#define fxtod(fx_x) ((double)(fx_x) / 256) // 定點轉雙精度
#define Mulfx(fx_x,fx_y) (((fx_x) * (fx_y)) >> 8) // 定點積得定點
#define Divfx(fx_x,fx_y) (((fx_x) << 8) / (fx_y)) // 定點除得定點
16位
typedef int FIXED; // long型定點類型
#define itofx(i_x) ((i_x) << 16) // 整轉定點
#define ftofx(f_x) (long)((f_x) * 65536) // 浮點轉定點
#define dtofx(d_x) (long)((d_x) * 65536) // 雙精度轉定點
#define fxtoi(fx_x) ((fx_x) >> 16) // 定點轉整
#define fxtof(fx_x) ((float) (fx_x) / 65536) // 定點轉浮點
#define fxtod(fx_x) ((double)(fx_x) / 65536) // 定點轉雙精度
#define Mulfx(fx_x,fx_y) (((fx_x) * (fx_y)) >> 16) // 定點積得定點
#define Divfx(fx_x,fx_y) (((fx_x) << 16) / (fx_y)) // 定點除得定點
3D圖形計算一般會用到16位的,2D圖形計算一般會用到8位的,本著實用的原則定義定點數類型
Fixed是業界使用最廣的一種類型,他并沒有在標準C或者其他語言中定義,程序員可以靈活的使用Fixed類型,可以定義自己想要的Fixed類型。那么什么是Fixed類型呢?Fixed類型是用來取代浮點,使用4字節的高2個字節表示整數位,低2個字節表示浮點位。每個字節有8個bit位,4個字節32個bit位,因此,我們把這種Fixed稱為16.16Fixed。當然,也有使用24.8的Fixed,這就要看需求和精確度了。比如Fixed中的數字1,就是65536,也就是(1<<16)。這里用了位移公式,就是將1左移16位,也就是2個字節,左移16等于剩以65536,只不過位移來的非常快,快過加法。(這里理解不了就算了)比如數字32.5,等于(32<<16)|32768,等于32*65536+32768。為什么要這么麻煩呢?有了Fixed,就好像操作整數一樣,都是整數運算了。Fixed的四舍五入也很簡單,比如我們將X四舍五入到整數類型,就是(X+32768)>>16。32768就是半個Fixed的1,也就是浮點的0.5。右移16位就是除以65536,為的是將高2字節移到正常的整數位上。我都說暈了,以后慢慢解釋給大家,呵呵。
Fixed類型說了一堆,究竟來做什么的?
比如上例中,Y軸每次都要偏移0.4,而這個數是個浮點,嚴重影響了運算速度。比如,我們后臺有一個數,用來計量Y軸本次的坐標,就叫做變量YY吧。X每次都加1,也就是XX++,Y每次加0.4,也就是YY+=0.4。為了提高速度,我們將YY升級到Fixed類型,YY每次加Fixed的0.4,也就是0.4*65536=26214,然后再四舍五入到整數類型,即YY+=26214,Y=(YY+32768)>>16。這樣,就得到了每次的整數Y,并且都是整數的加減和位運算,速度非常快
軟件安裝分為以下幾個部分:
1、 Java環境安裝:
這里使用的是jdk-1_5_0_05-windows-i586-p.exe,這個可以到sun公司的網站去下載:http://java.sun.com/。
下載完成后,即可安裝J2SE-SDK到D:\jsk目錄下(其他目錄下也可以)。
配置環境變量如下:
JAVA_HOME = D:\jdk
PATH=%JAVA_HOME%\bin;%JAVA_HOME%\lib;%JAVA_HOME%\jre\lib;
CLASSPATH = %JAVA_HOME%\lib;%JAVA_HOME%\jre\lib;
2、 Tomcat 安裝與環境變量設置:
Web Server選擇流行的Apache Tomcat 5.0.28,到 http://tomcat.apache.org/ 處下載,建議使用非安裝的壓縮版,有一點需要注意,Apache Tomcat不支持EJB,因此如果要進行EJB開發,那么就不要選擇Apache Tomcat。 安裝tomcat到D:\Tomcat目錄下。
運行Monitor Tomcat 然后打開http://localhost:8080/ ,出現 Tomcat頁面則安裝成功。
配置環境變量如下:
TOMCAT_HOME = D:\Tomcat
3.Eclipse 下載與安裝
Eclipse Release 3.2 SDK 可從
http://www.eclipse.org/downloads/download.php?file=/eclipse/downloads/drops/R-3.2-200606291905/eclipse-SDK-3.2-win32.zip下載
下載完的解壓包可以直接解壓到D:\eclipse,就完成安裝
4.TomcatPlugin插件安裝:
下載安裝Sysdeo Tomcat插件,用來管理Tomcat服務器,提供斷點調試功能,并且能自動建立Tomcat環境,修改其配置文件,是一個不錯的Tomcat開發插件。
英文原版下載地址:http://www.sysdeo.com/sysdeo/eclipse/tomcatplugin
解壓tomcatPluginV31.zip,
將解壓目錄下文件夾com.sysdeo.eclipse.tomcat_3.1復制到eclipse安裝目錄中的plugins目錄中,即D:\eclipse\plugins。啟動Eclipse,啟動后你將看到你的菜單上多了一個下拉項Tomcat,點擊 窗口->首選項,在左邊樹中點擊tomcat,設置tomcat version為version 5.x,設置tomcat根目錄為D:\tomcat,在左邊樹中點擊tomcat->JVM setting,設置JRE為jdk(即jre所在目錄)。
5.MyEclipse 的安裝與插入Eclipse
在http://www.myeclipseide.com/ 下載MyEclipse_5.1.1后,安裝,注意:安裝時候要選擇Eclipse的安裝路徑,其他選項保持默認。
安裝完畢之后,將MyEclipse安裝目錄下的features和plugins文件里的全部文件復制到Eclipse下的features和plugins文件中。復制完后可以將MyEclipse卸載。
啟動Eclipse,依次點擊Window ----> Preferences ---->MyEclipse---->Subscription ----> Enter Subscription,輸入注冊名以及注冊機生成的注冊碼(myeclipse5.0注冊碼License Name : yjhmily ,License Key : lLR8ZC-444-55-4467865759095168)
到此,一個JSP開發環境配置成功。
rt.jar ,dt.jar ,tool.jar都是 做什么用的 ,分別什么時候需要設置到classpath里?
---------------------------------------------------------------
rt.jar是JAVA基礎類庫,dt.jar是關于運行環境的類庫,tools.jar是工具類庫
設置在classpath里是為了讓你 import *
---------------------------------------------------------------
web系統都用到tool.jar
你用winrar看看里面是什么內容啦
---------------------------------------------------------------
1.
rt.jar 默認就在 根classloader的加載路徑里面 放在claspath是多此一舉
不信你可以去掉classpath里面的rt.jar
然后用 java -verbose XXXX 的方式運行一個簡單的類 就知道 JVM的系統根Loader的路徑里面
不光rt.jar jre\lib下面的大部分jar 都在這個路徑里
2.
tools.jar 是系統用來編譯一個類的時候用到的 也就是javac的時候用到
javac XXX.java
實際上就是運行
java -Calsspath=%JAVA_HOME%\lib\tools.jar xx.xxx.Main XXX.java
javac就是對上面命令的封裝 所以tools.jar 也不用加到classpath里面
3.
dt.jar是關于運行環境的類庫,主要是swing的包 你要用到swing時最好加上
在這里只講安裝的過程,介于如何下載安裝所需的軟件非常簡單,就不再嗷述,望見諒。這里主要以我的安裝過成給大家分享
jsp 安裝過程和先后順序:
1 、jdk1.5 (需要設置環境變量)
2 、eclipse+多國語言包
3 、tomcat 5.5
4、 myeclipse 5.0 (注意路徑的選擇)
jsp安裝的順序和所要注意的問題及變量的設置具體方法如下:
一、先安裝 JDK1.5
具體安裝不說了,主要講環境變量的設置。
安裝完 jdk1.5.0 以后,設置環境變量:右擊“我的電腦”→屬性→高級→環境變量→在“系統變量”中設置JAVA_HOME、Path 和CLASSPATH,如果沒有,請在“系統變量”點擊“新建”。(比如JAVA_HOME沒有,在點“新建”后,先在“變量名”中輸入“JAVA_HOME”,再在“變量值”中輸入“C:\Program Files\Java\jdk1.5.0_06
”),如果已經存在,就點“編輯”,在它的最前面或最后面加上“變量值”。
我的環境變量(沒有請“新建”,有則點“編輯”):
1、名:JAVA_HOME(不分大小寫,以下各步均相同),(沒有請“新建”,有則點“編輯”)
值:C:\Program Files\Java\jdk1.5.0_06(C代表JDK安裝在C盤,后面的 \Program Files\Java\ 是安裝后JDK的路徑,\jdk1.5.0_06是JDK的具體位置)
2、Path (沒有請“新建”,有則“編輯”)
值:%JAVA_HOME%\bin;
3、CLASSPATH(沒有請“新建”,有則“編輯”)
值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; (要加點“.”表示當前路徑)
4、鍵入命令“java -version”(這里先打“java”,空格鍵,然后才是 “-version”,注意是:java+空格鍵+ -version)出現圖面,表示成功!!!
補充:配置環境變量
JAVA_HOME: D: \jdk1.5.0 (這里的JDK安裝在D盤)
PATH: D:\jdk1.5.0\bin; (或者%JAVA_HOME%\bin;)
CLASSPATH: .;D:\jdk1.5.0\lib\tools.jar;D:\jdk1.5.0\jre\lib\rt.jar;
(或者:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar )
注意:在設置CLASSPATH時,一定要注意設置變量值時先輸入點和分號“.;”以后才是后面的\jdk..........或%java-home...............
二、安裝eclipse
其實“安裝eclipse”這個詞放在eclipse上,好像有些步正確,因為他并不需要安裝,只要jdk安裝好了,直接壓縮就可以使用,但為了便于理解,還是叫他安裝吧。下面:
直接解壓eclipse-SDK-3.2-win32.zip到名為eclipse的文件夾,再解壓NLpack1-eclipse-SDK-3.2-win32到文件夾,得到features和plugins兩個文件夾,把features和plugins兩個文件夾拷貝到eclipse里面(全部替換原有的features和plugins兩個文件夾)
安裝eclipse多國語言包插件:
在解壓eclipse-SDK-3.2-win32.zip到名為eclipse的文件夾中新建一個文件夾links,在links里新建一個文本文件并重命名為language.links(擴展名隨便),內容為:
path=path=E:\java\eclipse\language
注意路徑要跟你的language目錄一致。(且一定都是英文的目錄才可以!!如果你是FAT32格式的話,那么可以是中文目錄,如果你是NTFS的話,那就必須是全英文目錄了,目前我測試都是這樣)
總結:1.首先安裝完語言包(下載頁面:http://eclipse.cdpa.nsysu.edu.tw/downloads/drops/L-3.2_Language_Packs-200607121700/download.php?dropFile=NLpack1-eclipse-SDK-3.2-win32.zip)。
2.在桌面的快捷方式(在你解壓縮后的那個文件夾里的月食圖標“右擊”→發送到桌面→快捷方式 來建立)路徑后面加上參數即可:
英文-> -nl "en_US"
簡體-> -nl "zh_CN"
繁體-> -nl "zh_TW"
其它語言按java標準類推.
在桌面上建立了它的快捷方式,直接點擊它時,eclipse出現的界面是中文的了;當在路徑后面加入參數 -nl "en_US",(即
E:\java\eclipse\eclipse.exe -nl "en_US")時,界面又成英文了
三、安裝tomcat 5.5
安裝Tomcat后,在我的電腦->屬性->高級->環境變量->系統變量中添加以下環境變量(假定你的tomcat安裝在c:\tomcat):
CATALINA_HOME=c:\tomcat
CATALINA_BASE=c:\tomcat
然后修改環境變量中的classpath,把tomat安裝目錄下的common\lib下的(可以根據實際追加)servlet.jar追加到classpath中去,修改后的classpath如下:
classpath=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;%CATALINA_HOME%\common\lib\servlet.jar;
接著可以啟動tomcat,在IE中訪問http://localhost:8080,如果看到tomcat的歡迎頁面的話說明安裝成功了。
四、安裝myeclipse 5.0
在選擇路徑中,路徑選擇eclipse目錄,即eclise的安裝所在路徑
安裝完畢,啟動eclipse,配置myeclipse update,必須注冊
然后輸入http://lochost:8080/出現tomcat,安裝成功!!!
補充:
jdk環境變量,Eclipse詳細配置
1. 下載jdk,安裝完成后,右鍵點擊“我的電腦”,選擇“高級”,點“環境變量”,在下面的“系統變量”中,點擊新建,
變量名 java_home
變量值為你安裝java的目錄,如 C:\Java ,安裝時如果修改安裝路徑,確保jdk,jre在同一目錄Java下
選擇已經存在的path,在變量值最后加 ;C:\Java\jdk1.5.0\bin ,或者在最前寫 C:\Java\jdk1.5.0\bin;
新建classpath 變量值 C:\Java\jdk1.5.0 \lib\dt.jar;C:\Java\jdk1.5.0\lib\tools.jar
2. links方式安裝插件 如語言包,解開后為NLpack1-eclipse-SDK-3.2-win32,下面有個eclipse,【復制】eclipse這個文件夾
在eclipse安裝目錄下,如F:\eclipse 下新建文件夾命名為language ,再在links文件夾下新建文本文檔,
里面寫 path=language
然后把文本文件改名為language.ini ,接下去把復制的eclipse文件夾放到language文件夾下,
也就是F:\eclipse\language下還有個 eclipse文件夾。路徑是這樣的F:\eclipse\language\eclipse 。
3. 運行eclipse,已經變成中文版的了
4. MyEclipse安裝,下載對應的版本后,如myeclipse5.0以上的,對應eclipse3.2 ,直接點擊安裝,
路徑選擇eclipse目錄
安裝完成后,在eclipse工作界面中欄目里多了MyEclipse,第1次運行會彈出注冊界面,
輸入網上找的注冊碼(網上搜索多的是)
點擊finish
tomcat安裝,下載tomcat 5.0以上版本,安裝完成后,同樣在環境變量里新建tomcat_home ,輸入變量值,F:\Tomcat 5.0
在存在的classpath最后添加 F:\Tomcat 5.0\common\lib\servlet-api.jar,注意和前面的tools.jar用分號;隔開
在eclipse工作界面中點窗口,首選項,MyEclipse - Application Server 選擇Tomcat 5
Tomcat home directory 設置enable 瀏覽選擇Tomcat安裝目錄,在Tomcat目錄下有個JDK,重新選擇路徑,
名稱自己定義,如jdk1.5