XP Style



  • bei:
    m_theme.DrawBackground(lpDrawItemStruct->hDC, BP_PUSHBUTTON, PBS_DEFAULTED, &lpDrawItemStruct->rcItem, 0);

    kommt ein wert von -2147024890 glaube nicht das der richtig ist, also das da irgendetwas falsch läuft... ausgeschaltet dürfte er aber nicht sein, weil der ThemenExplorer con codeguro auch funktioniert... muss ich vieleicht noch wm_themenchange behandeln?



  • bei:
    m_theme.DrawBackground(lpDrawItemStruct->hDC, BP_PUSHBUTTON, PBS_DEFAULTED, &lpDrawItemStruct->rcItem, 0);

    kommt ein wert von -2147024890 glaube nicht das der richtig ist, also das da irgendetwas falsch läuft... ausgeschaltet dürfte er aber nicht sein, weil der ThemenExplorer con codeguro auch funktioniert... muss ich vieleicht noch wm_themenchange behandeln?



  • sorry mein explorer hat grad gesponnen... Deshalb sind die einträge jetzt doppelt!!! 😞



  • habe es nochmal debugt und habe außer das :

    m_theme.DrawBackground(lpDrawItemStruct->hDC, BP_PUSHBUTTON, PBS_DEFAULTED, &lpDrawItemStruct->rcItem, 0);

    einen komischen wert zurückliefert noch festgestellt, das m_hTheme selber NULL :

    - m_theme {...}
    m_hTheme 0x00000000 -> warum null oder ist das so?
    + m_hThemeDll 0x5b0f0000
    m_bLoaded 1
    m_pOpenThemeData 0x5b0f7cb8
    m_pCloseThemeData 0x5b0f4940
    m_pDrawThemeBackground 0x00000000
    m_pDrawThemeText 0x00000000
    m_pGetThemeBackgroundContentRect 0x00000000
    m_pGetThemeBackgroundExtent 0x00000000
    m_pGetThemePartSize 0x00000000
    m_pGetThemeTextExtent 0x00000000
    m_pGetThemeTextMetrics 0x00000000
    m_pGetThemeBackgroundRegion 0x00000000
    m_pHitTestThemeBackground 0x00000000
    m_pDrawThemeEdge 0x00000000
    m_pDrawThemeIcon 0x00000000
    m_pIsThemePartDefined 0x00000000
    m_pIsThemeBackgroundPartiallyTransparent 0x00000000
    m_pGetThemeColor 0x00000000
    m_pGetThemeMetric 0x00000000
    m_pGetThemeString 0x00000000
    m_pGetThemeBool 0x00000000
    m_pGetThemeInt 0x00000000
    m_pGetThemeEnumValue 0x00000000
    m_pGetThemePosition 0x00000000
    m_pGetThemeFont 0x00000000
    m_pGetThemeRect 0x00000000
    m_pGetThemeMargins 0x00000000
    m_pGetThemeIntList 0x00000000
    m_pGetThemePropertyOrigin 0x00000000
    m_pSetWindowTheme 0x00000000
    m_pGetThemeFilename 0x00000000
    m_pGetThemeSysColor 0x00000000
    m_pGetThemeSysColorBrush 0x00000000
    m_pGetThemeSysBool 0x00000000
    m_pGetThemeSysSize 0x00000000
    m_pGetThemeSysFont 0x00000000
    m_pGetThemeSysString 0x00000000
    m_pGetThemeSysInt 0x00000000
    m_pIsThemeActive 0x00000000
    m_pIsAppThemed 0x00000000
    m_pGetWindowTheme 0x00000000
    m_pEnableThemeDialogTexture 0x00000000
    m_pIsThemeDialogTextureEnabled 0x00000000
    m_pGetThemeAppProperties 0x00000000
    m_pSetThemeAppProperties 0x00000000
    m_pGetCurrentThemeName 0x00000000
    m_pGetThemeDocumentationProperty 0x00000000
    m_pDrawThemeParentBackground 0x00000000
    m_pEnableTheming 0x00000000



  • also m_theme darf nicht null sein. bei initialisierung von :

    IMPLEMENT_DYNAMIC(CXPBUTTON, CButton)
    
    CXPBUTTON::CXPBUTTON(): m_theme(GetSafeHwnd(), L"BUTTON") 
    
    {
    }
    

    bekommt m_theme NULL, da GetSafeHwnd() null zurückliefert, da der Button bzw. die Dialogbox noch nicht existiert irgendwie :

    + m_theme {...}
    + this 0x0012fe90 {CXPBUTTON hWnd=0x00000000}
    CButton::CButton returned <void>
    CWnd::GetSafeHwnd returned 0x00000000
    CXPTheme::CXPTheme returned <void>

    Hem.... Habe nun in DrawItem die Zeile:

    CXPTheme m_theme(GetSafeHwnd(), L"BUTTON");
    

    eingefügt. und es funktioniert... Warum das ganze so ist verstehe ich schon... aber wozu schreibe ich denn dann das ganze so:

    IMPLEMENT_DYNAMIC(CXPBUTTON, CButton)
    
    CXPBUTTON::CXPBUTTON(): m_theme(GetSafeHwnd(), L"BUTTON") 
    
    {
    }
    


  • Hi,

    ich habe den code auch mal debugt. GetSafeHwnd liefert natürlich NULL weil
    es im Konstruktor aufgerufen wird und das Fenster dann noch nicht existiert.

    Trotzdem wird bei mir ein gültiges themehandle gesetzt (zumindest im Debug-Mode)
    warum auch immer da ein Unterschied bei dir ist, liegt wohl tiefer im
    Betriebssystem (XP Professionell SP2), aber du hast recht das es so nicht
    richtig ist.

    Da DrawItem im laufe des Programms sehr oft aufgerufen wird, ist es ziemlicher
    Overkill jedesmal ein Objekt vom Typ CXPTheme zu erzeugen, auch wenn das
    auf modernen schnellen Rechnern nicht so auffält.

    Um es dennoch mit der Membervariable zu machen, bleibt dann wohl nichts anderes
    übrig als diese zu Laufzeit dynamisch zu erzeugen.

    Bei einem abgeleiteten Button am besten in PreSubclassWindow

    IMPLEMENT_DYNAMIC(CXPButton, CButton)
    CXPButton::CXPButton()
    : m_pTheme(NULL)
    {
    }
    
    CXPButton::~CXPButton()
    {
    	delete m_pTheme;
    }
    
    void CXPButton::PreSubclassWindow()
    {
    	m_pTheme = new CXPTheme(GetSafeHwnd(), L"BUTTON");
    
    	CButton::PreSubclassWindow();
    }
    

    Gruss
    EB



  • habe es geändert. weil mit dem Overkill hast Du schon recht... Jetzt steht bei m_theme auch etwas drin, also ist nicht mehr NULL. nur leider geht es dann auch nicht. wie gesagt: nur wenn ich die zeile:

    CXPTheme m_theme(GetSafeHwnd(), L"BUTTON");
    

    in die DrawItem function schreibe... ist ganz schön seltsam... 😕



  • habe jetzt in der Function PreSubClassWindow() folgendes geändert:

    void CXPBUTTON::PreSubclassWindow() 
    {
    	// TODO: Add your specialized code here and/or call the base class
    
    	 m_pTheme = CXPTheme(GetSafeHwnd(), L"BUTTON"); 
    
    	CButton::PreSubclassWindow();
    }
    

    und das:

    delete m_pTheme;
    

    habe ich gelöscht... Danach ging es auf einmal... 😕

    Noch mal nur so ne andere Frage...

    um den Status des Buttons muss ich mich jetzt selbst kümmern oder gibt es da vieleicht noch ne einfachere Methode? ich wollte es mit wm_mousemove in verbindung mit der drawitem Methode machen und so abfragen ob sich die mause über dem button befindet, um dann das aussehen auf BPS_HOT zu stellen...?



  • darkangel76 schrieb:

    habe jetzt in der Function PreSubClassWindow() folgendes geändert:

    void CXPBUTTON::PreSubclassWindow() 
    {
    	// TODO: Add your specialized code here and/or call the base class
    	
    	 m_pTheme = CXPTheme(GetSafeHwnd(), L"BUTTON"); 
    	
    	CButton::PreSubclassWindow();
    }
    

    und das:

    delete m_pTheme;
    

    Du hast in der Header datei aus CXPTheme m_theme wohl keinen Zeiger
    gemacht!
    Das hatte ich eigentlich als Grundwissen vorausgesetzt...
    Es muss im Heáder folgendes stehen:

    private:
       CXPTheme*  m_pTheme;
    

    Danach klappt die Speicherzuweisung mit new und das freigeben mit delete.

    darkangel76 schrieb:

    um den Status des Buttons muss ich mich jetzt selbst kümmern oder gibt es da vieleicht noch ne einfachere Methode? ich wollte es mit wm_mousemove in verbindung mit der drawitem Methode machen und so abfragen ob sich die mause über dem button befindet, um dann das aussehen auf BPS_HOT zu stellen...?

    Stimmmt, das gehört jetzt alles Dir 😋 und wird alles in DrawItem
    gemacht. Sieh dir dazu die MSDN an was alles in der Struktur lpDrawItemStruct
    drinsteckt, dann kannst Du entscheiden wie und was Du zeichnest in DrawItem.

    Gruss
    EB



  • Hab jetzt soweit alles fertig. auch das der Button auf Mouseleave reagiert u. so... hat nur noch einen kleinen Grafik fehler... der button sieht ein wenig nach mehrmaliegen rüberfahren mit der maus oder beim durchlaufen mit der Tastatur wie ein eingestampf aus - falls du weist was ich meine... wenn ich das fenster minimiere und dann wieder groß mache ist er wieder normal... Na mal schauen ob ich das noch wegbekomme 😕

    Danke Dir aber janz dolle...



  • 😕

    Ich stelle mal meinen Quellcode von meinem CXPButton rein... Vieleicht kann mir ja jemand sagen warum mein Button nachdem ich mit meiner Maus ein paar mal rüber gefahren bin irgendwie so aussieht als ob er tiefergesetzt wurde... Ist schon merkwürdig... man könnte zwar im Hauptprogramm dann über nen wm_mousemove abfragen wo sich der zeiger befindet und dann den kompletten Dialog neu zeichnen, aber ich wollte eigentlich alles in meiner CXPButton Klasse unterbringen. So das man sich beim einbinden keinen Kopf mehr machen muss... erst recht wenn es am ende dann vieleicht 10 Button und noch anderer kram ist... kann man das ganze vieleicht mit nem Sendmessage ans Dialogfenster in "onMouseLeave" erreichen? und wenn ja wie?

    // XPBUTTON.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "XPStyle.h"
    #include "XPBUTTON.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    #define ODS_NOFOCUSRECT     0x0200
    
    /////////////////////////////////////////////////////////////////////////////
    // CXPBUTTON
    IMPLEMENT_DYNAMIC(CXPBUTTON, CButton)
    
    CXPBUTTON::CXPBUTTON(): m_pTheme(NULL) 
    
    {
    	bMouseOverButton = false;
    }
    
    CXPBUTTON::~CXPBUTTON()
    {
    }
    
    BEGIN_MESSAGE_MAP(CXPBUTTON, CButton)
    	//{{AFX_MSG_MAP(CXPBUTTON)
    	ON_WM_ERASEBKGND()
    	ON_WM_MOUSEMOVE()
    	//}}AFX_MSG_MAP
    	ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CXPBUTTON message handlers
    
    void CXPBUTTON::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
    {
    	// wird aufegrufen vom Framework wegen ownerdraw-style 
    
    	CDC dc; 
        dc.Attach(lpDrawItemStruct->hDC); 
        CString strCaption; 
        GetWindowText(strCaption); 
        if (m_pTheme.IsAppThemed())
    	{			
    		// button state
    		BOOL bIsPressed =	(lpDrawItemStruct->itemState & ODS_SELECTED);
    		BOOL bIsFocused  = (lpDrawItemStruct->itemState & ODS_FOCUS);
    		BOOL bIsDisabled = (lpDrawItemStruct->itemState & ODS_DISABLED);
    		BOOL bDrawFocusRect = !(lpDrawItemStruct->itemState & ODS_NOFOCUSRECT);
    
    		// Prepare draw... paint button background
    
    		DWORD state = (bIsPressed)?PBS_PRESSED:PBS_NORMAL;
    
    		if(state == PBS_NORMAL)
    		{
    			if(bIsFocused)
    				state = PBS_DEFAULTED;
    			if(bMouseOverButton)
    				state = PBS_HOT;
    		}
    
    		m_pTheme.DrawBackground(lpDrawItemStruct->hDC, BP_PUSHBUTTON, state, &lpDrawItemStruct->rcItem, 0); 
    		int nOldBkgnMode = dc.SetBkMode(TRANSPARENT); 
    		dc.DrawText(strCaption, &lpDrawItemStruct->rcItem, DT_CENTER|DT_SINGLELINE|DT_VCENTER); 
    		dc.SetBkMode(nOldBkgnMode);	
    
    		if (bIsFocused && bDrawFocusRect)
    		{
    			RECT focusRect =lpDrawItemStruct->rcItem;
    			InflateRect(&focusRect, -3, -3);
    			DrawFocusRect(dc, &focusRect);
    		}
    	}
        dc.Detach(); 	
    }
    
    BOOL CXPBUTTON::OnEraseBkgnd(CDC* pDC) 
    {
    	// wir zeichnen nichts, weil wir das fenster mit den button 
        // komplett in DrawItem zeichnen 
        // ausserdem verhindern wir dadurch flickern da der standard hintergrund 
        // weiss gezeichnet wird 
        return TRUE;
    }
    
    void CXPBUTTON::PreSubclassWindow() 
    {
    	// TODO: Add your specialized code here and/or call the base class
    
    	 m_pTheme = CXPTheme(GetSafeHwnd(), L"BUTTON"); 
    
    	CButton::PreSubclassWindow();
    }
    
    void CXPBUTTON::OnMouseMove(UINT nFlags, CPoint point) 
    {
    	// TODO: Add your message handler code here and/or call default
    
    	if(!bMouseOverButton)
    	{
    		bMouseOverButton = TRUE;
    
    		TRACKMOUSEEVENT trackmouseevent;
    		trackmouseevent.cbSize = sizeof(trackmouseevent);
    		trackmouseevent.dwFlags = TME_LEAVE;
    		trackmouseevent.hwndTrack = GetSafeHwnd();
    		trackmouseevent.dwHoverTime = 0;
    		_TrackMouseEvent(&trackmouseevent);
    
    		InvalidateRect(NULL, FALSE);
    	} 
    
    	CButton::OnMouseMove(nFlags, point);
    }
    
    LONG CXPBUTTON::OnMouseLeave(WPARAM wParam, LPARAM lParam) 
    {
    	bMouseOverButton = false;
    
    	InvalidateRect(NULL, FALSE);	
    
    	return 0;
    }
    
    #if !defined(AFX_XPBUTTON_H__9AE4DC26_E531_4C94_BF39_F53EE333DF78__INCLUDED_)
    #define AFX_XPBUTTON_H__9AE4DC26_E531_4C94_BF39_F53EE333DF78__INCLUDED_
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    // XPBUTTON.h : header file
    //
    
    /////////////////////////////////////////////////////////////////////////////
    // CXPBUTTON window
    
    class CXPBUTTON : public CButton
    {
    	DECLARE_DYNAMIC(CXPBUTTON)	
    // Construction
    public:
    	CXPBUTTON();
    
    // Attributes
    public:
    
    // Operations
    public:
    
    // Overrides
    	// ClassWizard generated virtual function overrides
    	//{{AFX_VIRTUAL(CXPBUTTON)
    	public:
    	virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    	protected:
    	virtual void PreSubclassWindow();
    	//}}AFX_VIRTUAL
    
    // Implementation
    public:
    	virtual ~CXPBUTTON();
    
    private:
    	CXPTheme m_pTheme;
    	BOOL	ScreenPointInButtonRect(CPoint point);
    
    	bool bMouseOverButton;
    
    	// Generated message map functions
    protected:
    	//{{AFX_MSG(CXPBUTTON)
    	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    	//}}AFX_MSG
    	LONG OnMouseLeave(WPARAM wParam, LPARAM lParam);
    
    	DECLARE_MESSAGE_MAP()
    };
    
    /////////////////////////////////////////////////////////////////////////////
    
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
    
    #endif // !defined(AFX_XPBUTTON_H__9AE4DC26_E531_4C94_BF39_F53EE333DF78__INCLUDED_)
    

    ist bestimmt nur kinderkram für die meisten von euch, aber für mich die halbe c++ welt... 😉


Anmelden zum Antworten