|
>>but how does this affect editing labels?
It effects almost everything. When you use LVS_OWNERDATA the control only maintains information
about what item is selected and the control's focus. It's up to you to provide the rest.
When it needs text you provide the text. When it needs the image (icon) you provide it, etc.
LVN_GETDISPINFO is sent to the parent of the control.
In the parent window class, add a OnNotify() function (handler for WM_NOTIFY).
In this example I've used the item's lParam to store an index into some array of structures
which hold the info for each item in the list. I've shown a way to handle LVN_GETDISPINFO for
LVIF_TEXT and LVIF_IMAGE. This would be the bare minimum you'd need to provide to the control.
(Actually I don't think items HAVE to have an image )
All the other notifications are dispatched to functions I've added to my CMyCWndDerivedClass
class...
BOOL CMyCWndDerivedClass::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
NMHDR *pHdr = (NMHDR *)lParam;
if (wParam == IDC_MYLISTVIEWCTRL)
{
if (pHdr->code == LVN_GETDISPINFO)
{
NMLVDISPINFO *pLVDispInfo = (NMLVDISPINFO *)pHdr;
if (pLVDispInfo->item.mask | LVIF_TEXT)
{
LVITEM LVItem;
LVItem.mask = LVIF_PARAM;
LVItem.iItem = pLVDispInfo->item.iItem;
LVItem.iSubItem = 0;
pListCtrl->GetItem(&LVItem);
int nItemIndex = (int)LVItem.lParam;
if (nItemIndex >= 0)
{
pLVDispInfo->item.pszText = <--(point this to the row's text)
}
else
{
pLVDispInfo->item.pszText = _T("ERROR");
}
}
if (pLVDispInfo->item.mask | LVIF_IMAGE)
{
LVITEM LVItem;
LVItem.mask = LVIF_PARAM;
LVItem.iItem = pLVDispInfo->item.iItem;
LVItem.iSubItem = 0;
pListCtrl->GetItem(&LVItem);
int nItemIndex = (int)LVItem.lParam;
pLVDispInfo->item.iImage = <--(provide index into image list here)
}
return TRUE;
}
else if (pHdr->code == LVN_BEGINDRAG)
{
LvnBeginDrag((NMLISTVIEW *)lParam);
return TRUE;
}
else if (pHdr->code == LVN_ITEMCHANGED)
{
LvnItemChanged((NMLISTVIEW *)¬ifyInfo);
return TRUE;
}
else if (pHdr->code == LVN_ITEMACTIVATE)
{
LvnItemActivate((NMITEMACTIVATE *)¬ifyInfo);
return TRUE;
}
else if (pHdr->code == NM_RCLICK)
{
ListRClick((NMLISTVIEW *)lParam);
return TRUE;
}
else if (pHdr->code == NM_DBLCLK)
{
ListDblClick((NMLISTVIEW *)lParam);
return TRUE;
}
else if (pHdr->code == LVN_BEGINLABELEDIT)
{
return LvnBeginLabelEdit((NMLVDISPINFO *)lParam);
}
else if (pHdr->code == LVN_ENDLABELEDIT)
{
return LvnEndLabelEdit((NMLVDISPINFO *)lParam);
}
else if (pHdr->code == LVN_COLUMNCLICK)
{
LvnColumnClick((NMLISTVIEW *)lParam);
return TRUE;
}
} //if (wParam == IDC_MYLISTVIEWCTRL)
return CWnd::OnNotify(wParam, lParam, pResult);
}
|
|
|
|
|
By the way, it's rare that you need to override control classes in MFC. Except for special needs,
controls and their notifications can nearly always be handled in the control's owner window.
That's by design in MFC
Mark
|
|
|
|
|
How do I do image comparison for 2 live video feed?
I am suppose to compare 2 live video feed of vehicular flow. So how do i track the vehicles from the first video to the second video?
pls help. Thanks
|
|
|
|
|
You need to match the items exactly - not just track movement, but work out which vehicle is which ? Will you have any idea what part of teh screen they will be on ? They are two different videos, right ? I'm guessing from different angles ?
Christian Graus - Microsoft MVP - C++
Metal Musings - Rex and my new metal blog
|
|
|
|
|
yup.. i will get 2 videos, one at from the start of the roaad and the other one at about 250m away. i will need to match the vehicle shown in the first video to the one shown in the second video. the angle is about the same
|
|
|
|
|
i would position the cameras so i can capture the license plates on the vehicles, then use a library to convert the license plate number in to text and match for the two vehicles.
I can only please one person a day... today is not your day
|
|
|
|
|
I'm getting fed up of calling LoadString() every other line, so I decided to make a wrapper class. The class works, but I always need to use the '&' address of operator when calling a function.
class CStr
{
public:
TCHAR str[2048];
CStr(){};
CStr(UINT id){ LoadString(GetModuleHandle(NULL),id,str,2048); }
LPTSTR operator&(){ return str; }
};
Its currently called like this:
LPCTSTR foo = &CStr(101);
but I want it to be like this:
LPCTSTR foo = CStr(101);
Is there any way I can hide the '&'?
|
|
|
|
|
Add a casting operator instead of the & operator.
class CStr
{
public:
TCHAR str[2048];
CStr(){};
CStr(UINT id)
{
LoadString(GetModuleHandle(NULL),id,str,2048);
}
operator LPTSTR() { return str; }
};
Steve
|
|
|
|
|
What about a conversion operator?
class CStr<br />
{<br />
public: <br />
TCHAR str[2048]; <br />
CStr(){}; <br />
CStr(UINT id){ LoadString(GetModuleHandle(NULL),id,str,2048); } <br />
operator LPTSTR() {return str;}<br />
};<br />
By the way, in this line:
LPCTSTR foo = CStr(101);<br />
Only a temp object is created for the assignment. foo will be undefined after that!
Try:
CStr fooCStr(101);<br />
LPCTSTR foo = fooCStr;<br />
Mark
|
|
|
|
|
The casting operator works, thanks guys.
Mark Salsbery wrote: Only a temp object is created for the assignment. foo will be undefined after that!
I realise this. This example I gave was very simple, there is infact a base class which stores the loaded string (hoping it will increase the performance a little). The purpose of this wrapper is to make it easier to pass strings into functions, so really I only need a temp assignment.
|
|
|
|
|
>>The purpose of this wrapper is to make it easier to pass strings into functions, so really I only need a temp assignment.
Ok good You won't want to try to persist that returned LPCTSTR from an implicitely created object!!
Mark
|
|
|
|
|
waldermort wrote: I'm getting fed up of calling LoadString() every other line, so I decided to make a wrapper class. The class works, but I always need to use the '&' address of operator when calling a function.
You can use LoadString function of CString .
#define IDS_FILENOTFOUND 1
CString s;
if (! s.LoadString( IDS_FILENOTFOUND ))
{
AfxMessageBox("Error Loading String: IDS_FILENOTFOUND");
...
}
LPCTSTR lpctszOooohBlahBlah = s;
|
|
|
|
|
If I were using MFC I wouldn't need to create a wrapper now would I
Even if that were the case, you would still need to create a CString object, call it's LoadString() member, then pass the object to a function. Thats 3 lines of code. My class allows me to it in a single line, Ie. A wrapper.
|
|
|
|
|
waldermort wrote: If I were using MFC I wouldn't need to create a wrapper now would I
If that's the case then fine or else I would go for CString .
|
|
|
|
|
OK, Still having a little trouble with this. The CStr class is derived from CStrBase class. In the base a static vector is filled with the loaded string. To cut down on memory usage, I first load the string into a buffer, then use operator new to allocate the right sized memory. Trouble is I can't delete it, everywhere I try either causes the string to go out of scope or an assertation failiure.
struct _string
{
UINT id;
LPTSTR str;
_string() { str = NULL; };
_string(const _string& s)
{
id = s.id;
str = s.str;
}
};
class CStrBase
{
public:
static std::vector<_string> m_vec;
static TCHAR m_Buffer[2048];
CStrBase(){};
CStrBase(UINT id,HINSTANCE inst)
{
for ( UINT i=0; i<m_vec.size(); i++ )
if ( id == m_vec[i].id )
return;
m_Buffer[0] = 0;
int len = LoadString(inst,id,m_Buffer,2048);
_string s;
s.id = id;
s.str = new TCHAR [len+1];
_tcscpy_s(s.str,len+1,m_Buffer);
m_vec.push_back(s);
}
~CStrBase()
{
for ( UINT i=0; i<m_vec.size(); i++ )
}
};
TCHAR CStrBase::m_Buffer[2048];
std::vector<_string> CStrBase::m_vec;
class CNStr : public CStrBase
{
public:
TCHAR str[2048];
LPTSTR s;
UINT m_id;
CNStr(UINT id, HINSTANCE inst = GetModuleHandle(NULL)) : CStrBase(id,inst)
{
m_id = id;
}
operator LPCTSTR()
{
for ( UINT i=0; i<m_vec.size(); i++ )
if ( m_vec[i].id == m_id )
return m_vec[i].str;
return _T("");
}
};
|
|
|
|
|
Never mind, easy solution. I just needed to set a pointer and check it in the destructor.
|
|
|
|
|
...also, your struct needs reference counting with the copy ctor you supplied.
|
|
|
|
|
waldermort wrote: I'm getting fed up of calling LoadString() every other line, so I decided to make a wrapper class.
See here.
"Approved Workmen Are Not Ashamed" - 2 Timothy 2:15
"Judge not by the eye but by the heart." - Native American Proverb
|
|
|
|
|
Thanks David, that article is where I got the idea to create this class. But unfortunatly, CMsg is derived from CString and can only be used with functions expecting a CString object. His class would be perfect, but it requires the use of MFC and it doesn't cache loaded strings.
|
|
|
|
|
waldermort wrote: But unfortunatly, CMsg is derived from CString...His class would be perfect, but it requires the use of MFC...
I knew you were looking for a non-MFC solution. How much work would be involved in changing all CString references to std::string instead?
"Approved Workmen Are Not Ashamed" - 2 Timothy 2:15
"Judge not by the eye but by the heart." - Native American Proverb
|
|
|
|
|
Hi,
I'm new to MFC and so this is probably a simple question - but I can't seem to find an answer after much looking. The background to the problem is:
1) I create a standard SDI application (using the wizard in Visual Studio).
2) In the View class (header) I create a combo box member varaible "CComboBox m_Com1; ".
3) I then call the Create function of "m_Com1 " from the "OnInitialUpdate " function of the view ("m_Com1.Create(WS_VISIBLE | CBS_DROPDOWNLIST , CRect(400,100,500,200) , this, 9); ").
This compiles fine but when I run the program and try and start a new file (or open a new file) from the main menu, I hit an assertion failure. This derives from "ASSERT(pWnd->m_hWnd == NULL); // only do once ", within "void AFXAPI AfxHookWindowCreate(CWnd* pWnd) ".
Could anyone tell me why this is happening?
Many thanks,
b_e_n_82
b_e_n_82
|
|
|
|
|
It is telling you that the window has already been created, and this is the second time you are calling Create() .
You may be right I may be crazy -- Billy Joel --
Within you lies the power for good, use it!!!
|
|
|
|
|
You can use of if before create combobox
|
|
|
|
|
Remeber that SDI applications reuse their view when you open a new document.
|
|
|
|
|
b_e_n_82 wrote: 3) I then call the Create function of "m_Com1" from the "OnInitialUpdate" function of the view...
Create the control in the view's OnCreate() method instead.
"Approved Workmen Are Not Ashamed" - 2 Timothy 2:15
"Judge not by the eye but by the heart." - Native American Proverb
|
|
|
|