HexViewer
1、建立名为HexViewer的SDI项目,在创建单文档时把Base Class(基类)改为CScrollView。CScrollView就是CView的一个派生类,通过它可以很容易地处理水平和垂直滚动。
2、打开和读取文件
首先,在CHexViewerDoc类中定义两个成员变量,分别用于检索要打开文件的指针以及文件的大小,并初始化这些值,同时添加用于清除的代码。
class
CHexViewerDoc :
public
CDocument
{
..
public :
CFile * m_pFile;
LONG m_lFileSize;
..
};
CHexViewerDoc::CHexViewerDoc()
{
m_pFile = NULL;
m_lFileSize = 0L ;
}
CHexViewerDoc:: ~ CHexViewerDoc()
{
if (m_pFile != NULL)
{
m_pFile -> Close();
delete m_pFile;
m_pFile = NULL;
m_lFileSize = 0L ;
}
}
在使用MFC框架的因公程序中打开文档后,还会调用CHexViewerDoc::OnOpenDocument虚函数。
{
![](http://img.e-com-net.com/image/product/02d0904de3cc460eae11f6902a7115a2.gif)
public :
CFile * m_pFile;
LONG m_lFileSize;
![](http://img.e-com-net.com/image/product/02d0904de3cc460eae11f6902a7115a2.gif)
};
CHexViewerDoc::CHexViewerDoc()
{
m_pFile = NULL;
m_lFileSize = 0L ;
}
CHexViewerDoc:: ~ CHexViewerDoc()
{
if (m_pFile != NULL)
{
m_pFile -> Close();
delete m_pFile;
m_pFile = NULL;
m_lFileSize = 0L ;
}
}
BOOL CHexViewerDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if ( ! CDocument::OnOpenDocument(lpszPathName))
return FALSE;
if (m_pFile != NULL)
{
m_pFile -> Close();
delete m_pFile;
m_pFile = NULL;
m_lFileSize = 0L ;
}
try
{
m_pFile = new CFile(lpszPathName,CFile::modeRead | CFile::typeBinary);
}
catch (CFileException * e)
{
CString strError;
strError.Format(_T( " Couldn't open file:%d " ),_sys_errlist[e -> m_lOsError]);
AfxMessageBox(strError);
return FALSE;
}
m_lFileSize = m_pFile -> GetLength();
return TRUE;
}
最后添加一个辅助成员函数,视图调用该函数从打开的文件中读取一行数据。
{
if ( ! CDocument::OnOpenDocument(lpszPathName))
return FALSE;
if (m_pFile != NULL)
{
m_pFile -> Close();
delete m_pFile;
m_pFile = NULL;
m_lFileSize = 0L ;
}
try
{
m_pFile = new CFile(lpszPathName,CFile::modeRead | CFile::typeBinary);
}
catch (CFileException * e)
{
CString strError;
strError.Format(_T( " Couldn't open file:%d " ),_sys_errlist[e -> m_lOsError]);
AfxMessageBox(strError);
return FALSE;
}
m_lFileSize = m_pFile -> GetLength();
return TRUE;
}
BOOL CHexViewerDoc::ReadLine(CString
&
strLine,
int
nLength,LONG lOffset
/*
=-1L
*/
)
{
LONG lPosition;
if (lOffset !=- 1L )
lPosition = m_pFile -> Seek(lOffset,CFile::begin);
else
lPosition = m_pFile -> GetPosition();
if (lPosition ==- 1L )
{
TRACE( " CHexViewDoc::ReadLine returns False Seek (%8.8lX,%8.8lX)\n " ,lOffset,lPosition);
// 这个宏是用来调试用的,在VC的窗口的输入框中会看到输出的内容!只有在debug版本中才会运行
return FALSE;
}
BYTE * pszBuffer = new BYTE[nLength];
int nReturned = m_pFile -> Read(pszBuffer,nLength);
if (nReturned <= 0 )
{
TRACE2( " CHexViewDoc::ReadLine returns FALSE Read (%d,%d) " ,nLength,nReturned);
delete pszBuffer;
return FALSE;
}
CString strTemp;
CString strCharsIn;
strTemp.Format(_T( " %8.8lX - " ),lPosition);
strLine = strTemp;
for ( int nIndex = 0 ;nIndex < nReturned;nIndex ++ )
{
if (nIndex == 0 )
strTemp.Format(_T( " %2.2X " ),pszBuffer[nIndex]);
// 以2位的十六进制读取
else if (nIndex % 16 == 0 )
strTemp.Format(_T( " =%2.2X " ),pszBuffer[nIndex]);
else if (nIndex % 8 == 0 )
strTemp.Format(_T( " -%2.2X " ),pszBuffer[nIndex]);
else
strTemp.Format(_T( " %2.2X " ),pszBuffer[nIndex]);
if (_istprint(pszBuffer[nIndex]))
strCharsIn += pszBuffer[nIndex];
else
strCharsIn += _T( ' . ' );
strLine += strTemp;
}
if (nReturned < nLength)
{
CString strPadding(_T( ' ' ), 3 * (nLength - nReturned));
strLine += strPadding;
}
strLine += _T( " " );
strLine += strCharsIn;
delete pszBuffer;
return true ;
}
3、视图的编码
{
LONG lPosition;
if (lOffset !=- 1L )
lPosition = m_pFile -> Seek(lOffset,CFile::begin);
else
lPosition = m_pFile -> GetPosition();
if (lPosition ==- 1L )
{
TRACE( " CHexViewDoc::ReadLine returns False Seek (%8.8lX,%8.8lX)\n " ,lOffset,lPosition);
// 这个宏是用来调试用的,在VC的窗口的输入框中会看到输出的内容!只有在debug版本中才会运行
return FALSE;
}
BYTE * pszBuffer = new BYTE[nLength];
int nReturned = m_pFile -> Read(pszBuffer,nLength);
if (nReturned <= 0 )
{
TRACE2( " CHexViewDoc::ReadLine returns FALSE Read (%d,%d) " ,nLength,nReturned);
delete pszBuffer;
return FALSE;
}
CString strTemp;
CString strCharsIn;
strTemp.Format(_T( " %8.8lX - " ),lPosition);
strLine = strTemp;
for ( int nIndex = 0 ;nIndex < nReturned;nIndex ++ )
{
if (nIndex == 0 )
strTemp.Format(_T( " %2.2X " ),pszBuffer[nIndex]);
// 以2位的十六进制读取
else if (nIndex % 16 == 0 )
strTemp.Format(_T( " =%2.2X " ),pszBuffer[nIndex]);
else if (nIndex % 8 == 0 )
strTemp.Format(_T( " -%2.2X " ),pszBuffer[nIndex]);
else
strTemp.Format(_T( " %2.2X " ),pszBuffer[nIndex]);
if (_istprint(pszBuffer[nIndex]))
strCharsIn += pszBuffer[nIndex];
else
strCharsIn += _T( ' . ' );
strLine += strTemp;
}
if (nReturned < nLength)
{
CString strPadding(_T( ' ' ), 3 * (nLength - nReturned));
strLine += strPadding;
}
strLine += _T( " " );
strLine += strCharsIn;
delete pszBuffer;
return true ;
}
首先,定义一些变量,并对数据的字体进行改变
class
CHexViewerView :
public
CScrollView
{
.
protected :
CFont * m_pFont;
LOGFONT m_logfont;
int m_nPointSize;
int m_nPageHeight;
int m_nPageWidth;
.
};
CHexViewerView::CHexViewerView()
{
// TODO: add construction code here
memset( & m_logfont, 0 , sizeof (m_logfont));
m_nPointSize = 120 ;
_tcscpy(m_logfont.lfFaceName,_T( " Fixedsys " ));
// 函数原型:char *strcpy( char *strDestination, const char *strSource );
CWindowDC dc(NULL);
m_logfont.lfHeight = ::MulDiv(m_nPointSize,dc.GetDeviceCaps(LOGPIXELSY), 720 );
// MulDiv字体高度值和磅值有如下的换算公式;GetDeviceCaps该函数检索指定设备的设备指定信息。
// LOGPIXELSY沿屏幕高度每逻辑英寸的像素数,在多显示器系统中,该值对所显示器相同;
m_logfont.lfPitchAndFamily = FIXED_PITCH; // 指定字体间距和字体族,低端二位指定字体的字符间距
m_pFont = new CFont;
m_pFont -> CreateFontIndirect( & m_logfont);
}
CHexViewerView:: ~ CHexViewerView()
{
if (m_pFont != NULL)
{
delete m_pFont;
}
}
设置滚动的大小,可以向其传递映射模式(MM_TEXT显示文本)和文档大小(m_lFileSize)
{
![](http://img.e-com-net.com/image/product/02d0904de3cc460eae11f6902a7115a2.gif)
protected :
CFont * m_pFont;
LOGFONT m_logfont;
int m_nPointSize;
int m_nPageHeight;
int m_nPageWidth;
![](http://img.e-com-net.com/image/product/02d0904de3cc460eae11f6902a7115a2.gif)
};
CHexViewerView::CHexViewerView()
{
// TODO: add construction code here
memset( & m_logfont, 0 , sizeof (m_logfont));
m_nPointSize = 120 ;
_tcscpy(m_logfont.lfFaceName,_T( " Fixedsys " ));
// 函数原型:char *strcpy( char *strDestination, const char *strSource );
CWindowDC dc(NULL);
m_logfont.lfHeight = ::MulDiv(m_nPointSize,dc.GetDeviceCaps(LOGPIXELSY), 720 );
// MulDiv字体高度值和磅值有如下的换算公式;GetDeviceCaps该函数检索指定设备的设备指定信息。
// LOGPIXELSY沿屏幕高度每逻辑英寸的像素数,在多显示器系统中,该值对所显示器相同;
m_logfont.lfPitchAndFamily = FIXED_PITCH; // 指定字体间距和字体族,低端二位指定字体的字符间距
m_pFont = new CFont;
m_pFont -> CreateFontIndirect( & m_logfont);
}
CHexViewerView:: ~ CHexViewerView()
{
if (m_pFont != NULL)
{
delete m_pFont;
}
}
void
CHexViewerView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CHexViewerDoc * pDoc = GetDocument();
ASSERT_VALID(pDoc);
CSize sizeTotal( 0 ,pDoc -> m_lFileSize);
// sizeTotal.cx = sizeTotal.cy = 100;
SetScrollSizes(MM_TEXT, sizeTotal);
}
给视图添加为当前设备上下文(DC)计算字体高度(以像素计)的辅助函数。这里的技巧是传递-1作为字符串长度。这意味着不进行任何实际绘制操作,但是DrawText函数仍返回指定文本的高度。
{
CScrollView::OnInitialUpdate();
CHexViewerDoc * pDoc = GetDocument();
ASSERT_VALID(pDoc);
CSize sizeTotal( 0 ,pDoc -> m_lFileSize);
// sizeTotal.cx = sizeTotal.cy = 100;
SetScrollSizes(MM_TEXT, sizeTotal);
}
int
CHexViewerView::MeasureFontHeight(CFont
*
pFont,CDC
*
pDC)
{
CFont * pOldFont;
pOldFont = pDC -> SelectObject(pFont);
CRect rectDummy;
CString strRender = _T( " 1234567890ABCDEF- " );
int nHeight = pDC -> DrawText(strRender, - 1 ,rectDummy,DT_TOP | DT_SINGLELINE | DT_CALCRECT);
pDC -> SelectObject(pOldFont);
return nHeight;
}
最后队试图进行修改,用GetScrollPosition返回用户滚动的位置,用GetClientRect来返回工作区的大小,用MeasureFontHeight返回每行的高度,然后可以用一个for循环通过ReadLine函数来从文档中检索每行数据。
{
CFont * pOldFont;
pOldFont = pDC -> SelectObject(pFont);
CRect rectDummy;
CString strRender = _T( " 1234567890ABCDEF- " );
int nHeight = pDC -> DrawText(strRender, - 1 ,rectDummy,DT_TOP | DT_SINGLELINE | DT_CALCRECT);
pDC -> SelectObject(pOldFont);
return nHeight;
}
void
CHexViewerView::OnDraw(CDC
*
pDC)
{
CHexViewerDoc * pDoc = GetDocument();
ASSERT_VALID(pDoc);
CString strRender;
CFont * pOldFont;
CSize ScrolledSize;
int nStartLine;
int nHeight;
CRect ScrollRect;
CPoint ScrolledPos = GetScrollPosition(); // 获取该屏滚动条的位置
CRect rectClient;
GetClientRect( & rectClient);
pOldFont = pDC -> SelectObject(m_pFont);
nHeight = MeasureFontHeight(m_pFont,pDC);
ScrolledSize = CSize(rectClient.Width(),rectClient.Height());
ScrollRect = CRect(rectClient.left,ScrolledPos.y,rectClient.right,ScrolledSize.cy + ScrolledPos.y);
nStartLine = ScrolledPos.y / 16 ;
ScrollRect.top = nStartLine * nHeight;
if (pDoc -> m_pFile != NULL)
{
int nLine;
for (nLine = nStartLine;ScrollRect.top < ScrollRect.bottom;nLine ++ )
{
if ( ! pDoc -> ReadLine(strRender, 16 ,nLine * 16 ))
break ;
nHeight = pDC -> DrawText(strRender, - 1 , & ScrollRect,DT_TOP | DT_NOPREFIX | DT_SINGLELINE);
ScrollRect.top += nHeight;
}
}
pDC -> SelectObject(pOldFont);
}
{
CHexViewerDoc * pDoc = GetDocument();
ASSERT_VALID(pDoc);
CString strRender;
CFont * pOldFont;
CSize ScrolledSize;
int nStartLine;
int nHeight;
CRect ScrollRect;
CPoint ScrolledPos = GetScrollPosition(); // 获取该屏滚动条的位置
CRect rectClient;
GetClientRect( & rectClient);
pOldFont = pDC -> SelectObject(m_pFont);
nHeight = MeasureFontHeight(m_pFont,pDC);
ScrolledSize = CSize(rectClient.Width(),rectClient.Height());
ScrollRect = CRect(rectClient.left,ScrolledPos.y,rectClient.right,ScrolledSize.cy + ScrolledPos.y);
nStartLine = ScrolledPos.y / 16 ;
ScrollRect.top = nStartLine * nHeight;
if (pDoc -> m_pFile != NULL)
{
int nLine;
for (nLine = nStartLine;ScrollRect.top < ScrollRect.bottom;nLine ++ )
{
if ( ! pDoc -> ReadLine(strRender, 16 ,nLine * 16 ))
break ;
nHeight = pDC -> DrawText(strRender, - 1 , & ScrollRect,DT_TOP | DT_NOPREFIX | DT_SINGLELINE);
ScrollRect.top += nHeight;
}
}
pDC -> SelectObject(pOldFont);
}