Windowing again....

Started by
17 comments, last by ANSI2000 21 years, 10 months ago
I start things and then leave then out for the longest of times... So now am back to my Windowing class... Here is the code...
  
#ifndef G3DGUI_H
#define G3DGUI_H

// Required include files.

#include <windows.h>
#include <windowsx.h>

namespace G3DGUI
{
	class Object
	{
	public:

		Object(HINSTANCE pInstance, HWND pParent)
		{
			setInstance(pInstance);
			setParent(pParent);
			setHandle(NULL);
			setClassName(NULL);
			setX(0);
			setY(0);
			setWidth(0);
			setHeight(0);
			setStyle(0);
			setStyleEx(0);
			setCaption(NULL);
			setMenu(NULL);			
		}
		
		virtual ~Object() {}

		const HINSTANCE getInstance() const { return(instance); }
		const HWND getParent() const { return(parent); }
		const HWND getHandle() const { return(handle); }
		const char* getClassName() const { return(className); }
		const getX() const { return(x); }		
		const getY() const { return(y); }		
		const getWidth() const { return(width); }		
		const getHeight() const { return(height); }		
		const unsigned int getStyleEx() const { return(styleEx); }
		const unsigned int getStyle() const { return(style); }
		const char* getCaption() const { return(caption); }
		const HMENU getMenu() const { return(menu); }

		void create(const char *pClassName, int pX, int pY, int pWidth, int pHeight, unsigned int pStyle, unsigned int pStyleEx, const char *pCaption, HMENU pMenu = NULL)
		{
			setClassName(pClassName);
			setX(pX);
			setY(pY);
			setWidth(pWidth);
			setHeight(pHeight);
			setStyle(pStyle);
			setStyleEx(pStyleEx);
			setCaption(pCaption);
			setMenu(pMenu);

			windowClass.lpfnWndProc = defaultProc;
			windowClass.hInstance = getInstance();
			windowClass.lpszClassName = getClassName();
			windowClass.cbSize = sizeof(WNDCLASSEX);
			windowClass.cbClsExtra = 0;
			windowClass.cbWndExtra = 0;
			windowClass.style = 0;
			windowClass.hCursor = LoadCursor(0, IDC_ARROW);
			windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
			windowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
			windowClass.hIconSm = LoadIcon(0, IDI_APPLICATION);
			windowClass.lpszMenuName = NULL;

			registerClass();
			
			setHandle(CreateWindowEx(getStyleEx(), getClassName(), getCaption(), getStyle(),
									 getX(), getY(), getWidth(), getHeight(), getParent(),
									 getMenu(), getInstance(), (LPSTR)this));
			update();
			
			show();
		}
		
		void update() { UpdateWindow(getHandle()); }
		void show()	{ ShowWindow(getHandle(), SW_SHOW); }
		void hide()	{ ShowWindow(getHandle(), SW_HIDE); }
		void focus() { SetFocus(getHandle()); }

		static LRESULT CALLBACK defaultProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
		{
			Object *thisObject = (Object*)GetWindowLong(hWnd, GWL_USERDATA);
			
			if(!thisObject)
			{
				if(Msg == WM_CREATE)
				{
					LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
					thisObject = (Object*)lpcs->lpCreateParams;
					SetWindowLong(hWnd, GWL_USERDATA, (LONG)thisObject);
					return thisObject->winProc(Msg, wParam, lParam);
				}
				else
					return DefWindowProc(hWnd, Msg, wParam, lParam); // should never be called

			}
			else
			{
				return thisObject->winProc(Msg, wParam, lParam);
			}
		}
	
		virtual LRESULT winProc(UINT Msg, WPARAM wParam, LPARAM lParam) = 0;

	protected:

		void setInstance(HINSTANCE pInstance) { instance = pInstance; };
		void setParent(HWND pParent) { parent = pParent; };
		void setHandle (HWND pHandle) { handle = pHandle; }		
		void setClassName(const char *pClassName) { className = pClassName; }
		void setX(int pX) { x = pX; }		
		void setY(int pY) { y = pY; }		
		void setWidth(int pWidth) { width = pWidth; }		
		void setHeight(int pHeight) { height = pHeight; }		
		void setStyle(unsigned int pStyle) { style = pStyle; }
		void setStyleEx(unsigned int pStyleEx) { styleEx = pStyleEx; }
		void setCaption(const char *pCaption) { caption = pCaption; }
		void setMenu(HMENU pMenu) { menu = pMenu; }

