www.pudn.com > VQ_Final.rar > Main.cpp


 
#include "afxwin.h" 
#include "afxdlgs.h" 
 
#include "resource.h" 
#include "VQWizard.h" 
#include "Step1.h" 
#include "Step2.h" 
#include "Step3.h" 
 
#include "main.h" 
 
#define TITLE "位图矢量量化程序--作者:0213104班 18号 王肇刚"		//标题 
 
//以下为控件资源常量 
 
#define IDC_OPEN 101												 
#define IDC_INFO 102 
#define IDC_VQ   103 
#define IDD_VQWIZARD 104 
#define IDC_ABOUT 105 
 
CMyApp myApp; 
 
BOOL CMyApp::InitInstance() 
{ 
	m_pMainWnd=new CMainWindow();	 
	m_pMainWnd->ShowWindow(TRUE); 
	m_pMainWnd->UpdateWindow(); 
	return TRUE; 
} 
BEGIN_MESSAGE_MAP(CMainWindow,CWnd) 
	ON_WM_CREATE() 
	ON_WM_ERASEBKGND() 
	ON_WM_SIZE() 
	ON_BN_CLICKED(IDC_OPEN,OnOpen) 
	ON_BN_CLICKED(IDC_VQ,OnVQ) 
	ON_BN_CLICKED(IDC_ABOUT,OnAbout) 
	ON_WM_LBUTTONDOWN() 
	ON_WM_RBUTTONDOWN() 
	ON_WM_LBUTTONUP() 
	ON_WM_MOUSEMOVE() 
END_MESSAGE_MAP() 
 
