Sign in to follow this  

Custom Control: Infinite Draw Loop

This topic is 2811 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi I am trying to create my own control called an update box which right now looks & acts exactly like a Listbox control but when I get that working I want to add more things. Its programmed in c++ win32. But my problem is that my program crashes. The objects being drawn seem to be constantly being redrawn & I am not sure why(where in my code this is occuring). To describe what it looks like; the object is drawn(a custom made listbox) & a row(cell) is added to the listbox & drawn. Then it seems the whole client window is cleared & everything disappears, then the same things are drawn again, then cleared & it seems the program goes into an infinite loop. Can you help me figure out what is going wrong & where? Header File:
#ifndef UPDATEBOX_H
#define UPDATEBOX_H

#include <windows.h>
#include <string>
#include <vector>

using namespace std;

#define UB_DRAWCELL 999

// Update Box Cell Object
class ubCell {
     
     public:
          ubCell(HWND Hwnd, POINT p, int wdth, int hght);
          bool drawControl();
          ~ubCell();
            
     private:
          // COLUMN parentCol; // consider a parent object column
          POINT pos;
          int width;
          int height;
          HWND hwnd;
          HRGN region;
          HBRUSH bgBrush;
          HBRUSH frameBrush;
          string data;
};

// Visual Control - Similar to a List Box control but with more custom functionality
class updateBox {
      
      public:
           updateBox(HWND Hwnd, POINT p, int wdth, int hght);
           ~updateBox();
           bool drawControl();
           void addCell();
             
      private:
           POINT pos;
           int width;
           int height;
           int cellHeight;
           HWND hwnd;
           HRGN region; // Why HRGN & not RECT? So I can develop this class further to create controls that have irregular shapes
           HBRUSH bgBrush;
           HBRUSH frameBrush;
           int columns;
           int rows;
           ubCell *focusCell;
           vector <ubCell*> cellList;          
};

#endif



Implementation:
#include <windows.h>
#include <string>
#include <vector>

#include "updateBox.h"

using namespace std;



/// Update Box Control Class ///
///                          ///
updateBox::updateBox(HWND Hwnd, POINT p, int wdth, int hght)
{
   // Post: Constructor
   
   pos.x      = p.x;
   pos.y      = p.y;
   width      = wdth;
   height     = hght;
   cellHeight = 20;
   hwnd       = Hwnd;
   bgBrush    = CreateSolidBrush(RGB(255,255,255));
   frameBrush = CreateSolidBrush(RGB(0,0,0));
   columns    = 2;
   rows       = 1;
   
   // Call Functions
   drawControl();
   addCell();
}

updateBox::~updateBox()
{
   // Post: Default Destructor
   DeleteObject(hwnd);
   DeleteObject(region);
   
   while (!cellList.empty()) {
         
         delete cellList.back(); // WILL this call the ubCell Destructor??
         cellList.pop_back();
   }     
}

bool updateBox::drawControl()
{
   // Post: Draw Control
   // IT SEEMS THIS FUNCTION IS BEING PERFORMED REPEATEDLY BUT I DONT KNOW WHY
   
   HDC hdc;
   PAINTSTRUCT ps;
   hdc = BeginPaint(hwnd,&ps);
   
   // Create Background
   region = CreateRectRgn(pos.x,pos.y,pos.x+width,pos.y+height);
   if (region != NULL) 
   {
       InvalidateRgn(hwnd,region,true);
       int success = FillRgn(hdc,region,bgBrush);
       success = FrameRgn(hdc,region,frameBrush,1,1);
       if (success==0) {
           MessageBox(hwnd,"Failed to fill/frame background HRGN","Error:",MB_OK|MB_ICONERROR);  
           return false;  
       }  
   }
   else {
       MessageBox(hwnd,"Create background region Failed","Error:",MB_OK|MB_ICONERROR);
       return false;
   }
   
   EndPaint(hwnd,&ps); 
   return true;     
}

void updateBox::addCell()
{
   // Post: Add a row to Update Box
   
   POINT tPos;
   tPos.x = pos.x;
   tPos.y = pos.y+(cellList.size()*cellHeight);
   ubCell *newCell = new ubCell(hwnd,tPos,width,cellHeight);
   focusCell = newCell;
   cellList.push_back(newCell);
}



/// Update Box Cell Object ///
///                        ///