		bool registerClass()
		{
			if(!RegisterClassEx(&windowClass))
				return(false);
			else
				return(true);
		}
		
		void unRegisterClass()
		{
			UnregisterClass(getClassName(), getInstance());
		}

	private:

		HINSTANCE instance;
		HWND parent;
		HWND handle;
		WNDCLASSEX windowClass;
		const char* className;
		const char*	caption;
		HMENU menu;
		int x;
		int	y;
		int	width;
		int	height;
		unsigned int style;
		unsigned int styleEx;
	};
}

#endif
  
People mentioned that this was unflexible and only good if I wanted to create windows only. How would I fix this problem without having to use templates, like some other gui API out there etc...
Advertisement
For one, separate your abstraction of the WNDCLASS(EX) from that of the HWND.

"Don''t be afraid to dream, for out of such fragile things come miracles."
So Redleaf eventually I will finish this...

So I should keep windowclas(ex) in the base "Object" class and have the hwnd per sub class or the other way around? Keep the hwnd in the base class and put the windowclass(ex) in the sub classes?
Actually, I would probably encapsulate the WNDCLASSEX as a specification or blueprint for a particular type of window. Something that can make the "Objects" you refer to. Then, the Object class would encapsulate the HWND.

"Don''t be afraid to dream, for out of such fragile things come miracles."
So I said it right... The Object will be my base class that will encap the HWND. All other classes that sublclass from Object will have there own WindowClass with required info... Also where shoudl I put the default WindowProc, I guess, with the WindowClass....
Well they wouldn''t inherit from Object.

Your classes encapsulating WNDCLASSEXs would be in a parellel inheritence tree with those that encapsulate HWNDs.

For Example:
ObjectMaker encapsulates WNDCLASSEX
Object encapsulates HWND

ObjectMaker has some method for creating Objects

SpecialObjectMaker inherits from ObjectMaker
SpecialObject inherits from Object

SpecialObjectMaker would make SpecialObjects

"Don''t be afraid to dream, for out of such fragile things come miracles."
Ok now your pushing the factory patern...