CMainWindow::CMainWindow() 
{ 
	//初始化变量 
	m_sFile="";m_sFileVQ=""; 
	m_bVQed=FALSE; 
	m_ptLeftTop.x=m_ptLeftTop.y=0; 
	m_bDragging=m_bSmallBMP=FALSE; 
	m_nBits=0; 
	//注册窗口类并新建窗口 
	const char* m_pClassName=AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,LoadCursor(NULL,IDC_ARROW), 
	0,AfxGetApp()->LoadIcon(IDI_MAIN));  
	CWnd::CreateEx(0,m_pClassName, TITLE, WS_OVERLAPPEDWINDOW,  
	200,100,800,600, NULL,0,NULL);  
} 
int CMainWindow::OnCreate(LPCREATESTRUCT lpcs) 
{ 
	if (CWnd::OnCreate(lpcs)==-1) 
		return -1; 
 
	//设定图标 
	HICON hIcon=NULL; 
	hIcon=AfxGetApp()->LoadIcon(IDI_MAIN); 
	SetIcon(hIcon,TRUE); 
	SetIcon(hIcon,FALSE); 
 
	//初始化控件并布局 
	InitControls(); 
	Layout(); 
 
	//用一个和屏幕一样大的临时BMP来初始化内存DC 
	CBitmap temp; 
	temp.CreateCompatibleBitmap(GetDC(),GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN)); 
	m_dcBack.CreateCompatibleDC(GetDC()); 
	m_dcBack.SelectObject(&temp); 
	temp.DeleteObject(); 
	 
	return 1; 
} 
BOOL CMainWindow::OnEraseBkgnd(CDC *pDC)	//每次刷新时重绘窗口,也可以写在OnPaint里 
{ 
	CRect rc; 
	GetClientRect(&rc); 
	DrawBoard(&m_dcBack);		//在内存DC上画面板 
	DrawBMP(&m_dcBack);			//在内存DC上画位图 
	pDC->BitBlt(0,0,rc.Width(),rc.Height(),&m_dcBack,0,0,SRCCOPY);	 
		//把内存DC传送到窗口DC,显示出来  
	Layout();	//重新布局 
	return TRUE; 
} 
void CMainWindow::Layout()	//重新布局 
{ 
	UINT nLeft; 
	CRect rcOpen,rcVQ,rcInfo,rcAbout;	//四个控件的位置 
	 
	GetClientRect(&m_rcLeft); 
	nLeft=(UINT)(m_rcLeft.Width()*LEFT); 
	m_rcLeft.left=(LONG)(m_rcLeft.Width()*LEFT); 
	 
	rcOpen.left=(LONG)(nLeft*.3); 
	rcOpen.top=m_rcLeft.Height()/10; 
	rcOpen.right=(LONG)(nLeft*.7); 
	rcOpen.bottom=rcOpen.top+m_rcLeft.Height()/10; 
	 
	rcInfo.left=(LONG)(nLeft*.1); 
	rcInfo.top=m_rcLeft.Height()/5+m_rcLeft.Height()/10; 
	rcInfo.right=(LONG)(nLeft*.9); 
	rcInfo.bottom=(LONG)(rcInfo.top+m_rcLeft.Height()/3); 
 
	rcVQ.left=(LONG)(nLeft*.3); 
	rcVQ.top=m_rcLeft.Height()/5+m_rcLeft.Height()/8+m_rcLeft.Height()/3; 
	rcVQ.right=(LONG)(nLeft*.7); 
	rcVQ.bottom=rcVQ.top+m_rcLeft.Height()/10; 
 
	rcAbout.left=(LONG)(nLeft*.3); 
	rcAbout.top=m_rcLeft.Height()/5+m_rcLeft.Height()/8+m_rcLeft.Height()/2; 
	rcAbout.right=(LONG)(nLeft*.7); 
	rcAbout.bottom=rcAbout.top+m_rcLeft.Height()/10; 
 
	//以下刷新四个控件 
	m_bnOpen.MoveWindow(rcOpen,FALSE); 
	m_bnVQ.MoveWindow(rcVQ,FALSE); 
	m_bnAbout.MoveWindow(rcAbout,FALSE); 
	m_lbInfo.MoveWindow(rcInfo,FALSE); 
 
 
	m_bnOpen.RedrawWindow(&rcOpen); 
	m_bnVQ.RedrawWindow(&rcVQ); 
	m_bnAbout.RedrawWindow(&rcAbout); 
	m_lbInfo.UpdateWindow(); 
	m_lbInfo.RedrawWindow(&rcInfo); 
 
} 
void CMainWindow::InitControls()	//初始化控件 
{ 
	m_bnOpen.Create("打开文件",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(0,0,20,20),this,IDC_OPEN); 
	m_bnVQ.Create("矢量量化",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(0,0,20,20),this,IDC_VQ); 
	m_bnAbout.Create("关于",WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,CRect(0,0,20,20),this,IDC_ABOUT); 
	m_lbInfo.Create(WS_CHILD|WS_VISIBLE|WS_HSCROLL,CRect(0,0,200,200),this,IDC_INFO); 
 
} 
void CMainWindow::OnSize(UINT nType,int cx,int cy)	//当用户改变窗口大小时 
{ 
	CWnd::OnSize(nType,cx,cy); 
	Layout();			//重新布局 
	 
	SmallBMP();			//处理位图小于窗口的情况 
	 
	m_ptLeftTop.x=m_ptLeftTop.y=0;	//从左上角开始显示位图 
	 
	OnPaint(); 
 
 
} 
 