ubCell::ubCell(HWND Hwnd, POINT p, int wdth, int hght)
{
   // Post: Constructor
   
   pos.x      = p.x;
   pos.y      = p.y;
   width      = wdth;
   height     = hght;
   hwnd       = Hwnd;
   bgBrush    = CreateSolidBrush(RGB(0,0,255));
   frameBrush = CreateSolidBrush(RGB(255,0,0));
   data       = "...empty";
   
   // Call Functions
   drawControl();
}

ubCell::~ubCell()
{
   // Post: Destructor
   DeleteObject(hwnd);
   DeleteObject(region);  
}

bool ubCell::drawControl()
{
   // Post: Draw Cell control
   // IT SEEMS THIS FUNCTION IS BEING PERFORMED REPEATEDLY BUT I DONT KNOW WHY
   
   HDC hdc;
   PAINTSTRUCT ps;
   hdc = BeginPaint(hwnd,&ps);
   
   // Create Background
   region = CreateRectRgn(pos.x,pos.y,pos.x+width,pos.y+height);
   if (region != NULL) 
   {
       InvalidateRgn(hwnd,region,true); // I think the problem is here
       int success = FillRgn(hdc,region,bgBrush);
       success = FrameRgn(hdc,region,frameBrush,1,1);
       //success = DrawText(hdc,data.c_str(),data.length(),(LPRECT)region,DT_INTERNAL);
       success = SetBkMode(hdc,TRANSPARENT);
       success = TextOut(hdc,pos.x+2,pos.y+4,data.c_str(),data.length());
       if (success==0) {
           MessageBox(hwnd,"Failed to fill/frame background HRGN OR draw data contents.","Error:",MB_OK|MB_ICONERROR);  
           return false;  
       }  
   }
   else {
       MessageBox(hwnd,"Create background region Failed","Error:",MB_OK|MB_ICONERROR);
       return false;
   }
   
   MessageBox(hwnd,"","",MB_OK);
   EndPaint(hwnd,&ps);
   return true;
}




WinMain:
#include <windows.h>
#include <cstdlib>

#include "updateBox.h"

using namespace std;

// Global Variables
static HINSTANCE gInstance;
bool test = true;

// Functions
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = gInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = "Custom Class";
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        "Custom Class",
        "Custom Control: Update Box Class",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, 600, 600,
        NULL, NULL, gInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CREATE:
        {

        }     
        break;
        case WM_COMMAND:
        {
             switch(LOWORD(wParam)) {
                   
                   case WM_KEYDOWN:
                   {
                        if (HIWORD(wParam) == VK_SPACE) {
                            InvalidateRect(hwnd,NULL,true);
                        }
                   }    
                   break;
                   default:
                   break;                
             }            
        }    
        break;
        case WM_PAINT:
        {
             if (test) {
                 POINT p;
                 p.x = 10;
                 p.y = 10;
                 updateBox ub(hwnd,p,200,200);
                 test = false;
                 MessageBox(hwnd,"code Performed","",MB_OK);
             }
             else MessageBox(hwnd,"code NOT performed","",MB_OK);
        }     
        break;
        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}



Share this post


Link to post
Share on other sites
As you suspected: The InvalidateRgn call seems to set the window to dirty again.

Also, never use MessageBoxes inside WM_PAINT calls to "debug". You only repeatedly invalidate the window region.

Also, MOVE THE return DefWindowProc AFTER THE SWITCH. NOT IN THE DEFAULT CASE. EVER.

I've removed the MessageBox stuff from the WM_PAINT handler and also the test=false line.

Also, initialize the region to NULL and DO NOT CALL DeleteObject on HWND (Destructor of updateBox). HWNDs are not GDI objects.

After those changes it runs quite smooth (your cell is a white square with a thin black border?)

Share this post


Link to post
Share on other sites
Hi thanks for your help

It seems now your advice has fixed the repeated repainting but when I delete the lines that invalidate the regions in both classes drawControl() functions then yes it just draws the list box outline. But it is meant to draw the row(cell) aswell, which right now is a blue background, red frame & text "...empty". So if I delete the InvalidateRgn(); from ubCell class but keep the InvalidateRgn() funct in updateBox class then the row is drawn BUT not the listbox outline?

