📄 jlview.cpp
字号:
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 + -