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