Cum "prind" VK_RETURN in combobox in PreTranslateMessage?

Intrebari legate de programarea cu biblioteci precum MFC, ATL, WTL si GDI+.
Post Reply
mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Cum "prind" VK_RETURN in combobox in PreTranslateMessage?

Post by mesajflaviu » 01 Nov 2013, 16:54

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 ?



User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by Ovidiu Cucu » 01 Nov 2013, 18:05

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.

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by mesajflaviu » 04 Nov 2013, 10:57

Fac cariera pe PreTranslateMessage :))

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by mesajflaviu » 04 Nov 2013, 14:54

Banui ca acces la edit-ul combobox-ului am tot cu GetComboBoxInfo, nu ?

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by mesajflaviu » 04 Nov 2013, 16:23

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.

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by mesajflaviu » 04 Nov 2013, 16:35

As avea totusi o intrebare: este OK sa folosesc SendMessage in interiorul PreTranslateMessage ? Lucrez cu VC6, si nu pot folosi GetComboBoxInfo ...

User avatar
Silviu Ardelean
Senior
Senior
Posts: 1175
Joined: 12 Jul 2007, 09:22
Judet: Timiş
Location: Timisoara
Contact:

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by Silviu Ardelean » 05 Nov 2013, 11:01

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.

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by mesajflaviu » 05 Nov 2013, 11:38

Ma gandeam eu ca nu-i chiar bine sa folosesc SendMessage in PreTranslateMessage ... sa vad ce pot face ...

mesajflaviu
Membru++
Membru++
Posts: 688
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by mesajflaviu » 05 Nov 2013, 12:24

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 !

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by Ovidiu Cucu » 18 Nov 2013, 17:06

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.

User avatar
Silviu Ardelean
Senior
Senior
Posts: 1175
Joined: 12 Jul 2007, 09:22
Judet: Timiş
Location: Timisoara
Contact:

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by Silviu Ardelean » 18 Nov 2013, 22:26

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).

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by Ovidiu Cucu » 19 Nov 2013, 11:25

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. :)

User avatar
Silviu Ardelean
Senior
Senior
Posts: 1175
Joined: 12 Jul 2007, 09:22
Judet: Timiş
Location: Timisoara
Contact:

Re: Cum "prind" VK_RETURN in combobox in PreTranslateMessage

Post by Silviu Ardelean » 19 Nov 2013, 11:33

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:

Post Reply