Textfarbe einer Combobox ändern



  • Moin!
    Ich mal wieder... 😉

    Ich möchte, dass meine Comboboxen so aussehen wie schreibgeschützte CEdits, wenn sie deaktiviert sind (weil man das besser lesen kann).
    Ich habe meine eigene Klasse für Comboboxen und habe genauso wie in einem bei Codeproject gefundenen Projekt die Farbänderung eingebaut.
    http://www.codeproject.com/miscctrl/colorcontols.asp

    Das funktioniert aber nicht.

    Wenn in der Messagemap
    ON_WM_CTLCOLOR()
    steht, dann geht er gar nicht in die Funktion.
    Schreibe ich
    ON_WM_CTLCOLOR_REFLECT()
    dann stürzt er ab. 😞

    Hier ist noch die Funktion an sich:

    HBRUSH CAdCbx::CtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
    {
    	HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor); // <--- Absturz
    	if ((!IsWindowEnabled()) && (nCtlColor == CTLCOLOR_EDIT))
    	{
    		pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
    		pDC->SetBkColor(::GetSysColor(COLOR_3DFACE));
    	}
    	return hbr;
    }
    

    Das ist die Funktion, wo es dann endgültig knallt.

    HBRUSH CWnd::OnCtlColor(CDC*, CWnd* pWnd, UINT)
    {
    	ASSERT(pWnd != NULL && pWnd->m_hWnd != NULL);
    	LRESULT lResult;
    	if (pWnd->SendChildNotifyLastMsg(&lResult))
    		return (HBRUSH)lResult;     // eat it
    	return (HBRUSH)Default();
    }
    

    Was habe ich falsch gemacht? 😕



  • hallo,
    im ersten

    HBRUSH CAdCbx::CtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
    {
        HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); // CDialog müste eigentlich hin
        if ((!IsWindowEnabled()) && (nCtlColor == CTLCOLOR_EDIT))
        {
            pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
            pDC->SetBkColor(::GetSysColor(COLOR_3DFACE));
        }
        return hbr;
    }
    

    unten wie ich nicht so recht.

    MFG TaccoGo



  • Ne, CDialog ist da völlig falsch - das ist eine CComboBox Klasse (zu erkennen am Cbx im Namen)

    Aber mittlerweile überlege ich echt ob ich das nicht doch in jeden Formview einbaue...

    Aber etwa 100 Mal den selben Code, nur aus Unverständnis? Das gefällt mir nicht. 😞



  • hast du ein Dialog anwendung oder was anderes

    ich habe ein dialog und habe keine klasse für die combobox

    HBRUSH COberflche_alkDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) //COberflche_alkDlg ist mein dlg
    {
    	HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
    	// TODO: Attribute des Gerätekontexts hier ändern
    
            if (pWnd->GetDlgCtrlID()== IDC_STATIC22) // um beim ausgabefeld die farben zu ändern
    		{     
    		//	HBRUSH f=CreateSolidBrush(RGB(0,0,0));
    			pDC->SetTextColor(RGB(255,0,0));
    		//	pDC->SetBkColor(RGB(0,0,0));//TRANSPARENT
    		}
    		if (pWnd->GetDlgCtrlID()== IDC_Ausgabe) // um beim ausgabefeld die farben zu ändern
    		{     
    
    			pDC->SetTextColor(RGB(0,255,0));
    			pDC->SetBkColor(RGB(0,0,0));//TRANSPARENT
    		//	pDC->SetBkMode(TRANSPARENT);         
                hbr = (HBRUSH)blak_brush;            // Setzt die Farbe für den Hintergrund     
    		} 
    
    		if (pWnd->GetDlgCtrlID()== IDC_COMBO2||pWnd->GetDlgCtrlID()== IDC_COMBO1||pWnd->GetDlgCtrlID()== IDC_annoJustify)
    		{     
    
    			pDC->SetTextColor(RGB(0,0,0));
    	//		pDC->SetBkColor(RGB(255,255,255));//TRANSPARENT
    			pDC->SetBkMode(TRANSPARENT); 
    		//	SetDCBrushColor((HDC*)pDC,RGB(255,0,0));
    
                hbr = (HBRUSH)white_brush; // Setzt die Farbe für den Hintergrund     
    
    		} 
    
    	return hbr;
    }
    

    das klapt
    MFG TaccoGo



  • Ich habe eine SDI Anwendung mit Formviews. Das werden irgendwann mal etwa 80 Stück sein, deswegen möchte ich das doch lieber zentral irgendwo machen. 🙂

    Diese Formviews haben alle eine gemeinsame Basisklasse die von CFormView abgeleitet ist. Mein Versuch, die Farben dort zu ändern ist bisher nicht erfolgreich, der Thread dazu ist etwas weiter unten zu finden.

    Also habe ich den Ansatz gestartet, die Farbe direkt in der Controlklasse zu ändern. Ich habe ja schon für fast alle Controls eine eigene. 😃
    Da stürzt er aber immer beim Aufruf der Basisklasse ab, egal ob Combobox oder Edit (mehr habe ich noch nicht getestet).
    Die Behandlung durch die Basisklasse möchte ich aber eigentlich nicht weglassen, da ich sonst deren Arbeit auch machen muss bzw. den Code davon bei mir reinkopieren - ist doch auch nicht Sinn der Sache, oder?

    So wie du das machst, direkt im Dialog / Formview, habe ich auch schon eingebaut, das funktioniert an der Stelle auch.



  • Servus,

    sage mal warum machst du das nicht ein bisschen einfacher als jede ComboBox mit einer anderen Schrift zu versehen.

    Habe hier etwas nettes:

    ReadOnlyComboBox.cpp

    // ReadOnlyComboBox.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "ReadOnlyComboBox.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CReadOnlyComboBox
    
    CReadOnlyComboBox::CReadOnlyComboBox()
    {
    }
    
    CReadOnlyComboBox::~CReadOnlyComboBox()
    {
    }
    
    BEGIN_MESSAGE_MAP(CReadOnlyComboBox, CComboBox)
    	//{{AFX_MSG_MAP(CReadOnlyComboBox)
    	ON_WM_ENABLE()
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CReadOnlyComboBox message handlers
    
    void CReadOnlyComboBox::OnEnable(BOOL bEnable) 
    {
    	CComboBox::OnEnable(bEnable);
    
    	CEdit*	pEdit = (CEdit*)GetWindow(GW_CHILD);
    	pEdit->EnableWindow(TRUE);
    	pEdit->SetReadOnly(!bEnable);
    }
    

    ReadOnlyComboBox.h

    #pragma once
    // ReadOnlyComboBox.h : header file
    //
    
    /////////////////////////////////////////////////////////////////////////////
    // CReadOnlyComboBox window
    
    class CReadOnlyComboBox : public CComboBox
    {
    // Construction
    public:
    	CReadOnlyComboBox();
    
    // Implementation
    public:
    	virtual ~CReadOnlyComboBox();
    
    protected:
    	afx_msg void OnEnable(BOOL bEnable);
    	DECLARE_MESSAGE_MAP()
    };
    
    /////////////////////////////////////////////////////////////////////////////
    

    Die beiden bindest du in dein Projekt ein, gibst der ComboBox eine Control-Membervariable. In der *.h in der die Var angelegt wird machst du noch ein "#include ReadOnly...h" und setzt für deine Var die Klasse "CReadOnlyComboBox", anstatt "CComboBox". Wenn du jetzt die ComboBox auf Disable = true setzt erhälst du ein schönes ReadOnly Control. 😉

    *winke*
    Hellsgore



  • Super Idee!

    Das baue ich gleich mal in meine Klasse rüber. 🙂



  • also wen du das wirklich nur auf ReadOnly haben woltest dan brauchst du doch nur eine membervariable von deiner combobox und dan m_combo.EnableWindow(TRUE);
    und alles ist fertig.

    MFG TaccoGo



  • Ne eben nicht.

    Er wollte eine Art Edit.ReadOnly haben. d.h. Grauer Hintgrund und schwarze Schrift. Setzt du bei einer ComboBox Enabled auf False, dann wird der Hintergrund Grau und die Schrift Hellgrau -> Schlecht zu erkennen. Also muss man das ganze umgehen und der ComboBox sagen das es sich auf ReadOnly setzen soll.

    *winke*
    Hellsgore



  • So, ich habe das rübergebaut, aber der Cast schlägt fehl. 😞

    Zuerst hatte ich es 1:1 kopiert. Da gab es einen deftigen Absturz.
    Dann habe ich es so gemacht:

    void CAdCbx::OnEnable(BOOL bEnable) 
    { 
        CComboBox::OnEnable(bEnable); 
    
        CEdit* pEdit = dynamic_cast<CEdit*>(GetWindow(GW_CHILD)); 
    	if (pEdit)
    	{
    		pEdit->EnableWindow(TRUE); 
    		pEdit->SetReadOnly(!bEnable); 
    	}
    }
    

    Nun stürzt er nicht mehr ab (ist ja klar, das verhindert die if), aber das SetReadOnly funktioniert natürlich auch nicht. 😞

    Hast du eine Idee, warum das nicht geht?



  • Schei&%&e mit Erdbeeren,

    du verwendest ein SDI oder? Dann muss ich mal ein bisschen rumtesten *g*. Hatte einfach eine Dialog basierende Anwendung gebastelt...

    Hellsgore



  • Das ist nett von dir. 🙂

    Ja, ich habe eine SDI mit FormViews. Ich teste mal, ob der Trick auch bei Edits funktioniert (oder auch nicht), dann muss ich nicht alles umschmeißen, was ich schon habe. 🙂

    Edit: Jawoll! Bei Edits funktioniert es. 😃



  • Ja klar bei Edits funzt das auf jedenfall. Die haben ja auch eine Eigenschaft mit ReadOnly.

    So, ich bin davon ausgegangen das er beim GetWindow(GW_CHILD) hängen geblieben ist. Darum habe ich versucht die ComboBox zu finden. Es ist zwar im Prinzip Blödsinn in einer Klasse von einem Control das eigene Control zu suchen aber es sollte eigentlich funtkionieren. Das ist eine Quick&Dirty (Aber ziemlich Dirty *g*) Lösung.

    ReadOnlyComboBox.cpp

    BOOL CALLBACK CReadOnlyComboBox::EnumChildProc(HWND hwnd,LPARAM lParam)
    {
        CWnd* pcWnd = FromHandle(hwnd);
        CString strClassName;
        TCHAR cClassName[255];
        memset(cClassName, 0, sizeof(cClassName));
    
        //Klassenname holen
        GetClassName(hwnd, cClassName, sizeof(cClassName));
        strClassName = cClassName;
    
        //Wenn 1 dann setze diabled
        if(lParam == 0)
        {
            //Wenn Edit dann setze Readonly
    		pcWnd->EnableWindow(TRUE);
            if(strClassName == "Edit")
            {
                CEdit* pEdit = static_cast<CEdit*>(pcWnd);
                pEdit->SetReadOnly(TRUE);
                return FALSE;
            }
    
        }
        //Wenn was anderes als 1 dann setze enabled
        else
        {
    		pcWnd->EnableWindow(TRUE);
            if(strClassName == "Edit")
            {
                CEdit* pEdit = static_cast<CEdit*>(pcWnd);
                pEdit->SetReadOnly(FALSE);
                return FALSE;
            }
    
        }   
        return TRUE;
    }
    
    void CReadOnlyComboBox::OnEnable(BOOL bEnable) 
    {
    	CComboBox::OnEnable(bEnable);
    
    	EnumChildWindows(this->m_hWnd,EnumChildProc, bEnable);
    
    	/*CEdit*	pEdit = (CEdit*)GetWindow(GW_CHILD);
    	pEdit->EnableWindow(TRUE);
    	pEdit->SetReadOnly(!bEnable);*/
    }
    

    ReadOnly....h

    public:
       static BOOL CALLBACK EnumChildProc(HWND hwnd,LPARAM lParam);
    

    Musst du mal Testen. Ich habe hier keinen Compiler wo ich das mal eben durchjagen kann. Vielleicht geht es so.

    Hellsgore



  • Der geht nicht in die EnumChildProc rein. 😕

    In die Zeile mit EnumChildWindows kommt er aber.

    Allerdings funktionieren meine Edits doch nicht so gut wie ich dachte, die sind jetzt immer schreibgeschützt, da muss ich nochmal forschen... 😞



  • Setze bitte bei den Edit direkt auf ReadOnly. Die haben eine Eigenschaft dafür. Hier gaukelst du der ComboBox die Eigenschaft nur vor (obwohl er sie eigentlich hat).

    Hat er denn ein Handle im m_hwnd? Aber ich glaube ich kann dir im Moment nicht mehr weiterhelfen. Ohne Compiler ist es sehr schwer 🙂 .

    Schade eigentlich, hätte ja funktionieren können. 😃 Bei Dialogbasierenden Anwendungen geht das aufjedenfall.

    Hellsgore



  • Du kannst ja, wenn du magst, weiterforschen, wenn du einen Compiler hast.

    Das eilt nicht so sehr, das Projekt dauert noch einige Zeit, es gerade in die Phase, wo fertige Teile durch ausgewählte Endnutzer getestet werden dürfen.
    Ob die nun grau auf grau oder grün auf lila lesen müssen ist fast egal - hauptsache irgendwann geht es.

    Das mit dem m_hwnd gucke ich gleich noch...

    Hmm, direkt auf ReadOnly setzen ist doof, das sind fast 500 Zeilen, die ich durchgehen muss - naja dann ist es wenigstens ordentlich.
    ...übergeredet 😉



  • So, zurück zur Combobox:

    Ich hänge auf der Zeile:

    CEdit* pEdit = dynamic_cast<CEdit*>(GetWindow(GW_CHILD));
    

    und für this steht in der Überwachung:

    0x006c7a48 {CAdCbx
    hWnd=0x0014083a
    


  • Ich komme da immer noch nicht weiter. 😞

    Hat noch jemand Ideen, Tips, Lesevorschläge?





  • Vielen Dank! 🙂
    Da sind ja Sachen bei, wow!

    Leider hilft es mir nicht weiter. 😞
    Ich habe IMMER die gleiche Schriftfarbe, wenn ich die Combobox deaktiviere - egal was für eine ich einstelle.
    Und ich finde nicht, wo das einzustellen ist. 😞

    Hast du eine Idee?


Log in to reply