Hmm, its really confusing why I am getting this error? Do you think this is a really hack/bad way of creating my own control? Is there a better way of doing what I am trying to do? Is this how an Edit box or List box is coded?

Share this post


Link to post
Share on other sites
Good Effort. Creating a custom win32 Control is not easy. But I love to do it.
Your Object Oriented Paradigm is a bit wrong the updateBox object is supposed to be persistent, either global or created with new.
Then you need a way of mapping an HWND to an updateBox object. You can use an STL map or store the Pointer to the updateBox object in the Window extra Data.
Binding C++ to GUI objects is not a trivial subject. MFC does it one way, ATL does it a bit different, WxWidgets and Qt will also have their own binding Technology.
Here is a very old code of mine. It should give you an Idea of how to bind a C++ object to an HWND. My current technology is a bit more complex than this example, but is still based in the same Principle of having a Temporary Window Procedure that allocates the Object.


void RegisterGridCtrl ( HINSTANCE hinst )
{
WNDCLASS wc ;

if ( ! ( ::GetClassInfo ( hinst,
GRIDCTRL_WNDCLASS, & wc ) ) ) {

InitIELib () ;

wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW ;
wc.lpfnWndProc = RawGridCtrl::CreateWndProc ;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
wc.hInstance = hinst ;
wc.hIcon = NULL ;
wc.hCursor = ::LoadCursor ( NULL, IDC_ARROW ) ;
wc.hbrBackground = ::GetSysColorBrush ( COLOR_WINDOW ) ;
//wc.hbrBackground = ( HBRUSH ) ::GetStockObject ( BLACK_BRUSH ) ;
wc.lpszClassName = GRIDCTRL_WNDCLASS ;
wc.lpszMenuName = NULL ;

::RegisterClass ( & wc ) ;
}
}

HWND GridCtrl::Create ( int x, int y, int nWidth, int nHeight,
HWND hWndparent, int id, HINSTANCE hInstance )
{
hwnd = CreateWindow ( GRIDCTRL_WNDCLASS, "",
WS_CHILD | WS_VISIBLE | WS_BORDER,
x, y, nWidth, nHeight,
hWndparent, ( HMENU ) id, hInstance, NULL ) ;

::SendMessage ( hwnd, GCM_SETROWWIDTH, cxRowWidth, 0 ) ;
::SendMessage ( hwnd, GCM_SETROWCOUNT, 0, nRows ) ;

return hwnd ;
}


LRESULT CALLBACK RawGridCtrl::CreateWndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
RawGridCtrl * prgc ;

prgc = new RawGridCtrl ;

::SetWindowLong ( hwnd, GWL_USERDATA, ( long ) prgc ) ;
::SetWindowLong ( hwnd, GWL_WNDPROC, ( long ) RawGridCtrl::WndProc ) ;

return CallWindowProc ( RawGridCtrl::WndProc, hwnd, message,
wParam, lParam ) ;
}

LRESULT CALLBACK RawGridCtrl::WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
RawGridCtrl * prgc ;

//////////////////////////////////
prgc = ( RawGridCtrl * ) ::GetWindowLong ( hwnd, GWL_USERDATA ) ;

// Now you can use prgc anyway you like to process the messages
switch ( message ) {

...
case WM_PAINT :

prgc->Paint () ;

return 0 ;

...



About your bug, make your Object persistent first, then it will be easier for someone to help you.

Share this post


Link to post
Share on other sites
* In the WM_KEYDOWN switch case, you should call UpdateWindow() right after you call InvalidateRect(). Without this call pressing space will not cause the control to be updated (it won't receive a WM_PAINT message).

* In updateBox::drawControl(), EndPaint() seems to never be reached. This is bad. You should be doing this instead:


case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdcPaint = BeginPaint( hWnd, &ps );
// Call a function or method to draw the control here.
EndPaint( hWnd, &ps );
}
break;


This ensures a BeginPaint() call will be matched with a corresponding EndPaint() call.

* You seem to be filling the background with some color when you paint the control. If so, consider adding

case WM_ERASEBKGND: return 1; // You're painting the background anyway, avoid flicker.


* A region for each element? I really can't imagine why. You are already keeping what seems to be "bounding box" information for each cell, so why not use just rectangles? You can use bitmaps to draw irregularly shaped cells, but their placement in the control as well as user interaction with them should really use rectangles. Of course, this is a general advice as I'm not sure what exactly the control you are creating is supposed to be for.

* There is an article on catch22.net titled "custom control from scratch" I think. It's a must read for anyone wanting to create their own win32 control.

* Instead of creating solid brushes for each item, use this, it's faster and more efficient:

// From catch22.net - could be faster than FillRect.
inline VOID FillRect( HDC hDC, const RECT* pRect, COLORREF color )
{
COLORREF oldColor = SetBkColor( hDC, color );
ExtTextOut( hDC, 0, 0, ETO_OPAQUE, pRect, TEXT(""), 0, 0 );
SetBkColor( hDC, oldColor );
}

Share this post


Link to post
Share on other sites
Thanks for all your help :)

