CListCtrl -> Felder Editieren und Übernhmen



  • Hi

    ich hab lange gesucht jedoch nicht darüber gefunden wie ich die einzelnen Felder einer CListCtrl editieren kann.

    Ich hab eine List welche in einer CListCtrl angezeigt wird. Jedoch hätte ich gerne das ich die einzelnen Felder editieren kann und das alle die geändert wurden auch übernehme und speicher kann.

    Weiss das zufällig jemand wie das geht ??

    Danke,
    Indian



  • Mal ein kurzer Beitrag dazu:

    1. Mach dir ne Basisklasse für das ListCtrl, welche von CListCtrl erbt,
    damit ersparst du dir, es bei jeder anderen ListCtrl immer wieder vollständig
    implementieren zu müssen...

    Header:

    class LBasisListCtrl : public CListCtrl
    {
    // Konstruktion
    public:
    	LBasisListCtrl();
    public:
    	CEdit* EditSubLabel(int nItem, int nCol);
    	virtual ~LBasisListCtrl();
    	virtual void SetSubItemText(int item, int subitem, CString text) =0;
    	// Generierte Nachrichtenzuordnungsfunktionen
    protected:
    	//{{AFX_MSG(LBasisListCtrl)
    	afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
    	afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
    	//}}AFX_MSG
    	DECLARE_MESSAGE_MAP()
    };
    

    cpp:

    CEdit* LBasisListCtrl::EditSubLabel(int nItem, int nCol)
    {
    	// The returned pointer should not be saved
    
    	// Make sure that the item is visible
    	if( !EnsureVisible( nItem, TRUE ) ) return NULL;
    
    	// Make sure that nCol is valid
    	CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
    	int nColumnCount = pHeader->GetItemCount();
    	if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
    		return NULL;
    
    	// Get the column offset
    	int offset = 0;
    	for( int i = 0; i < nCol; i++ )
    		offset += GetColumnWidth( i );
    
    	CRect rect;
    	GetItemRect( nItem, &rect, LVIR_BOUNDS );
    
    	// Now scroll if we need to expose the column
    	CRect rcClient;
    	GetClientRect( &rcClient );
    	if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
    	{
    		CSize size;
    		size.cx = offset + rect.left;
    		size.cy = 0;
    		Scroll( size );
    		rect.left -= size.cx;
    	}
    
    	// Get Column alignment
    	LV_COLUMN lvcol;
    	lvcol.mask = LVCF_FMT;
    	GetColumn( nCol, &lvcol );
    	DWORD dwStyle ;
    	if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
    		dwStyle = ES_LEFT;
    	else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
    		dwStyle = ES_RIGHT;
    	else dwStyle = ES_CENTER;
    
    	rect.left += offset+4;
    	rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
    	if( rect.right > rcClient.right) rect.right = rcClient.right;
    
    	dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;
    	CEdit *pEdit = new CInPlaceEdit(nItem, nCol, GetItemText( nItem, nCol ));
    	pEdit->Create( dwStyle, rect, this, IDC_EDIT );
    
    	return pEdit;
    }
    
    void LBasisListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
    {
    	if( GetFocus() != this ) SetFocus();
    	CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
    }
    
    void LBasisListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
    {
    	if( GetFocus() != this ) SetFocus();
    	CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
    }
    

    Hier dann die konkrete Implementierung, die SetSubItemText wird hier ausformuliert:

    Header:

    class LInc : public LBasisListCtrl
    {
    // Konstruktion
    public:
    	LInc();
    	virtual void SetSubItemText(int item, int subitem, CString text);
    // Attribute
    public:
    
    // Operationen
    public:
    
    // Überschreibungen
    	// Vom Klassen-Assistenten generierte virtuelle Funktionsüberschreibungen
    	//{{AFX_VIRTUAL(LInc)
    	//}}AFX_VIRTUAL
    
    // Implementierung
    public:
    	void Init();
    	virtual ~LInc();
    
    	// Generierte Nachrichtenzuordnungsfunktionen
    protected:
    	//{{AFX_MSG(LInc)
    	afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult);
    	afx_msg void OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult);
    	//}}AFX_MSG
    
    	DECLARE_MESSAGE_MAP()
    };
    

    cpp:

    void LInc::OnClick(NMHDR* pNMHDR, LRESULT* pResult) 
    {
    	LPNMITEMACTIVATE    lpItem = (LPNMITEMACTIVATE) pNMHDR;
    	if(lpItem->iItem > -1 && lpItem->iSubItem >-1)
    	{
    		EditSubLabel( lpItem->iItem, lpItem->iSubItem );
    	}
    	*pResult = 0;
    }
    
    void LInc::SetSubItemText(int item, int subitem, CString text)
    {
    	*/Text speichern*/
      	SetItemText(item,subitem,text);
    }
    
    void LInc::OnEndlabeledit(NMHDR* pNMHDR, LRESULT* pResult) 
    {
     	LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR;
     	LV_ITEM	*plvItem = &plvDispInfo->item;
     	if (plvItem->pszText != NULL)
     	{
    		SetSubItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
     	}
     	*pResult = FALSE;
    }
    

    Jetzt brauchen wir noch eine Klasse von CEdit abzuleiten, die weiss wo sie gerade
    editiert etc.

    Header:

    class CInPlaceEdit : public CEdit
    {
    // Konstruktion
    public:
    	CInPlaceEdit(int iItem, int iSubItem, CString sInitText);
    // Attributes
    public:
    // Operations
    public:
    
    // Overrides
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CInPlaceEdit)
    	public:
    	virtual BOOL PreTranslateMessage(MSG* pMsg);
    	//}}AFX_VIRTUAL
    // Implementation
    public:
    	virtual ~CInPlaceEdit();
    
    	// Generated message map functions
    protected:
    	//{{AFX_MSG(CInPlaceEdit)
    	afx_msg void OnKillFocus(CWnd* pNewWnd);
    	afx_msg void OnNcDestroy();
    	afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
    	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    	//}}AFX_MSG
    
    	DECLARE_MESSAGE_MAP()
    private:
    	int m_iItem;
    	int m_iSubItem;
    	CString m_sInitText;
    	BOOL    m_bESC;	 	// To indicate whether ESC key was pressed
    };
    

    cpp:

    CInPlaceEdit::CInPlaceEdit(int iItem, int iSubItem, CString sInitText)
    :m_sInitText( sInitText )
    {
    	m_iItem = iItem;
    	m_iSubItem = iSubItem;
    	m_bESC = FALSE;
    }
    
    CInPlaceEdit::~CInPlaceEdit()
    {
    }
    
    BEGIN_MESSAGE_MAP(CInPlaceEdit, CEdit)
    	//{{AFX_MSG_MAP(CInPlaceEdit)
    	ON_WM_KILLFOCUS()
    	ON_WM_NCDESTROY()
    	ON_WM_CHAR()
    	ON_WM_CREATE()
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CInPlaceEdit message handlers
    
    BOOL CInPlaceEdit::PreTranslateMessage(MSG* pMsg)
    {
    	if( pMsg->message == WM_KEYDOWN )
    	{
    		if(pMsg->wParam == VK_RETURN
    				|| pMsg->wParam == VK_DELETE
    				|| pMsg->wParam == VK_ESCAPE
    				|| GetKeyState( VK_CONTROL)
    				)
    		{
    			::TranslateMessage(pMsg);
    			::DispatchMessage(pMsg);
    			return TRUE;		    	// DO NOT process further
    		}
    	}
    
    	return CEdit::PreTranslateMessage(pMsg);
    }
    
    void CInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
    {
    	CEdit::OnKillFocus(pNewWnd);
    
    	CString str;
    	GetWindowText(str);
    
    	// Send Notification to parent of ListView ctrl
    	LV_DISPINFO dispinfo;
    	dispinfo.hdr.hwndFrom = GetParent()->m_hWnd;
    	dispinfo.hdr.idFrom = GetDlgCtrlID();
    	dispinfo.hdr.code = LVN_ENDLABELEDIT;
    
    	dispinfo.item.mask = LVIF_TEXT;
    	dispinfo.item.iItem = m_iItem;
    	dispinfo.item.iSubItem = m_iSubItem;
    	dispinfo.item.pszText = m_bESC ? NULL : LPTSTR((LPCTSTR)str);
    	dispinfo.item.cchTextMax = str.GetLength();
    
    	GetParent()->GetParent()->SendMessage( WM_NOTIFY, GetParent()->GetDlgCtrlID(), 
    					(LPARAM)&dispinfo );
    
    	DestroyWindow();
    }
    
    void CInPlaceEdit::OnNcDestroy()
    {
    	CEdit::OnNcDestroy();
    
    	delete this;
    }
    
    void CInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
    {
    	if( nChar == VK_ESCAPE || nChar == VK_RETURN)
    	{
    		if( nChar == VK_ESCAPE )
    			m_bESC = TRUE;
    		GetParent()->SetFocus();
    		return;
    	}
    
    	CEdit::OnChar(nChar, nRepCnt, nFlags);
    
    	// Resize edit control if needed
    
    	// Get text extent
    	CString str;
    
    	GetWindowText( str );
    	CWindowDC dc(this);
    	CFont *pFont = GetParent()->GetFont();
    	CFont *pFontDC = dc.SelectObject( pFont );
    	CSize size = dc.GetTextExtent( str );
    	dc.SelectObject( pFontDC );
    	size.cx += 5;			   	// add some extra buffer
    
    	// Get client rect
    	CRect rect, parentrect;
    	GetClientRect( &rect );
    	GetParent()->GetClientRect( &parentrect );
    
    	// Transform rect to parent coordinates
    	ClientToScreen( &rect );
    	GetParent()->ScreenToClient( &rect );
    
    	// Check whether control needs to be resized
    	// and whether there is space to grow
    	if( size.cx > rect.Width() )
    	{
    		if( size.cx + rect.left < parentrect.right )
    			rect.right = rect.left + size.cx;
    		else
    			rect.right = parentrect.right;
    		MoveWindow( &rect );
    	}
    }
    
    int CInPlaceEdit::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CEdit::OnCreate(lpCreateStruct) == -1)
    		return -1;
    
    	// Set the proper font
    	CFont* font = GetParent()->GetFont();
    	SetFont(font);
    
    	SetWindowText( m_sInitText );
    	SetFocus();
    	SetSel( 0, -1 );
    	return 0;
    }
    

    Fertig 😃

    Devil



  • ich bekommne Fehlermeldung das

    IDC_EDIT nicht deklariert ist

    c:\Dokumente und Einstellungen\Mother\Eigene Dateien\Visual Studio-Projekte\Kasse\Kasse\SortListCtrl.cpp(467): error C2065: 'IDC_EDIT' : nichtdeklarierter Bezeichner



  • Hi,

    ich weis zwar nicht viel, aber IDC_EDIT ist ein Steuerelement 😃

    Auch als Eingabefeld getarnt. Baue ein Eingabefeld mit dem Namen IDC_EDIT
    ein, und schaue was passiert.

    asmodia



  • asmodia schrieb:

    Hi,

    ich weis zwar nicht viel, aber IDC_EDIT ist ein Steuerelement 😃

    Auch als Eingabefeld getarnt. Baue ein Eingabefeld mit dem Namen IDC_EDIT
    ein, und schaue was passiert.

    asmodia

    Stimmt, habe vergessen, das man in den Dialog auch ein Editfeld einbauen
    muss, welches dann auf randlos gestellt wird, und der Haken bei Sichtbar sollte raus.

    Devil



  • hi

    also mir ist war das mit ner eigenen klasse für clistctrl zu arg.
    ich habe mir nen schönen dialog gebaut - dort alle items/subitems rein
    dann kann man dort schön ändern und bei ok werden alle member des dlgs wieder
    in die liste geschrieben.

    sentinel



  • Ich hab ein neues EditFeld (Steuerelement) erzeugt mit dem Namen IDC_EDIT. Wird leider trotzdem nicht erkannt. Das Kompilieren hat funktioniert als ich die Klasse vom Dialog eingebundenn habe jedoch funktioniert das editieren immer noch nicht. Nur die erste Spalte wie sonst auch immer.

    Kann mir jemand erklären wie ich Funktionen nutze. Ist bischen schwer für mich hier einzuarbeiten



  • an devil81

    fehlt bei der Implementierung nicht eine Implementierung welches die notwendige Funktion aufruft, damit man die Felder editieren kann ?? Eine MessageMap Einbindung ? 😕

    ich kann immer nur noch die erste spalte default mässig editieren, alle anderen sind immer noch nicht editierbar. Ausserdem kann ich denn wert in der ersten Spalten nach dem editieren ja nicht übernehmen. Nachdem ich editierthabe und "ENTER" drücke müsste doch der neue wert übernommen werden oder ?



  • hi

    leider wird das editierte Feld mit dem editiertem Wert nicht übernommen. Handler fehlten noch

    ON_WM_LBUTTONDBLCLK()
    ON_NOTIFY_REFLECT(LVN_ENDLABELEDIT, OnEndLabelEdit)



  • hi devil81

    noch ne frage. wie kann ich festlegen welche spalte editiert werden kann und welche nicht ???


Anmelden zum Antworten