Page 1 of 1

Cum "prind" VK_RETURN in combobox in PreTranslateMessage?

Posted: 01 Nov 2013, 16:54
by mesajflaviu
Am o aplicatie simpla, SDI, cu view-ul bazat pe CFormView. Pe acea forma, am mai multe controale, printre care si un CComboBox. Problema e ca nu pot sa prind tasta Enter cand user-ul se afla focusat pe controlul CComboBox ... iata cateva incercari:

Code: Select all

BOOL CTestView::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class

//	if(GetFocus() && GetFocus()->GetDlgCtrlID() == IDC_COMBO1)
//	 if(pMsg->hwnd == GetDlgItem(IDC_COMBO1)->GetSafeHwnd())
	if(GetFocus()->GetSafeHwnd() == m_Combo.GetSafeHwnd())
		TRACE("aaaaaaaaa\n");

	return CFormView::PreTranslateMessage(pMsg);
}
de fapt, nu pot stii in PreTranslateMessage cand focusul este in CComboBox ... nu acelasi lucru se intampla cand ma aflu an alt tip de control .. CEdit de exemplu ... de ce ?

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 01 Nov 2013, 18:05
by Ovidiu Cucu
Pai, un combobox simplu sau dropdown (CBS_SIMPLE sau CBS_DROPDOWN) are un copilas de tip Edit, in care e focusul pe care-l cauti.

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 04 Nov 2013, 10:57
by mesajflaviu
Fac cariera pe PreTranslateMessage :))

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 04 Nov 2013, 14:54
by mesajflaviu
Banui ca acces la edit-ul combobox-ului am tot cu GetComboBoxInfo, nu ?

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 04 Nov 2013, 16:23
by mesajflaviu
Da, am gasit tasta "Enter" :biggrin:

Code: Select all

BOOL CTestView::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class

	if(WM_KEYDOWN == pMsg->message && VK_RETURN == pMsg->wParam)
	{
		COMBOBOXINFO cbi = {0};
		cbi.cbSize = sizeof(COMBOBOXINFO);
		BOOL bRet = m_Combo.SendMessage(CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbi);
		if(bRet && pMsg->hwnd == cbi.hwndItem)
		{
			CString sText;
			m_Combo.GetWindowText(sText);
			TRACE("The choosen text is: '%s' and has the index: %d\n", sText, m_Combo.FindString(-1, sText));
		}
	}

	return CFormView::PreTranslateMessage(pMsg);
}
unde m_Combo este de tip CComboBox.

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 04 Nov 2013, 16:35
by mesajflaviu
As avea totusi o intrebare: este OK sa folosesc SendMessage in interiorul PreTranslateMessage ? Lucrez cu VC6, si nu pot folosi GetComboBoxInfo ...

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 05 Nov 2013, 11:01
by Silviu Ardelean
mesajflaviu wrote:As avea totusi o intrebare: este OK sa folosesc SendMessage in interiorul PreTranslateMessage ? Lucrez cu VC6, si nu pot folosi GetComboBoxInfo ...
Folosind SendMessage() care blocheaza coada de mesaje nu e recomandata mai ales in PreTranslateMessage().

Faptul ca lucrezi cu VC6 n-ar trebui sa te afecteze cat timp folosesti un Windows SDK al zilelor noastre si ti-ai defini WINVER adecvat (alte informatii aici). Din documentatia GetComboBoxInfo() inteleg ca aceasta functie e disponibila de la Win2K, deci mai mult decat decent.

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 05 Nov 2013, 11:38
by mesajflaviu
Ma gandeam eu ca nu-i chiar bine sa folosesc SendMessage in PreTranslateMessage ... sa vad ce pot face ...

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 05 Nov 2013, 12:24
by mesajflaviu
Am gasit o solutie:

Code: Select all

