Sign in to follow this  
Programmer16

STL Vector Problem

Recommended Posts

Programmer16    2321
Okay, I've used the STL vector alot and I've never had any problems until now. I can't figure out why this code isn't working. I use the debugger and when it gets the OnMouseMove() in the WM_MOUSEMOVE code block, it sets the m_bMouseHover to true (if the mouse is over it), but when it gets to WM_PAINT, its back to false.
#include "DevFuncs.h"
#include <vector>

LRESULT CALLBACK GuiInputProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
bool Frame();

class Widget
{
	D3DXVECTOR2	m_Position;
	UINT		m_nWidth, m_nHeight;
	bool		m_bMouseHover;
public:
	void Create(float fX, float fY, UINT nWidth, UINT nHeight)
	{
		m_Position		= D3DXVECTOR2(fX, fY);
		m_nWidth		= nWidth;
		m_nHeight		= nHeight;
		m_bMouseHover	= false;
	}

	void Render(HDC hDC)
	{
		RECT Rect;
		UINT nEdge = 0;
		SetRect(&Rect, m_Position.x, m_Position.y, m_Position.x + m_nWidth, m_Position.y + m_nHeight);
		if(m_bMouseHover)
			nEdge = EDGE_SUNKEN;
		else
			nEdge = EDGE_RAISED;
		DrawEdge(hDC, &Rect, nEdge, BF_RECT);
	}

	void OnMouseMove(WPARAM wParam, LPARAM lParam)
	{
		UINT nX = 0, nY = 0;
		nX = LOWORD(lParam);
		nY = HIWORD(lParam);
		RECT Rect;
		SetRect(&Rect, m_Position.x, m_Position.y, m_Position.x + m_nWidth, m_Position.y + m_nHeight);
		if(nX > m_Position.x && nY > m_Position.y && nX < (m_Position.x + m_nWidth) && nY < (m_Position.y + m_nHeight))
			m_bMouseHover = true;
		else
			m_bMouseHover = false;
	}
};

std::vector<Widget*> g_Controls;

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	Widget* Ctrl1 = new Widget;
	Ctrl1->Create(10, 10, 25, 25);
	g_Controls.push_back(Ctrl1);

	Widget* Ctrl2 = new Widget;
	Ctrl2->Create(45, 35, 35, 30);
	g_Controls.push_back(Ctrl2);

	SetUpSystem(GuiInputProc);
	StartLoop(Frame);
	ShutDownSystem();
	delete Ctrl2;
	delete Ctrl1;
	return 0;
}

bool Frame()
{
	return true;
}

LRESULT CALLBACK GuiInputProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	switch(nMsg)
	{
	case WM_DESTROY:
	case WM_CLOSE:
		{
			PostQuitMessage(0);
			return 0;
		}

	case WM_PAINT:
		{
			PAINTSTRUCT Paint;
			BeginPaint(hWnd, &Paint);

			for(UINT nIndex = 0; nIndex < g_Controls.size(); ++nIndex)
			{
				Widget* pCtrl = g_Controls.at(nIndex);
				pCtrl->Render(Paint.hdc);
			}
			EndPaint(hWnd, &Paint);
			return 0;
		}

	case WM_MOUSEMOVE:
		{
			for(UINT nIndex = 0; nIndex < g_Controls.size(); ++nIndex)
			{
				Widget* pCtrl = g_Controls.at(nIndex);
				pCtrl->OnMouseMove(wParam, lParam);
			}
			return 0;
		}
	}
	return DefWindowProc(hWnd, nMsg, wParam, lParam);
}



Edit: I've also tried an iterator:
std::vector<Widget*>::iterator pItor = g_Controls.begin();
while(pItor != g_Controls.end())
{
Widget* pCtrl = ((Widget*)pItor);
pCtrl->Function();
++pItor;
}


But with the iterator it never even shows up (m_nWidth and m_nHeight are never assigned the values that they should be). The code in OnMouseMove() works fine (it sets it to true when I'm above it, and false when I'm not), but for some reason it doesn't seem to be keeping the value. Edit: With the current setup, all of the values are good (i.e. the width and height are correct), but the changes are only temporary. Thanks [Edited by - Programmer16 on June 9, 2005 3:03:21 PM]