The tutorial was really helpful. I have made alot of progress but I am trying to figure out if it is possible to do this:

-Have an object(window) for the custom control called an updateBox
-Have the object create & run its own Windows Proceedure function as a member function of the class updateBox

But my problem is how to do this, it all gets a bit inbred & "chicken & the egg" problem when I imagine I want to create the control using the function [i]CreateWindowEx() but how, when & where will my object updateBox be created(where should I code this?) from the previous mentioned functioned & can my main Windows Proceedure pass messages to my updateBoxes Windows Proceedure IF its a member function of a class?

Hope this makes sense. Here is the progress I have made:

#ifndef UPDATEBOX_H
#define UPDATEBOX_H

#include <windows.h>
#include <string>
#include <vector>

using namespace std;



// Update Box Cell Object
struct ubCell {

ubCell(HWND Hwnd, POINT p, int wdth, int hght);
bool drawControl();
~ubCell();

// COLUMN parentCol; // consider a parent object column
POINT pos;
POINT textPos;
int width;
int height;
HWND hwnd;
HRGN region;
HBRUSH bgBrush;
HBRUSH frameBrush;
string data;
};

// Visual Control - Similar to a List Box control but with more custom functionality
class updateBox {

public:
updateBox(HWND Hwnd, POINT p, int wdth, int hght);
~updateBox();
//LRESULT CALLBACK createWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
//LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
ubCell* addCell();
bool drawControl(HDC hdc);
bool drawFocusCell(HDC hdc);
bool drawDefaultCell(HDC hdc);
bool inCellRgn(int mouse_x, int mouse_y);
ubCell* findSelection(int mouse_x, int mouse_y);
void SelectCell(int mouse_x, int mouse_y);
void eraseRgn();
//HWND createNewMDIChild(HWND hMDIClient);
//bool setUpMDIChildWindowClass(HINSTANCE hInstance);

private:
POINT pos;
int width;
int height;
int cellHeight;
HWND hwnd;
HRGN region; // Why HRGN & not RECT? So I can develop this class further to create controls that have irregular shapes
HRGN cellRegion;
HBRUSH bgBrush;
HBRUSH frameBrush;
int columns;
ubCell *focusCell;
ubCell *prevFocusCell;
vector <ubCell*> cellList;
bool initialiseDraw;
};


/// Functions ///
void InitUpdateboxClass();
static updateBox* GetUpdateBox(HWND hwnd);
void SetUpdateBox(HWND hwnd, updateBox *udb);
LRESULT CALLBACK UpdateBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

#endif






#include <windows.h>
#include <string>
#include <vector>

#include "updateBox.h"

using namespace std;

/// Register Custom Control Class ///
/// ///
void InitUpdateboxClass()
{
// Post: Register custom class
WNDCLASSEX wc;

wc.cbSize = sizeof(wc);
wc.lpszClassName = "updateBox";
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = UpdateBoxWndProc;
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hIcon = NULL;
wc.lpszMenuName = NULL;
wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_BTNFACE);
wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(updateBox*);
wc.hIconSm = NULL;

if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Update Box Class Registration Failed", "Error",
MB_ICONEXCLAMATION | MB_OK);
}
}

static updateBox* GetUpdateBox(HWND hwnd)
{
// Post:
return (updateBox*)GetWindowLong(hwnd,0);
}

void SetUpdateBox(HWND hwnd, updateBox *udb)
{
// Post:
SetWindowLong(hwnd,0,(LONG)udb);
}

LRESULT CALLBACK UpdateBoxWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Post: Receives all UpdateBox window messages