BOOL CTestView::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class

	switch(pMsg->message)
	{
		case WM_MOUSEMOVE:
			m_ToolTips.RelayEvent(pMsg);
			break;
	}

	if(WM_KEYDOWN == pMsg->message && VK_RETURN == pMsg->wParam)
	{
		COMBOBOXINFO cbi = {0};
		cbi.cbSize = sizeof(COMBOBOXINFO);
//		BOOL bRet = m_Combo.SendMessage(CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbi);
		BOOL bRet = ::GetComboBoxInfo(m_Combo.m_hWnd, &cbi);	// <-- asa merge :)
		if(bRet && pMsg->hwnd == cbi.hwndItem)
		{
			CString sText;
			m_Combo.GetWindowText(sText);
			TRACE("The choosen text is: '%s' and has the index: %d\n", sText, m_Combo.FindString(-1, sText));
		}
	}

	return CFormView::PreTranslateMessage(pMsg);
}
ciudat, deci asa nu ii place:

Code: Select all

BOOL bRet = m_Combo.GetComboBoxInfo(&cbi);
dar asa da:

Code: Select all

BOOL bRet = ::GetComboBoxInfo(m_Combo.m_hWnd, &cbi);
pana la urma puteam si modifica WINVER-ul ... Multumesc tuturor pentru indrumari !

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 18 Nov 2013, 17:06
by Ovidiu Cucu
Silviu Ardelean wrote:[...]
Folosind SendMessage() care blocheaza coada de mesaje nu e recomandata mai ales in PreTranslateMessage().
[...]
SendMessage are si ea rostul ei si SE recomanda acolo unde trebuie. ;)
Keep an eye open here: viewtopic.php?f=31&t=648


[Later edit]
De altfel, MFC-ul are tone de metode care in spate cheama SendMessage.
Exemplu

Code: Select all

_AFXWIN_INLINE int CComboBox::GetCount() const
	{ ASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETCOUNT, 0, 0); }
_AFXWIN_INLINE int CComboBox::GetCurSel() const
	{ ASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETCURSEL, 0, 0); }
_AFXWIN_INLINE int CComboBox::SetCurSel(int nSelect)
	{ ASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_SETCURSEL, nSelect, 0); }
_AFXWIN_INLINE DWORD CComboBox::GetEditSel() const
	{ ASSERT(::IsWindow(m_hWnd)); return DWORD(::SendMessage(m_hWnd, CB_GETEDITSEL, 0, 0)); }
_AFXWIN_INLINE BOOL CComboBox::LimitText(int nMaxChars)
	{ ASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CB_LIMITTEXT, nMaxChars, 0); }
_AFXWIN_INLINE BOOL CComboBox::SetEditSel(int nStartChar, int nEndChar)
	{ ASSERT(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, CB_SETEDITSEL, 0, MAKELONG(nStartChar, nEndChar)); }
_AFXWIN_INLINE DWORD_PTR CComboBox::GetItemData(int nIndex) const
	{ ASSERT(::IsWindow(m_hWnd)); return ::SendMessage(m_hWnd, CB_GETITEMDATA, nIndex, 0); }
_AFXWIN_INLINE int CComboBox::SetItemData(int nIndex, DWORD_PTR dwItemData)
	{ ASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_SETITEMDATA, nIndex, (LPARAM)dwItemData); }
S.a.m.d. s.a.m.d...
In rest e corect.
Mesajul CB_GETCOMBOBOXINFO cere cel putin Windows XP/Server 2003, pe cand functia ::GetComboBoxInfo e ceva mai veche.

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 18 Nov 2013, 22:26
by Silviu Ardelean
Ovidiu Cucu wrote:
Silviu Ardelean wrote:[...]
Folosind SendMessage() care blocheaza coada de mesaje nu e recomandata mai ales in PreTranslateMessage().
[...]
SendMessage are si ea rostul ei si SE recomanda acolo unde trebuie. ;)
Keep an eye open here: viewtopic.php?f=31&t=648
Desigur. :) Poate ca nu m-am exprimat foarte clar. SendMessage() are sens a fi folosita cand doresti sa-ti continui fluxul doar dupa procesarea mesajului - deci blochezi threadul curent. Altfel, de multe ori, din thread-uri secundare cand nu e nevoie de acuratete maxima si vrem sa notificam GUIul e suficient sa folosim PostMessage() (ex. vrem sa updatam starea unui progress bar control).