void CMainWindow::OnOpen()	//“打开”按钮 
{ 
	char szFilters[]="位图文件 (*.bmp)|*.bmp|"; 
	CFileDialog dlg(TRUE,"bmp","*.bmp",OFN_HIDEREADONLY,szFilters,this); 
	 
	if( dlg.DoModal()==IDOK) 
	{ 
		CString sTitle; 
		CString sPathName = dlg.GetPathName();	//带路径的完整文件名 
		CString sFileName = dlg.GetFileTitle();	//文件名(不带路径) 
		if (sPathName==m_sFile) //若打开的是与当前文件相同的文件则不继续 
			return; 
		m_sTitle=sFileName; 
		sFileName="---"+sFileName; 
		sTitle=TITLE+sFileName; 
		SetWindowText(sTitle); //更改窗口标题 
		m_sFile=sPathName; //将完整文件名保存在类的成员变量中 
	 
    } 
	else 
		return; 
 
	LoadBMP(); 
} 
void CMainWindow::DrawBMP(CDC *pDC) 
{ 
	if (m_sFile.IsEmpty())	//要是开没有打开文件就显示白色矩形 
	{ 
		pDC->Rectangle(&m_rcLeft); 
	} 
	else 
	{ 
		if (m_bSmallBMP)	//若位图比窗口小则在四周显示空白,否则用户可以拖动 
		{ 
			pDC->BitBlt(m_rcLeft.left,0,m_rcLeft.Width(),m_rcLeft.Height(),&m_dcMem,m_ptLeftTop.x,m_ptLeftTop.y,SRCCOPY);		 
		} 
		else 
			pDC->BitBlt(m_rcLeft.left,0,m_rcLeft.Width(),m_rcLeft.Height(),&m_dcBmp,m_ptLeftTop.x,m_ptLeftTop.y,SRCCOPY);		 
	} 
} 
void CMainWindow::DrawBoard(CDC *pDC)	//绘制左边的面板,比较繁,写起来很痛苦 
{ 
 
	CPen pWhite,pBlack,*oldPen; 
	CBrush brBack,*oldBr; 
	pWhite.CreatePen(PS_SOLID,2,GetSysColor(COLOR_3DHILIGHT)); 
	pBlack.CreatePen(PS_SOLID,2,GetSysColor(COLOR_BTNSHADOW)); 
	brBack.CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); 
 
	oldBr=pDC->SelectObject(&brBack); 
	pDC->Rectangle(CRect(0,0,m_rcLeft.left,m_rcLeft.bottom )); 
	pDC->SelectObject(oldBr); 
	 
	oldPen=pDC->SelectObject(&pWhite); 
	pDC->MoveTo(m_rcLeft.left-2,0); 
	pDC->LineTo(m_rcLeft.left-2,m_rcLeft.bottom); 
	pDC->SelectObject(&pBlack); 
	pDC->MoveTo(m_rcLeft.left,0); 
	pDC->LineTo(m_rcLeft.left,m_rcLeft.bottom); 
	pDC->SelectObject(oldPen); 
 
	pWhite.DeleteObject(); 
	pBlack.DeleteObject(); 
	brBack.DeleteObject(); 
 
} 
void CMainWindow::LoadBMP()		//读入BMP 
{ 
	HBITMAP hBmp;				//位图句柄 
 
	//先从文件中读出位图 
	if (hBmp=(HBITMAP)LoadImage(NULL,m_sFile,IMAGE_BITMAP,0,0,LR_LOADFROMFILE)) 
	{ 
		CBitmap *pBmp=CBitmap::FromHandle(hBmp);	//把句柄转为类指针 
		pBmp->GetBitmap(&m_Bmp); 
		//以下读文件头 
		CFile fBmp;						 
		fBmp.Open(m_sFile,CFile::modeRead,NULL); 
		BITMAPFILEHEADER bmfh; 
		BITMAPINFO bmi; 
		ZeroMemory(&bmfh,sizeof(bmfh)); 
		ZeroMemory(&bmi,sizeof(bmi)); 
 
		fBmp.Read(&bmfh,sizeof(bmfh)); 
		fBmp.Read(&bmi,sizeof(bmi)); 
		fBmp.Close(); 
		//以下显示文件信息								 
		CString sInfo[8]; 
		sInfo[0]="文件名:"+m_sTitle; 
		sInfo[1].Format("宽度:%d",m_Bmp.bmWidth); 
		sInfo[2].Format("高度:%d",m_Bmp.bmHeight); 
		sInfo[3].Format("每行字节数:%d",m_Bmp.bmWidthBytes); 
		sInfo[4].Format("位面数:%d",m_Bmp.bmPlanes); 
		sInfo[5].Format("水平分辨率:%ld DPI",(long)(bmi.bmiHeader.biXPelsPerMeter*25.4/1000)); 
		sInfo[6].Format("垂直分辨率:%ld DPI",(long)(bmi.bmiHeader.biYPelsPerMeter*25.4/1000)); 
		sInfo[7].Format("每个像素的位数:%d",m_nBits=bmi.bmiHeader.biBitCount); 
		//若列表框有内容则清空 
		if (m_lbInfo.GetCount()!=0) 
			for (int i=0;i<8;i++) 
				m_lbInfo.DeleteString(0); 
		//把信息加入列表框 
		for (int i=0;i<8;i++) 
			m_lbInfo.AddString(sInfo[i]); 
		 
		//初始化内存DC,把BMP先入内存DC 
		if (m_dcBmp.m_hDC!=NULL) 
		m_dcBmp.DeleteDC(); 
		m_dcBmp.CreateCompatibleDC(GetDC()); 
		m_dcBmp.SelectObject(pBmp); 
		pBmp->DeleteObject();	 
		 
		SmallBMP();			//处理位图小于窗口的情况 
		 
		m_ptLeftTop.x=m_ptLeftTop.y=0;	//从左上角开始 
		Invalidate();					//刷新 
	} 
	else 
	{ 
		AfxMessageBox("无法打开BMP文件!"); 
		m_sFile=""; 
		SetWindowText(TITLE); 
	} 
 
} 
void CMainWindow::OnLButtonDown(UINT nFlags,CPoint point)	//鼠标左键按下就开始拖动 
{ 
	if (m_rcLeft.PtInRect(point) && !m_sFile.IsEmpty()) 
	{ 
		m_bDragging=TRUE; 
		SetCapture(); 
		SetCursor(LoadCursor(NULL,MAKEINTRESOURCE(32649)));	//手形鼠标指针 
	} 
} 
void CMainWindow::OnRButtonDown(UINT nFlags,CPoint point)	//右键按下就在原文件和VQ结果文件间切换 
{ 
	if (m_rcLeft.PtInRect(point) && m_bVQed) 
	{ 
		CString t;	//以下交换m_sFile和m_sFileVQ的内容 
		t=m_sFile; 
		m_sFile=m_sFileVQ; 
		m_sFileVQ=t; 
		LoadBMP();	//重新读入BMP 
	} 
} 
void CMainWindow::OnLButtonUp(UINT nFlags,CPoint point)		//左键松开就停止拖动 
{ 
	if (m_rcLeft.PtInRect(point)) 
	{ 
		m_bDragging=FALSE; 
		ReleaseCapture(); 
		SetCursor(LoadCursor(NULL,MAKEINTRESOURCE(32649))); //手形鼠标指针 
	} 
} 
void CMainWindow::OnMouseMove(UINT nFlags,CPoint point)		//拖动 
{ 
	static CPoint ptOld(0,0);	//用静态变量保存上次鼠标的位置 
	 
	if (!m_bDragging)	//没有在拖动则改变指针 
	{ 
		if (m_rcLeft.PtInRect(point)) 
			SetCursor(LoadCursor(NULL,MAKEINTRESOURCE(32649))); 
		else 
			SetCursor(LoadCursor(NULL,IDC_ARROW)); 
	} 
	else				//否则处理拖动 
	{ 
		//以下通过上一次鼠标位置和本次位置来改变窗口左上角开始显示的位图的位置 
		CPoint ptTemp=m_ptLeftTop; 
		ptTemp-=(point-ptOld); 
 
		if (!(ptTemp.x<0 || ptTemp.y<0 ||  
			ptTemp.x+m_rcLeft.Width()>m_Bmp.bmWidth || 
			ptTemp.y+m_rcLeft.Height()>m_Bmp.bmHeight)) 
			m_ptLeftTop=ptTemp; 
		InvalidateRect(m_rcLeft);	//刷新 
	} 
		ptOld=point; 
} 
void CMainWindow::SmallBMP()	//当位图小于窗口时 
{ 
	UINT nX=0,nY=0; 
	BOOL bFlagW=FALSE,bFlagH=FALSE; 
	m_bSmallBMP=FALSE; 
	if (m_Bmp.bmWidth