So If I understand you correctly...


        class ObjectFactory{public:   ObjectFactory();   virtual ~ObjectFactory();   Object *create(x, y, with, height, parent, menu, classname, caption)   {       // setup the windowClass structure...       Object object = new Object(x, y, width, height, menu, classname, caption); <<---- Is this correct, should only the HWND be passed or the entire WNDCLASSEX struct be passed? Should the parent be passed or is parent attached to the handle one CReateWindowEX is called?       return(object);   }private:   WNDCLASSEX windowClass;}class Object{public:   Object(x, y, width, height, menu, classname, caption);   virtual ~Object();   void update();   void show();   void hide();   void focus();   etc...private:   HWND hwnd;   int x, y, width, height;   char classname[128], caption[128];   HMENU menu;}        


Now where would I put the defaultProc and windowProc CALLBACK?
What else is missing?

[edited by - ANSI2000 on June 6, 2002 10:26:13 AM]

[edited by - ANSI2000 on June 6, 2002 10:29:15 AM]

[edited by - ANSI2000 on June 6, 2002 1:16:10 PM]

[edited by - ANSI2000 on June 6, 2002 1:17:07 PM]
Yes, I suppose I am.

Everything that is tied to the WNDCLASS directly, as a parameter for determining the type of window you would create with it, belongs encapsulated along with it. This includes the classname member you have in the Object class. It also includes the static CALLBACK function for the WndProc that you use as the WNDCLASS function pointer parameter. Then each Object has a member procedure of its own that you can have that static callback relay to, using the creation techniques from your previous method. This allows your window procedure access to your Object properties.

I''m not sure what you mean by defaultProc, as windows has its own default that you can call.


"Don''t be afraid to dream, for out of such fragile things come miracles."
This is what I wrote so far...

BUt of course it is wrong. It does not look like the CALLBACKS are being called...


  namespace G3DGUI{	class Object	{	public:		Object() {}		Object(HWND pParent, HWND pHandle, char *pClassName, int pX, int pY, int pWidth, int pHeight, char *pCaption)		{			MessageBox(NULL, NULL, "boo 4", 0);			parent = pParent;			handle = pHandle;		}				~Object() {}		virtual LRESULT winProc(UINT Msg, WPARAM wParam, LPARAM lParam)		{			switch (Msg)			{			case WM_CREATE:								MessageBox(NULL, NULL, "Create", 0);								break;						case WM_DESTROY:				PostQuitMessage(0);				break;			default:				return(DefWindowProc(handle, Msg, wParam, lParam));			}			return(0);				};		void update() { UpdateWindow(handle); }		void show()	{ ShowWindow(handle, SW_SHOW); }	private:		HWND parent;		HWND handle;		int x, y, width, height;		char className[128];		char caption[128];	};		class ObjectFactory	{	public:		ObjectFactory(HINSTANCE pInstance) : instance(pInstance)		{}				Object *createObject(HWND pParent, char *pClassName, int pX, int pY, int pWidth, int pHeight, char *pCaption)		{			MessageBox(NULL, NULL, "boo 1", 0);			windowClass.lpfnWndProc = defaultProc;			windowClass.hInstance = instance;			windowClass.lpszClassName = pClassName;			windowClass.cbSize = sizeof(WNDCLASSEX);			windowClass.cbClsExtra = 0;			windowClass.cbWndExtra = 0;			windowClass.style = 0;			windowClass.hCursor = LoadCursor(0, IDC_ARROW);			windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);			windowClass.hIcon = LoadIcon(0, IDI_APPLICATION);			windowClass.hIconSm = LoadIcon(0, IDI_APPLICATION);			windowClass.lpszMenuName = NULL;						HWND handle;						handle = CreateWindowEx(NULL, pClassName, pCaption, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,									 pX, pY, pWidth, pHeight, pParent,									 NULL, instance, (LPSTR)this);			MessageBox(NULL, NULL, "boo 2", 0);			registerClass();			object = new Object(pParent, handle, pClassName, pX, pY, pWidth, pHeight, pCaption);			object->update();			object->show();			return(object);		}		static LRESULT CALLBACK defaultProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)		{			MessageBox(NULL, NULL, "Call 1", 0);			Object *thisObject = (Object*)GetWindowLong(hWnd, GWL_USERDATA);						if(!thisObject)			{				MessageBox(NULL, NULL, "Call 2", 0);				if(Msg == WM_CREATE)				{					MessageBox(NULL, NULL, "Call 3", 0);							LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;					thisObject = (Object*)lpcs->lpCreateParams;					SetWindowLong(hWnd, GWL_USERDATA, (LONG)thisObject);					return thisObject->winProc(Msg, wParam, lParam);				}				else				{					MessageBox(NULL, NULL, "Call 4", 0);					return DefWindowProc(hWnd, Msg, wParam, lParam); // should never be called				}			}			else			{				MessageBox(NULL, NULL, "Call 5", 0);								return thisObject->winProc(Msg, wParam, lParam);			}		}		bool registerClass()		{			if(!RegisterClassEx(&windowClass))			{				MessageBox(NULL, NULL, "boo 3a", 0);				return(false);			}			else			{				MessageBox(NULL, NULL, "boo 3b", 0);				return(true);			}		}	private:		Object *object;		HINSTANCE instance;		WNDCLASSEX windowClass;	};}  
Your problem lies here:
handle = CreateWindowEx(NULL, pClassName, pCaption,WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,pX, pY, pWidth, pHeight, pParent, NULL, instance, (LPSTR)this);  


The last parameter is supposed to be a pointer to the "Object" instance you are creating, not to the ObjectFactory itself. Because you are changing the location of your Creation functionality, you have to adjust accordingly. It is no longer in the Object class. You cannot use the this pointer. You will need to be able to create an instance of your Object class before calling CreateWindowEx, so that you can pass the address of that instance as the final parameter for creation.

"Don't be afraid to dream, for out of such fragile things come miracles."

Edit: Well that was certainly lousy formatting on my part.

[edited by - Redleaf on June 6, 2002 7:18:23 PM]

[edited by - Redleaf on June 6, 2002 7:19:24 PM]

This topic is closed to new replies.

Advertisement