Share this post


Link to post
Share on other sites
Illco    928
You have a vector of pointers. The elements will be stored as is -- not copies. But after insertion you delete the pointers. Hence, the pointers in the vector are invalid.


int* p = new int;
std::vector v<int*>;
v.push_back( p );
delete p;

// v[0] is now a pointer to invalid memory


Greetz,

Illco

Share this post


Link to post
Share on other sites
Programmer16    2321
Quote:
Original post by Illco
You have a vector of pointers. The elements will be stored as is -- not copies. But after insertion you delete the pointers. Hence, the pointers in the vector are invalid.


int* p = new int;
std::vector v<int*>;
v.push_back( p );
delete p;

// v[0] is now a pointer to invalid memory


Greetz,

Illco


I delete them at the end of the program.
SetUpSystem() creates the window (and any other stuff like DirectX and such).
StartLoop() starts the message (using PeekMessage()).
ShutDownSystem() destroys the extra systems (like DirectX).

Edit: oops, beat to it.

Share this post


Link to post
Share on other sites
Illco    928
Ah, true good point. But this might be it: in a switch statement each case should be ended by break. Now for every message all cases get executed. Also, for messages your application handles you should return 0L from the WindowProc, instead of returning DefWindowProc.

Greetz,

Illco

Share this post


Link to post
Share on other sites
Programmer16    2321
Quote:
Original post by Illco
Ah, true good point. But this might be it: in a switch statement each case should be ended by break. Now for every message all cases get executed. Also, for messages your application handles you should return 0L from the WindowProc, instead of returning DefWindowProc.

Greetz,

Illco


True, but 'return 0;' will work fine since it exits the function (with the window procedure you're supposed to return 0 if you handle the message).

I did double check and only the message's case is getting executed.

I should return 0L? I've always been told to return DefWindowProc() (and I've always seen it done this way). What about WM_NCCREATE? If I return 0L, won't the window not get created?

Share this post


Link to post
Share on other sites
Agony    3452
Quote:
Original post by Illco
Ah, true good point. But this might be it: in a switch statement each case should be ended by break. Now for every message all cases get executed.
His return statements take care of that already.

I honestly can't find any problem with it, and I stared at it kinda hard. My best guess is that between OnMouseMove() getting called and m_bMouseHover getting set to true, and Render() getting called, OnMouseMove() gets called again, and sets m_bMouseHover back to false. But if he's doing breakpoints and watching everything, I don't see how that would happen.

Share this post


Link to post
Share on other sites
Programmer16    2321
Okay, I am really sorry for bothing everybody. Its seems that there isn't anything wrong with my STL (as far as I know). I've never really used Win32 for graphics and I guess I'm only getting WM_PAINT message once. Does anybody know how I fix this?

Again, I'm really sorry!

Share this post


Link to post
Share on other sites
snk_kid    1312
i know you have already found the problem but i just want to mention something

Quote:
Original post by Programmer16
Widget* pCtrl = ((Widget*)pItor);


This is not wright, setting a side the fact that C-style casts are bad for [grin], iterators are typically are user-defined types even if they really turn out to be plain pointers (rarely the case) you shouldn't make that assumption that they are. Also if you're imp's vector's iterators where plain pointers in this case it would have most likely been a "pointer to pointer to Widget" not a pointer to widget.

Normally if you wanted to work with the actual value instead of directly with an iterator you dereference the iterator and it returns (constant) reference to the element, i.e:


const foo& foo_ref = *my_const_itr;


Also prefer using the generic algorithms over explicit loop code on containers, in this case you could do:


#include <algorithm> // for_each
#include <functional> // mem_fun

//...

std::for_each(g_Controls.begin(), g_Controls.end(),
std::mem_fun(&Widget::Render));

Share this post


Link to post
Share on other sites
MaulingMonkey    1730
Quote:
Original post by snk_kid
i know you have already found the problem but i just want to mention something

Quote:
Original post by Programmer16
Widget* pCtrl = ((Widget*)pItor);


This is not wright, setting a side the fact that C-style casts are bad for [grin]


Indeed, this should be done like so:
Widget* pCtrl = &*pItor;

Widget** ppCtrl = &*pItor;
or:
Widget&* pCtrl = *pItor;
or:
Widget* pCtrl = *pItor;

Type and const-safe without any casts too!!! :-).

[Edited by - MaulingMonkey on June 9, 2005 5:07:32 PM]

Share this post


Link to post
Share on other sites
Programmer16    2321
I thought I was doing that wrong, but it seems to work fine (I'm still going to change it, because I know that just because something works once doesn't mean it always will). Also, I wanted to use for_each(), but I didn't know what header it was in.

Edit: I can't get for_each() to work (I think its because I need to pass an HDC to it Render()).

Thanks guys!

Share this post


Link to post
Share on other sites
snk_kid    1312
Quote:
Original post by MaulingMonkey
Indeed, this should be done like so:
Widget* pCtrl = &*pItor;


Ah but he has a vector of pointer to Widget [wink]

either:


Widget* pCtrl = *pItor;


or if he wants to actually modify the original value stored in the vec.


Widget*& pCtrl = *pItor;


Quote:
Original post by Programmer16
I didn't know what header it was in.


Handy reference here even if its not 100% correct.

Share this post


Link to post
Share on other sites
Agony    3452
Quote:
Original post by Programmer16
Okay, I am really sorry for bothing everybody. Its seems that there isn't anything wrong with my STL (as far as I know). I've never really used Win32 for graphics and I guess I'm only getting WM_PAINT message once. Does anybody know how I fix this?

I believe the typical method is to use some form of a timer or loop to continually tell Windows to repaint your window (as in send you a WM_PAINT message), by using either UpdateWindow() or InvalidateRect().

An easy way to set up a timer would be with SetTimer(). This will send a WM_TIMER message to your window at the (approximately) appropriate times, at which point you'd call one of those two functions above. It's not the most accurate thing in the world time-wise, but it's good to get the basic functionality working. A better timing mechanism can be added later.

And as a couple of side notes, I can't believe I missed that iterator/pointer thingy, and I don't accept your apology for asking questions when the problem was elsewhere. You shouldn't be apologizing to begin with. [smile]

Share this post


Link to post
Share on other sites
snk_kid    1312
Quote:
Original post by Programmer16
Edit: I can't get for_each() to work (I think its because I need to pass an HDC to it Render()).


Sorry only glanced at the code before [grin]


#include <algorithm> // for_each
#include <functional> // bind2nd, mem_fun

std::for_each(g_Controls.begin(), g_Controls.end(),
std::bind2nd(std::mem_fun(&widget::render), Paint.hdc));


Its times like these C++ can do with a boost [grin].

Share this post


Link to post
Share on other sites
Programmer16    2321
[quote]Original post by snk_kid
Quote:
Original post by Programmer16
Its times like these C++ can do with a boost [grin].

Ah, what a coincidence, I just downloaded this.

Edit:
Ok, does anybody know where I can find some boost tutorials? I read the documents, but it doesn't really have any examples (that I can find).

Thanks!

[Edited by - Programmer16 on June 9, 2005 5:51:27 PM]

Share this post


Link to post
Share on other sites
MaulingMonkey    1730
[quote]Original post by Programmer16
Quote:
Original post by snk_kid
Quote:
Original post by Programmer16
Its times like these C++ can do with a boost [grin].

Ah, what a coincidence, I just downloaded this.

Edit:
Ok, does anybody know where I can find some boost tutorials? I read the documents, but it doesn't really have any examples (that I can find).

Thanks!


Any specific part(s) of boost? I've found examples most of the time, just well hidden :-).

Share this post


Link to post
Share on other sites
Programmer16    2321
Quote:
Original post by MaulingMonkey
Any specific part(s) of boost? I've found examples most of the time, just well hidden :-).


Well, I've found some of them (hidden, as you said), but after actually trying to use it, boost seems to actually work like it shoud (so I've been able to figure it out for the most part).

Thanks for all of your help everybody!

Share this post


Link to post
Share on other sites

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