updateBox *udb = GetUpdateBox(hwnd);

switch (msg)
{
case WM_NCCREATE:
{
udb = (updateBox*)malloc(sizeof(updateBox));

if (udb==false) {
MessageBox(NULL,"Failed to create Update Box window","Error",MB_OK|MB_ICONERROR);
return 0;
}

SetUpdateBox(hwnd,udb); // Attach custom class to this window.
}
break;
case WM_LBUTTONDOWN:
{ // Select/Click a new cell to append/alter
if (udb.inCellRgn(LOWORD(lParam),HIWORD(lParam))) {
udb.SelectCell(LOWORD(lParam),HIWORD(lParam));
udb.eraseRgn();
}
}
break;
case WM_LBUTTONDBLCLK:
{ // Add new cell to update box
if (!udb.inCellRgn(LOWORD(lParam),HIWORD(lParam))) {
prevFocusCell = focusCell;
focusCell = addCell();
udb.eraseRgn();
}
else { // Select Cell
udb.SelectCell(LOWORD(lParam),HIWORD(lParam));
udb.eraseRgn();
}
}
break;
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd,&ps);

if (initialiseDraw) {
drawControl(hdc);
initialiseDraw = false;
}

if (focusCell != prevFocusCell) {
drawDefaultCell(hdc);
}

drawFocusCell(hdc);

EndPaint(hwnd,&ps);
}
break;
/* case WM_ERASEBKGND:
return 1; // You're painting the background anyway, avoid flicker.
break; */

case WM_NCDESTROY:
free(udb);
break;
default:
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}



/// Update Box Control Class ///
/// ///
updateBox::updateBox(HWND Hwnd, POINT p, int wdth, int hght)
{
// Post: Constructor

pos.x = p.x;
pos.y = p.y;
width = wdth;
height = hght;
cellHeight = 20;
hwnd = Hwnd;
region = NULL;
cellRegion = NULL;
bgBrush = CreateSolidBrush(RGB(255,255,255));
frameBrush = CreateSolidBrush(RGB(0,0,0));
columns = 2;
focusCell = addCell();
prevFocusCell = focusCell;
initialiseDraw = true;
}

updateBox::~updateBox()
{
// Post: Default Destructor
DeleteObject(region);
DeleteObject(cellRegon);

while (!cellList.empty()) {

delete cellList.back(); // WILL this call the ubCell Destructor??
cellList.pop_back();
}
}

/* LRESULT CALLBACK updateBox::createWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// Post:
updateBox *newObj = new updateBox(hwnd,p,width,height);
SetWindowLong ( hwnd, GWL_USERDATA, ( long )) ;
SetWindowLong ( hwnd, GWL_WNDPROC, ( long )updateBox::UpdateBoxWndProc ) ;

return CallWindowProc (updateBox::UpdateBoxWndProc, hwnd, message,wParam, lParam ) ;
} */


ubCell* updateBox::addCell()
{
// Post: Add a ubCell/row to Update Box

POINT tPos;
tPos.x = pos.x;
tPos.y = pos.y+(cellList.size()*cellHeight);
ubCell *newCell = new ubCell(hwnd,tPos,width,cellHeight);
cellList.push_back(newCell);

int success = CombineRgn(cellRegion,newCell->region,cellRegion,RGN_XOR); // update cellRegion
if (success==NULLREGION || success==ERROR) {
MessageBox(hwnd,"Failed to combine new ubCell region & cellRegion.","Error",MB_OK|MB_ICONERROR);
}
return newCell;
}

bool updateBox::drawControl(HDC hdc)
{
// Post: Draw Control
// Create Background
region = CreateRectRgn(pos.x,pos.y,pos.x+width,pos.y+height);
if (region != NULL)
{
//InvalidateRgn(hwnd,region,true);
int success = FillRgn(hdc,region,bgBrush);
success = FrameRgn(hdc,region,frameBrush,1,1);
if (success==0) {
//MessageBox(hwnd,"Failed to fill/frame background HRGN","Error:",MB_OK|MB_ICONERROR);
return false;
}
}
else {
//MessageBox(hwnd,"Create background region Failed","Error:",MB_OK|MB_ICONERROR);
return false;
}

return true;
}

bool updateBox::drawFocusCell(HDC hdc)
{
// Post: Draw ubCell 'appending' style
// CREATE CARAT
}

