problem mit LVN_ITEMCHANGING / LVN_ITEMCHANGED in win32 anwendung



  • ich bin gerade dabei eine win32 anwendung mit einer liste zu erstellen.
    bzw. ist diese liste schon mit daten gefüllt. jetzt wollte ich gern diese Liste editierbar machen.
    was auch schon annähernd klapt.
    Momentan hänge ich in der Callback funktion meines programmes bei LVN_ITEMCHANGING / LVN_ITEMCHANGED
    da hier ja der geeignete ort wäre die zeile & spalte abzufangen auf die geklickt wurde. an die zeile
    komm ich die wird immer korreckt angezeigt aber die spalte ist in LVN_ITEMCHANGING / LVN_ITEMCHANGED
    immer null. erst wenn ich versuche unter LVN_ITEMACTIVATE an die zeile & spalte zu kommen hat die
    spalte die korreckte nr. Dort ist aber schon zu spät da ja dann bereits das Editfeld schon erstellt ist.
    weis jemand wo der fehler liegt

    BOOL CALLBACK MainProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
    {
    
    	switch(message)
    	{
    	.....
    
    		case WM_NOTIFY:
    		{
    			switch(LOWORD(wParam))
    			{
    				case IDC_LIST:
    					{
    						switch(((LPNMHDR)lParam)->code)
    						{
    							case LVN_ITEMCHANGING:
    								{
    									NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)((LPNMHDR)lParam);
    									m_ptItemEditting.x = pNMListView->iItem;
    									m_ptItemEditting.y = pNMListView->iSubItem;
    									CString f;
    									f.Format("Item: %i\n"
    										"SubItem: %i\n",
    										m_ptItemEditting.x, 
    										m_ptItemEditting.y);
    
    									MessageBox(0,f,"Changing",0);
    
    								}
    							break;//LVN_ITEMCHANGING
    
    							case LVN_ITEMCHANGED:
    								{
    
    								}
    							break;//LVN_ITEMCHANGED
    							case LVN_ITEMACTIVATE:
    								{
    								}
    							break;//LVN_ITEMACTIVATE:
    
    							default:
    							  return bTorF;
    							break;
    
    						}//(((LPNMHDR)lParam)->code)
    
    					}
    				break;//IDC_LIST
    				default:
    				  return bTorF;
    				break;
    			}//WM_NOTIFY(LOWORD(wParam))
    
    		}//WM_NOTIFY
    		break;		
    
    		default:
    		  return bTorF;
    		break;
       }
    
    return bTorF;
    }
    

  • Mod

    1. Eine MessageBox hier zu verwenden ist tödlich. Die LVN_ITEMCHAGING wird für ales gesendet was sich ändert. D.h. es kann sehr wohl sein, dass Du diese Nachricht für ein Item öfters bekommst. Du musst selber sehen was hier als Änderung gemeldet wird.

    2. Wenn Du diese Items editieren willst, warum verwendest Du nicht LVN_BEGINLABELEDIT?



  • Eine MessageBox hier zu verwenden ist tödlich. Die LVN_ITEMCHAGING wird für ales gesendet was sich ändert. D.h. es kann sehr wohl sein, dass Du diese Nachricht für ein Item öfters bekommst

    die ist da nur zum test weil ich sehn wollte was subitem für einen wert hat. auch stimmt das sie öffters aufgeht nur ist subitem immer 0.

    ich verwende LVN_BEGINLABELEDIT nur ist ja dort die Editbox schon aktiv dort hole ich mir zb das handel auf die Editbox. und bei LVN_BEGINLABELEDIT passiert eben genau das gleiche, dort ist subitem auch wieder null. bisher bin ich nur bei NM_CLICK / NM_DBLCLK bzw. LVN_ITEMACTIVATE an das richtige subitem gekomment.

    ich kapier halt nicht wieso das bei LVN_ITEMCHANGING / LVN_ITEMCHANGED in einer win32 anwendung nicht funzt. sollte doch normalerweise gehn denn bei einer Dialoganwendung komm ich bei LVN_ITEMCHANGING / LVN_ITEMCHANGED bzw. bei der Funktion die dies repäsentiert ja auch über folgenden code drann.

    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    

    werd mich wohl jetzt darauf beschränken das subitem bei NM_CLICK zu holen.

    das nächste was jetzt ist, ich hab alle daten die ich brauche um das Editfeld zu gewegen. das handle auf die Editbox (das ist auch korrekt ich bekomme den text aus dem Editfeld)
    ich besorg mir über folgenden code die rechteckkorrdinaten der Zeile & Spalte auf die ich geklickt hab.

    ListView_GetSubItemRect(hList, m_ptItemEditting.x, m_ptItemEditting.y, LVIR_LABEL, &m_rcItemRect);
    

    auch hier stimmen dann wieder die Rechteckdaten nur läst sich das Editfeld nicht vom Platz bewegen, das klept wie angenagelt immer oben links in der Liste über der ersten Spalte.

    ich versuch das die ganze zeit unter LVN_BEGINLABELEDIT mit SetWindowPos bzw. MoveWindow zu bewegen aber es will nicht

    SetWindowPos(m_hWndEdit,HWND_TOP,m_rcItemRect.top,m_rcItemRect.left,(m_rcItemRect.right-m_rcItemRect.left),(m_rcItemRect.bottom-m_rcItemRect.top),SWP_SHOWWINDOW);
    
    MoveWindow(m_hWndEdit,m_rcItemRect.top,m_rcItemRect.left,(m_rcItemRect.right-m_rcItemRect.left),(m_rcItemRect.bottom-m_rcItemRect.top),TRUE);
    

  • Mod

    Du kannst nicht das bestehende Edit Control verwenden. Wenn Du dieses verschiebst gibt es massenweise Redrawing Probleme. Erzeuge Deine eigene Edit Box.

    BTW: Für diesen ganzen Bereich gibt es unter www.codeproject.com massenweise existierenden Code!

    Um das Item zu bestimmen das editiert werden soll gehe ich in etwa so vor:

    void CDlgSchedProjectPP2_Properties::OnLvnBeginlabeleditLcData(NMHDR *, LRESULT *pResult)
    {
    	// Prevent change, the following routine will do the rest
    	*pResult = TRUE;
    
    	int iRow=0, iCol=0;
             // Check if activated by keyboard (F2)
    	const MSG& msg=  *AfxGetCurrentMessage();
    	if (msg.message>=WM_KEYFIRST && msg.message<=WM_KEYLAST)
    		iRow = m_lcData.GetNextItem(-1,LVNI_ALL|LVNI_FOCUSED);	
    	else
    	{
    		LVHITTESTINFO ht;
    		ht.pt = msg.pt;
    
    		m_lcData.ScreenToClient(&ht.pt);
    		m_lcData.SubItemHitTest(&ht);
    
    		iRow = ht.iItem;
    		iCol = ht.iSubItem;
    	}
    
    	EditItem(iRow,iCol);
    }
    

    EditItem mach dann bei mir den Rest. Entsprechendes Edit Control anwerfen etc.
    Wie Du siehst umgehe ich die Standardbehandlung weil ich pResult auf TRUE setze!



  • werd mir das mit dem Hittest mal genauer anschauen, hab das bislang immer anderst bewerkstellingt.

    Hab da aber gleich noch ein anderes problem gefunden. bislang hab ich in Dialoganwendungen das Editfeld immer so erstellt

    CEdit *m_pWndEdit = new CEdit();
    
    if (m_pWndEdit->GetSafeHwnd() != NULL)
    	m_pWndEdit->DestroyWindow();
    
    m_pWndEdit->Create(ES_AUTOHSCROLL | ES_NOHIDESEL | WS_CHILD | WS_BORDER | FMT, CRect(0, 0, 1, 1), [b]this[/b], 100000);
    

    in der Win32 anwendung schmiert mir der Dialog immer ab wenn es daran geht das Editfeld zu erstellen, weil einmal dort kein this zeiger existiert, mit CWnd = NULL das Editfeld nicht erstellt werden kann und ich nicht weis wie ich an ein gültiges CWnd* object komme. den GetParent gibt ja in Win32 ein HWND zurück und solche versuche es zu casten schlugen fehl.

    CWnd *pWnd = (CWnd*)GetParent(hDlg);
    
    CWnd *pWnd = (CWnd*)GetWindow(hDlg,GW_OWNER);
    

    alle anderen werte sind vorhanden, das es korreckt erstellt werden könnte.


  • Mod

    Aber Du hast doch das Handle des Parent Windows. Du behandelst das gerade doch in der ensprechenden DialogProc. Also hast Du auch das Handle entweder des ListCtrls oder des Dialoges. Beide würden sich als Parent für das Edit Control anbieten. Ich verwende immer das List Ctrl.



  • Beide würden sich als Parent für das Edit Control anbieten. Ich verwende immer das List Ctrl.

    ja eben das dachte ich auch das der cast funzt leider nein, ich hab beide handle probiert, vom dialog bzw. von der Liste. das einzigste was sich geändert hat ist das bei GetParent / GetWindowLong keine Assert meldung sondern ne Debug meldung kam.

    CWnd *pWnd = (CWnd*)GetParent(hList) ;
    CWnd *pWnd = (CWnd*)GetWindow(hList,GW_OWNER);
    CWnd *pWnd = (CWnd*)GetWindowLong(hList,GWL_HWNDPARENT) ;
    
    CWnd *pWnd = static_cast<CWnd*>((CWnd*)GetParent(hList));
    CWnd *pWnd = static_cast<CWnd*>((CWnd*)GetWindow(hList,GW_OWNER));
    CWnd *pWnd = static_cast<CWnd*>((CWnd*)GetWindowLong(hList,GWL_HWNDPARENT)) ;
    

Log in to reply