Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

An ActiveX Control for Poker games

0.00/5 (No votes)
14 Jul 2002 2  
With this control, you can easily build up your own Poker games.

Sample Image - screen.jpg

Introduction

This is an ActiveX control for Poker games. I added several functions to it so that it can fulfill most responsibilities a card should take in a Poker game. Since it's an ActiveX control, practically, it can be used in programs written by any ActiveX-supported languages, like VC++, VB...even in a webpage. Furthermore, with the code I provide to you, you can easily revise it to satisfy your specific requirements, of course, with your knowledge of ActiveX control.

About the control

Each instance of the control class represents a card. It has the following functions and properties attached to it, which a user can manipulate.

Functions

  • BOOL SetValue(short nNewValue): sets the value of the card. The relationship between the value and the card is like:
    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
    (Note: sorry for my English if I don't use a right term in the Poker game because I am not a native speaker.)
  • short GetValue(): gets the value of the card.
  • BOOL SetBackID(short nNewID): sets the backside picture of the card. There are two pictures to choose from, which have IDs 1 and 2.
  • short GetBackID(): gets the current backside picture's ID( 1 or 2).

Properties

These are the properties I added to the control. However, you can't access them directly except at the visual design time. You have to do it with the help of the following functions.

  • BOOL GetBackSide(): to see whether the card is showing the backside now. TRUE means it's showing the backside, and vice versa.
  • void SetBackSide(BOOL): make the card show its backside or front side.
  • BOOL GetIsMovable(): to see whether the card can be dragged by a mouse. TRUE means it can, and vice versa.
  • void SetIsMovable(BOOL): make the card can or cannot be draggable.
  • BOOL GetIsReturn(): to see whether the card can return to its original place after dragging. TRUE means it can, and vice versa.
  • void SetIsReturn(BOOL): make the card can or cannot return to its original place after dragging.
  • BOOL GetIsSelected(): to see whether the card is currently selected. A selected card have a red frame around it.
  • void SetIsSelected(BOOL): make the card selected or not selected.

For functions, you can call them in your program. For the properties, of course you can also call them in your program. Furthermore, you can set their values at the design time, say, in the resource editor. When choosing the properties of the ActiveX control, you can see some checkboxes for the properties I introduced above. You set the initial values over there and most possibly, change it later in your code by calling the corresponding GetXXX() and SetXXX() methods.

Note: I added another function to the control. Whenever you click on it with the left mouse button, it will be selected, which is indicated by a red frame around it.

Stock ActiveX events

At last, I added five stock ActiveX events to the control. They are Click, DblClick, MouseDown, MouseMove and MouseUp. In your program, you can process any number of these events using event sink maps. For example, in my test program, I processed the MouseDown event: when you click the card with the right mouse button, you flip it.

Some coding details

I had drawn the card according to its current value. I saved 54 bitmaps in the program and load them programmatically like this:

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);
    }
}

To move the card, I processed MouseDown, MouseMove and MouseUp events. Please don't mix them up with those same-name stock ActiveX events. They're different concepts.

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);
}

To use the control

Register the control

Like any COM object, an ActiveX control can't be used unless it is registered on the host system. If you build the control with Visual C++ yourself, the control is automatically registered as part of the build process. If you want to use the control directly without bothering to compile it, you need to register it on your system, before it can be used. Here are two ways to register a control on your system.

The first way is to register the control programmatically. Because an OCX is a self-registering in-proc COM server, the program can load the OCX as if it were an ordinary DLL, find the address of its DllRegisterServer function, and call the function. DllRegisterServer, in turn, will register any and all of the controls in the OCX. The following code demonstrates how this is done if the OCX is named 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);
}

The second way is to use the Regsvr32 utility that comes with Visual C++. If Poker.ocx is in the current directory, typing the following command into a command prompt window will register the OCX's controls:

Regsvr32 Poker.ocx

By the same token, passing a /U switch to Regsvr32 unregisters the controls in an OCX:

Regsvr32 /U Poker.ocx

Use it

You add it to your program just like an ordinary control, say, add it to your dialog. You can size it as you like. You can set the properties in the properties menu entry. Later in your code, you can change them by calling the corresponding functions.

In my test program, I added three controls to the dialog, and three member variables, one for each control.

// 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);

I also added two checkboxes to demonstrate how to toggle the properties IsMovable and 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);
}

In the stock control events, I only processed MouseDown. I used it to make sure that at most one card gets selected at a time and a right click on it will flip the card. Of course, you can choose to process more events to fit your needs.

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());
    }    
}

Well, so far, I think I have covered most aspects about this control and how to use it. You can also use it in your VB program, webpage and so on although I haven't tried it myself.

Since I suppose the readers have a certain knowledge about ActiveX control, I skipped some unnecessary details. For those of you who is not quite familiar with ActiveX control, the last chapter of "Programming Windows with MFC", 2nd Edition by Jeff Prosise, is a good resource to learn. Enjoy!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here