⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jlview.cpp

📁 很经典的用C++编的空当接龙的程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:

				cdc.FrameRect(r,pBr);
				r.InflateRect(-1,-1);
				cdc.FrameRect(r,pBr);
				r.InflateRect(-1,-1);
				cdc.FrameRect(r,pBr);

				++p;
			}
		}
	}
	else {
		HitAt(point);//击中牌列则在这里处理
	}

	CView::OnLButtonDown(nFlags, point);
}

void CJLView::OnRButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	//刷新被右键点击的牌占据的矩形区域
	if(!m_rectRBDown.IsRectEmpty()) {
		InvalidateRect(m_rectRBDown);
		m_rectRBDown.SetRectEmpty();
		ReleaseCapture();
	}

	CView::OnRButtonUp(nFlags, point);
}


//在牌上点右键可以查看这张牌
void CJLView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	//测试点了哪张牌
	UINT hit = CardColHitTest(point);
	//击中牌列
	CJLDoc *pDoc = GetDocument();
	if(pDoc->ColInCard(hit)) { 
		for(UINT idx = 1; idx < pDoc->CntCardsIn(hit); idx++) {
			//击中被压住的牌
			if( pDoc->RectOf(hit,idx,1).PtInRect(point) && 
				! pDoc->RectOf(hit,idx+1,1).PtInRect(point) ) {
				m_rectRBDown = pDoc->RectOf(hit,idx,1);
				CClientDC cdc(this);
				DrawCard(m_rectRBDown.TopLeft(),pDoc->GetCard(hit,idx),&cdc );
				SetCapture();
				break;
			}
		}
	}

	CView::OnRButtonDown(nFlags, point);
}

void CJLView::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	//允许双击功能且有空档则双击有效
	CJLDoc *pDoc = GetDocument();
	if(pDoc->m_bEnableDbClick) {
		//取消选中列
		pDoc->UnselectCardCol();
		//测试击中哪列
		UINT curHit = CardColHitTest(point),emptyCol;
		if(
			pDoc->ColInBuf(curHit) 
			&& 
			pDoc->ColInCard(emptyCol = pDoc->FindEmptyCardCol()) 

			|| 

			pDoc->ColInCard(curHit) 
			&& 
			(
				pDoc->ColInBuf(emptyCol = pDoc->FindEmptyBuf())
				||
				pDoc->ColInCard(emptyCol = pDoc->FindEmptyCardCol())
			)
		  )
		{
			HitAt(point);//假设发生两个单击动作,第一个动作击中当前双击的地方
			HitAt(pDoc->RectOf(emptyCol,1,1).CenterPoint());//第二个单击动作击中某空档中央
		}
	}
	CView::OnLButtonDblClk(nFlags, point);
}
//测试击中了哪一列
UINT CJLView::CardColHitTest(const CPoint &point)
{
	CJLDoc *pDoc = GetDocument();
	for(UINT i = 1; i <= 16; i++)
		if(pDoc->RectOf(i,1,19).PtInRect(point))
			return i;
	return 0;
}

void CJLView::OnInitialUpdate() 
{
	CView::OnInitialUpdate();
	
	// TODO: Add your specialized code here and/or call the base class
	//如果没有文档打开就自动设置牌局
	CJLDoc * pDoc = GetDocument();
	if(pDoc->GetPathName().IsEmpty()) {
		pDoc->OnRand();
	}
	//调整窗口到合适的大小
	AdjustFrameToFixedSize();
}

void CJLView::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CJLDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);

	UINT curHit = CardColHitTest(point); 
	if
	(	//有选中列
		pDoc->IsCol(pDoc->m_nSel)
		//在牌列上移动
		&& pDoc->IsCol(curHit)
		//被选中的牌列不是目前光标所在的列
		&& pDoc->m_nSel != curHit 
		//空档足够则设置光标以提示可以移动若干张到目标列
		&& pDoc->CntMaxMv(curHit,pDoc->m_nSel)
	)
	{
		SetCursor(m_hDown);
	}
	CView::OnMouseMove(nFlags, point);
}
//擦除窗口背景
BOOL CJLView::OnEraseBkgnd(CDC* pDC) 
{
	CRect r;
	GetClientRect(r);
	pDC->FillRect(r,&m_brushBkgnd);
	return TRUE;
}

//测试当前单击点并根据击中的列的情况采取对应动作
//这个函数的代码本来是应该在OnLButtonDown中的,但
//考虑到双击动作可以用单击来模拟,而直接在OnLBtttonDblClk中调用
//OnLButtonDown不太合适,所以提取出来作为一个函数
//供OnLButtonDown和OnLBtttonDblClk两者调用
void CJLView::HitAt(CPoint point)
{
	CJLDoc *pDoc = GetDocument();
	UINT nMv = 0, hit;
	//测试当前点中了哪一列牌
	if(!(hit = CardColHitTest(point)))
		goto ret;//没有击中任何一列

	//本次单击之前未选中任何列
	if(!pDoc->m_nSel) { 
		if(hit <= 12 && pDoc->CntCardsIn(hit))//击中牌列或缓冲区且该列非空
			pDoc->SelectCardCol(hit);//选中此列
		goto ret;
	} 
	//已经选中某列,击中缓存列或牌列
	if(hit <= 12) { 
		if(hit == pDoc->m_nSel) { //单击了被选中列则取消当前选中
			pDoc->UnselectCardCol();
			goto ret;
		}
		//单击的列不是选中列,可以移动几张?
		if(!(nMv = pDoc->CntMaxMv(hit,pDoc->m_nSel))) {
			if(!pDoc->m_bEnableAlert) {
				//选中当前被击中的列(此列必定非空)
				pDoc->SelectCardCol(hit);
			} else {
				MessageBox("可能空档不够或不合规则。",
					"不能这样移动",MB_ICONWARNING | MB_OK);
			}
			goto ret;
		}
		//=================================-============================
		//可以移动若干张到目标列,目标列可以是空列也可以不是,源列正确性
		//(源列中一定有牌)这一点由SelectCardCol和CntMaxMv保证
		//=================================-============================
		if(pDoc->ColInCard(pDoc->m_nSel) && //选中牌列
			pDoc->ColInCard(hit) && 
			pDoc->IsEmptyCol(hit) && //击中空牌列
			nMv > 1) { //可移动多张
			//如果没有设置“尽可能移动多的牌”选项就询问
			if( !pDoc->m_bMaxMove && IDCANCEL == MessageBox(
				"整列牌都移到此处?","移动",MB_OKCANCEL) )
				nMv = 1;
		}
		//一定要备份pDoc->m_nSel,因为MoveCards会清除当前选中标记,
		//导致pDoc->m_nSel为0,这样Record中就不能正确记录当前选中列
Move:		UINT colSel = pDoc->m_nSel;
		pDoc->MoveCards(hit,colSel,nMv);
		pDoc->Record(new COperations(hit,colSel,nMv));
	}
	//本次单击之前已经选中某列,现在击中回收列
	else if((nMv = pDoc->CntMaxMv(hit,pDoc->m_nSel)) == 1) {
		goto Move;
	}
ret:	pDoc->AutoThrow();//自动扔牌
	pDoc->CheckGame();//游戏是否结束?
}
//调整窗口到合适的大小
void CJLView::AdjustFrameToFixedSize()
{
	CJLDoc * pDoc = GetDocument();

	//要求不管在什么时候窗口要正好能显示所有的牌
	CRect wr,cr;
	GetClientRect(cr);
	CWnd *pWnd = GetParent();
	pWnd->GetWindowRect(wr);
	
	// 窗口左右两个边的宽度和上下边框的高度
	int edge = (wr.Width() - cr.Width()) / 2 + 1;

	CRect r = pDoc->RectOf(8,1,1);//第八列第一张
	ClientToScreen(r);

	wr.right = r.right + CARD_INT + ptOrg.x + edge;
	wr.bottom = r.top + CARD_UNCOVER*12 + CARD_HEI + edge;

	pWnd->MoveWindow(wr);
	pWnd->CenterWindow();
}
//测试击中了哪一个标签
UINT CJLView::CardLabelHitTest(const CPoint &point)
{
	CJLDoc *pDoc = GetDocument();
	for(UINT i = 1; i <= 13; i++)
		if(pDoc->RectOf(i).PtInRect(point))
			return i;
	return 0;
}
//根据给定的颜色绘制窗口背景
void CJLView::OnBkColor() 
{
	CColorDialog dlg(RGB(0, 128, 0), CC_FULLOPEN);
	if (dlg.DoModal() != IDOK) return;

	m_brushBkgnd.DeleteObject();
	m_brushBkgnd.CreateSolidBrush(dlg.GetColor());
	InvalidateRect(NULL);
}
//根据给定的颜色绘制牌面背景
void CJLView::OnCardColor() 
{
	CColorDialog dlg(RGB(255, 255, 255), CC_FULLOPEN);
	if (dlg.DoModal() != IDOK) return;

	m_brushBk.DeleteObject();
	m_brushBk.CreateSolidBrush(dlg.GetColor());
	InvalidateRect(NULL);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -