STL Vector Problem

Started by
17 comments, last by MaulingMonkey 18 years, 10 months ago
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]
Advertisement
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
actually he's doing the delete at the end of main, before shutdown. that's fine.
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.
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
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?
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.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas only, and not for things themselves." - John Locke
God, I need some serious spectacles. Sorry for bothering everyone; I give up.
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!
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));

This topic is closed to new replies.

Advertisement