扑克游戏的 ActiveX 控件





5.00/5 (1投票)
2002年7月13日
5分钟阅读

68849

3118
使用此控件,您可以轻松构建自己的扑克游戏。
引言
这是一个用于扑克游戏的ActiveX控件。我为它添加了几个功能,使其能够满足扑克游戏中一张牌的大部分职责。由于它是一个ActiveX控件,实际上,它可以用于任何支持ActiveX的语言编写的程序中,例如VC++、VB……甚至网页。此外,通过我提供的代码,您可以轻松地对其进行修改以满足您的特定需求,当然,前提是您了解ActiveX控件。
关于该控件
控件类的每个实例代表一张牌。它具有以下用户可以操作的函数和属性。
函数
BOOL SetValue(short nNewValue)
:设置牌的值。值与牌的关系如下:spade 2, 3,..., 10, J, Q, K, A --> 1 ~ 13 heart 2, 3,..., 10, J, Q, K, A --> 14 ~ 26 club 2, 3,..., 10, J, Q, K, A --> 27 ~ 39 diamond 2, 3,..., 10, J, Q, K, A --> 40 ~ 52 small joker --> 53 big joker --> 54
(注意:如果我在扑克游戏中使用术语不当,请原谅我的英语,因为我不是母语人士。)short GetValue()
:获取牌的值。BOOL SetBackID(short nNewID)
:设置牌的背面图片。有两种图片可供选择,ID分别为1和2。short GetBackID()
:获取当前背面图片的ID(1或2)。
属性
以上是添加到控件的属性。但是,您不能直接访问它们,除非在可视化设计时。您需要借助以下函数来操作。
BOOL GetBackSide()
:查看牌当前是否显示背面。TRUE
表示显示背面,反之亦然。void SetBackSide(BOOL)
:使牌显示背面或正面。BOOL GetIsMovable()
:查看牌是否可以通过鼠标拖动。TRUE
表示可以,反之亦然。void SetIsMovable(BOOL)
:使牌可以或不可以被拖动。BOOL GetIsReturn()
:查看牌拖动后是否可以返回到其原始位置。TRUE
表示可以,反之亦然。void SetIsReturn(BOOL)
:使牌可以或不可以返回到其原始位置。BOOL GetIsSelected()
:查看牌当前是否被选中。被选中的牌周围会有一个红色边框。void SetIsSelected(BOOL)
:使牌被选中或不被选中。
对于函数,您可以在程序中调用它们。对于属性,当然您也可以在程序中调用它们。此外,您可以在设计时设置它们的初始值,例如在资源编辑器中。当选择ActiveX控件的属性时,您会看到一些用于上述属性的复选框。您可以在那里设置初始值,最可能的是,稍后在代码中通过调用相应的GetXXX()
和SetXXX()
方法来更改它们。
注意:我为控件添加了一个额外的功能。每当您用鼠标左键单击它时,它就会被选中,并以红色边框表示。
标准ActiveX事件
最后,我为控件添加了五个标准的ActiveX事件。它们是Click
、DblClick
、MouseDown
、MouseMove
和MouseUp
。在您的程序中,您可以使用事件接收映射来处理任意数量的这些事件。例如,在我的测试程序中,我处理了MouseDown
事件:当您用鼠标右键单击牌时,它会翻转。
一些编码细节
我根据牌的当前值绘制了牌。我在程序中保存了54张位图,并按如下方式以编程方式加载它们。
void CPokerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds,
const CRect& rcInvalid)
{
// TODO: Replace the following code with your own drawing code.
CBitmap* pOldBmp = NULL;
CBitmap bmp;
CDC dcMem;
dcMem.CreateCompatibleDC(pdc);
if(m_bBackSide)
{
if(GetBackID() == 1)
bmp.LoadBitmap(IDB_BACKSIDE1);
else
bmp.LoadBitmap(IDB_BACKSIDE2);
}
else
{
bmp.LoadBitmap(IDB_BITMAP1 + GetValue() - 1);
}
pOldBmp = dcMem.SelectObject(&bmp);
pdc->StretchBlt(0, 0, rcBounds.Width(), rcBounds.Height(),
&dcMem, 0, 0, 71, 96, SRCCOPY);
dcMem.SelectObject(pOldBmp);
if(m_bIsSelected)
{
CBrush* pOldBrush = (CBrush*)pdc->SelectStockObject(NULL_BRUSH);
CPen pen(PS_SOLID, 4, RGB(192, 0, 0));
CPen* pOldPen = pdc->SelectObject(&pen);
CRect rect;
GetClientRect(&rect);
pdc->Rectangle(&rect);
pdc->SelectObject(pOldBrush);
pdc->SelectObject(pOldPen);
}
}
为了移动牌,我处理了MouseDown
、MouseMove
和MouseUp
事件。请不要将它们与同名的标准ActiveX事件混淆。它们是不同的概念。
void CPokerCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_bIsSelected = TRUE;
if(m_bIsMovable)
{
m_bIsMoving = TRUE;
SetCapture();
// get the mouse position relative to the ActiveX
//control's lefttop corner
m_ptMouseInitPos = point;
GetClientRect(&m_rtHomeRect);
::ClientToScreen(m_hWnd, &m_rtHomeRect.TopLeft());
// get the screen coords of the ActiveX control's lefttop corner
m_ptOldLeftTop = m_rtHomeRect.TopLeft();
CRect rect;
GetClientRect(&rect);
MoveWindow(0, 0, rect.Width(), rect.Height(), TRUE);
GetClientRect(&m_rtHomeRect);
// get the screen coords of the container's lefttop corner
::ClientToScreen(m_hWnd, &m_rtHomeRect.TopLeft());
::ClientToScreen(m_hWnd, &m_rtHomeRect.BottomRight());
}
COleControl::OnLButtonDown(nFlags, point);
}
void CPokerCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_bIsMoving)
{
CPoint myPoint = point;
ClientToScreen(&myPoint);
MoveWindow(myPoint.x - m_ptMouseInitPos.x - m_rtHomeRect.left,
myPoint.y - m_ptMouseInitPos.y - m_rtHomeRect.top,
m_rtHomeRect.Width(), m_rtHomeRect.Height(), TRUE);
}
COleControl::OnMouseMove(nFlags, point);
}
void CPokerCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_bIsMoving)
{
ReleaseCapture();
m_bIsMoving = FALSE;
if(m_bIsReturn)
{
MoveWindow(m_ptOldLeftTop.x - m_rtHomeRect.left,
m_ptOldLeftTop.y - m_rtHomeRect.top,
m_rtHomeRect.Width(), m_rtHomeRect.Height(), TRUE);
}
}
COleControl::OnLButtonUp(nFlags, point);
}
如何使用该控件
注册控件
与任何COM对象一样,ActiveX控件必须在宿主系统上注册后才能使用。如果您自己使用Visual C++构建控件,则在构建过程中会自动注册控件。如果您想直接使用该控件而不进行编译,则需要在系统上注册它,然后才能使用。以下是两种在系统上注册控件的方法。
第一种方法是编程注册控件。由于OCX是自注册的进程内COM服务器,程序可以像加载普通DLL一样加载OCX,找到其DllRegisterServer
函数的地址,然后调用该函数。DllRegisterServer
会注册OCX中的所有控件。以下代码演示了如果OCX名为Poker.ocx,如何完成此操作。
HINSTANCE hOcx = ::LoadLibrary (_T ("Poker.ocx"));
if (hOcx != NULL)
{
FARPROC lpfn = ::GetProcAddress (hOcx, _T ("DllRegisterServer"));
if (lpfn != NULL)
(*lpfn) (); // Register the control(s).
::FreeLibrary (hOcx);
}
第二种方法是使用Visual C++附带的Regsvr32实用程序。如果Poker.ocx在当前目录中,在命令提示符窗口中键入以下命令将注册OCX的控件。
Regsvr32 Poker.ocx
同样,向Regsvr32传递/U开关可以注销OCX中的控件。
Regsvr32 /U Poker.ocx
使用它
您可以像添加普通控件一样将其添加到程序中,例如,将其添加到对话框中。您可以按任意大小调整它。您可以在属性菜单项中设置属性。稍后在代码中,您可以通过调用相应的函数来更改它们。
在我的测试程序中,我在对话框中添加了三个控件,并添加了三个成员变量,每个控件一个。
// in PokerTestDlg.h
CPoker m_ctlPoker1;
CPoker m_ctlPoker2;
CPoker m_ctlPoker3;
// in PokerTestDlg.cpp
DDX_Control(pDX, IDC_POKER1, m_ctlPoker1);
DDX_Control(pDX, IDC_POKER2, m_ctlPoker2);
DDX_Control(pDX, IDC_POKER3, m_ctlPoker3);
我还添加了两个复选框来演示如何切换IsMovable
和IsReturn
属性。
void CPokerTestDlg::OnCheckMovable()
{
// TODO: Add your control notification handler code here
m_bMovable = !m_bMovable;
m_ctlPoker1.SetIsMovable(m_bMovable);
m_ctlPoker2.SetIsMovable(m_bMovable);
m_ctlPoker3.SetIsMovable(m_bMovable);
}
void CPokerTestDlg::OnCheckReturn()
{
// TODO: Add your control notification handler code here
m_bReturn = !m_bReturn;
m_ctlPoker1.SetIsReturn(m_bReturn);
m_ctlPoker2.SetIsReturn(m_bReturn);
m_ctlPoker3.SetIsReturn(m_bReturn);
}
在标准控件事件中,我只处理了MouseDown
。我用它来确保一次最多只有一个牌被选中,并且右键单击它会翻转牌。当然,您可以选择处理更多事件以满足您的需求。
void CPokerTestDlg::OnMouseDownPoker1(short Button,
short Shift, long x, long y)
{
// TODO: Add your control notification handler code here
m_ctlPoker1.SetIsSelected(TRUE);
m_ctlPoker2.SetIsSelected(FALSE);
m_ctlPoker3.SetIsSelected(FALSE);
if(Button == MK_RBUTTON)
{
m_ctlPoker1.SetBackSide(!m_ctlPoker1.GetBackSide());
}
}
void CPokerTestDlg::OnMouseDownPoker2(short Button,
short Shift, long x, long y)
{
// TODO: Add your control notification handler code here
m_ctlPoker1.SetIsSelected(FALSE);
m_ctlPoker2.SetIsSelected(TRUE);
m_ctlPoker3.SetIsSelected(FALSE);
if(Button == MK_RBUTTON)
{
m_ctlPoker2.SetBackSide(!m_ctlPoker2.GetBackSide());
}
}
void CPokerTestDlg::OnMouseDownPoker3(short Button,
short Shift, long x, long y)
{
// TODO: Add your control notification handler code here
m_ctlPoker1.SetIsSelected(FALSE);
m_ctlPoker2.SetIsSelected(FALSE);
m_ctlPoker3.SetIsSelected(TRUE);
if(Button == MK_RBUTTON)
{
m_ctlPoker3.SetBackSide(!m_ctlPoker3.GetBackSide());
}
}
好了,到目前为止,我认为我已经涵盖了关于这个控件及其使用方法的大部分方面。您也可以在VB程序、网页等中使用它,尽管我个人尚未尝试过。
由于我假定读者对ActiveX控件有一定的了解,因此我省略了一些不必要的细节。对于那些不太熟悉ActiveX控件的读者,Jeff Prosise的《MFC编程》第二版最后一章是一个很好的学习资源。祝您使用愉快!