bool updateBox::drawDefaultCell(HDC hdc)
{
// Post: Draw ubCell 'default' style
// Write time in bold, other data in normal font, if other data is longer than cell width, we resize ubCell height
}

bool updateBox::inCellRgn(int mouse_x, int mouse_y)
{
// Post: Returns true if mouse lies/clicked any ubCell else false
int collision = PtInRegion(cellRegion,mouse_x,mouse_y);
if (collision != 0) {
return true;
}
else return false
}

ubCell* updateBox::findSelection(int mouse_x, int mouse_y)
{
// Post: Return the ubCell the user has selected with mouse
// ITERATIVE METHOD !!!! NOT EFFICIENT FIND OTHER WAY
for (int i=0 i<cellList.size(); i++) {
int collision = PtInRegion(cellList.at(i)->region,mouse_x,mouse_y);
if (collision != 0) {
return cellList.at(i);
}
}
return NULL; // Should not get to this point if function is used correctly but just incase return NULL pointer
}

void SelectCell(int mouse_x, int mouse_y)
{
// Post:
ubCell *selectedCell = findSelection(LOWORD(lParam),HIWORD(lParam));

if (selectedCell != focusCell) {
prevFocusCell = focusCell;
focusCell = selectedCell;
}
}

void updateBox::eraseRgn()
{
// Post:
InvalidateRgn(hwnd,focusCell.region,true); // Clear new focus cells rgn
InvalidateRgn(hwnd,prevFocusCell.region,true); // clear prev focus cells rgn
UpdateWindow(hwnd); // Send message WM_PAINT
}

/* HWND updateBox::createNewMDIChild(HWND hMDIClient)
{
MDICREATESTRUCT mcs;
HWND hChild;

mcs.szTitle = "Update Box";
mcs.szClass = "updateBox";
mcs.hOwner = GetModuleHandle(NULL);
mcs.x = mcs.cx = CW_USEDEFAULT;
mcs.y = mcs.cy = CW_USEDEFAULT;
mcs.style = MDIS_ALLCHILDSTYLES;

hChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LONG)&mcs);
if(!hChild)
{
MessageBox(hMDIClient, "MDI Child creation failed.", "Oh Oh...",
MB_ICONEXCLAMATION | MB_OK);
}
return hChild;
}

bool updateBox::setUpMDIChildWindowClass(HINSTANCE hInstance)
{
WNDCLASSEX wc;

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "updateBox";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))
{
MessageBox(0, "Could Not Register Child Window", "Oh Oh...",
MB_ICONEXCLAMATION | MB_OK);
return false;
}
else
return true;
} */




/// Update Box Cell Object ///
/// ///

ubCell::ubCell(HWND Hwnd, POINT p, int wdth, int hght)
{
// Post: Constructor

pos.x = p.x;
pos.y = p.y;
width = wdth;
height = hght;
hwnd = Hwnd;
region = NULL;
textPos.x = pos.x+2;
textPos.y = pos.y+1;
bgBrush = CreateSolidBrush(RGB(0,0,255));
frameBrush = CreateSolidBrush(RGB(255,0,0));
data = "...empty";
}

ubCell::~ubCell()
{
// Post: Destructor
DeleteObject(region);
}

bool ubCell::drawControl()
{
// Post: Draw Cell control
// Create Background
region = CreateRectRgn(pos.x,pos.y,pos.x+width,pos.y+height);
if (region != NULL)
{
//InvalidateRgn(hwnd,region,true);
int success = FillRgn(hdc,region,bgBrush);
success = FrameRgn(hdc,region,frameBrush,1,1);
//success = DrawText(hdc,data.c_str(),data.length(),(LPRECT)region,DT_INTERNAL);
success = SetBkMode(hdc,TRANSPARENT);
success = TextOut(hdc,textPos.x,textPos.y,data.c_str(),data.length());
if (success==0) {
//MessageBox(hwnd,"Failed to fill/frame background HRGN OR draw data contents.","Error:",MB_OK|MB_ICONERROR);
return false;
}
}
else {
//MessageBox(hwnd,"Create background region Failed","Error:",MB_OK|MB_ICONERROR);
return false;
}

return true;
}




Share this post


Link to post
Share on other sites

This topic is 2811 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this