Dar in cazul de fata, desi am open eyes, imi scapa de ce ar fi in regula sa o folosesti in PreTranslateMessage().
Eu nu gasesc normal ca in loc de mesajul WM_KEYDOWN venit pe PreTranslateMessage() inainte ca acesta sa ajunga la fereastra destinatie sa fortezi procesarea CB_GETCOMBOBOXINFO in avans.
Ovidiu Cucu wrote: De altfel, MFC-ul are tone de metode care in spate cheama SendMessage.
Exemplu

Code: Select all

_AFXWIN_INLINE int CComboBox::GetCount() const
	{ ASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETCOUNT, 0, 0); }
_AFXWIN_INLINE int CComboBox::GetCurSel() const
	{ ASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, CB_GETCURSEL, 0, 0); }
Categoric! Dar asta, din pacate, nu inseamna ca e ceea mai fericita implementare in spatele controalelor.
Imho, faptul ca foloseste intens SendMessage() in anumite situatii aduce o penalizare semnificativa. De exemplu, in momentul in care populam controale MFC ca cel de lista sau tree si ajung sa aibe un numar foarte mare de elemente de genul zecilor de mii sau chiar mai mult, atunci lucrurile incep sa "gafaie" si timpul ce umplere a controalelor creste exponential, interfata avand de suferit la capitolul "response".

Code: Select all

_AFXCMN_INLINE HTREEITEM CTreeCtrl::InsertItem(_In_ LPTVINSERTSTRUCT lpInsertStruct)
	{ ASSERT(::IsWindow(m_hWnd));  return (HTREEITEM)::SendMessage(m_hWnd, TVM_INSERTITEM, 0, (LPARAM)lpInsertStruct); }
In astfel de situatii folosirea listelor virtuale ca aici sau aici e musai (tehnica ce, in principiu, foloseste un container pentru date si incarca doar datele necesare pentru reprezentare via notificarea LVN_GETDISPINFO).

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 19 Nov 2013, 11:25
by Ovidiu Cucu
Silviu Ardelean wrote:[...]
Categoric! Dar asta, din pacate, nu inseamna ca e ceea mai fericita implementare in spatele controalelor.
Imho, faptul ca foloseste intens SendMessage() in anumite situatii aduce o penalizare semnificativa. De exemplu, in momentul in care populam controale MFC ca cel de lista sau tree si ajung sa aibe un numar foarte mare de elemente de genul zecilor de mii sau chiar mai mult, atunci lucrurile incep sa "gafaie" si timpul ce umplere a controalelor creste exponential, interfata avand de suferit la capitolul "response".
[...]
In astfel de situatii folosirea listelor virtuale ca...
[...]
Desigur, vom cere celor de la MS sa-si bage mintile-n cap si sa-l marcheze pe SendMessage ca "deprecated". In plus, ar cam fi timpul sa afle si ei ca moare omenirea de dorul unui combobox virtual. :D

Acuma serios si revenind incet-incet on-topic.

Am zis si altadata ca PreTranslateMessage nu-i locul unde "tot ce zboara se mananca".
Insa, pentru ce vrea Flaviu si asa cum a pus conditiile, e destul de OK si e pe departe de a "aduce o penalizare semnificativa".
Cu remarca pe care am facut-o in postul anterior, poate folosi atat ::GetComboBoxInfo (sau CComboBox::GetComboBoxInfo) cat si SendMessage cu CB_GETCOMBOBOXINFO.

IN NICI UN CAZ NU PostMessage(CB_GETCOMBOBOXINFO, 0, (LPARAM)&cbi).

De ce oare?
Simplu, pentru ca, precum bine (ar trebui sa) stim, functia PostMessage e asincrona, adica introarce imediat neasteptand ca acel mesaj sa fie procesat. Acuma, pentru ca in LPARAM i-am bagat un parametru de OUT, in mod sigur ce bagam aia scoatem. Deci n-am facut nimic.

M-am exprimat destul de clar sau cerem la MS si-o notificare gen CBN_GETCOMBOBOXINFODONE ca sa stie si parintele cand ce si cum s-a procesat. :)

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Posted: 19 Nov 2013, 11:33
by Silviu Ardelean
Ovidiu Cucu wrote:In plus, ar cam fi timpul sa afle si ei ca moare omenirea de dorul unui combobox virtual. :D
Nu-ti poti dori ceva mai mult decat un combobox virtual! :biggrin: