Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[VC, MFC] Größe, Position der Checkbox (ownerdraw)

45 views
Skip to first unread message

Dirk Noack

unread,
Sep 11, 2012, 5:35:05 AM9/11/12
to
Hallo NG,

ich gerade dabei eine Checkbox, genauer gesagt einen Button mit der
Eigenschaft Checkbox, selber zu zeichnen. Icons, Bitmaps oder andere
Schriftformatierungen spielen dabei keine Rolle. Ich keine aufgeblasene
XXLButton-Klasse der einschlᅵgigen Programmierwebsites nehmen um nur die
Hinter-/Vordergrundfarbe zu ᅵndern.

In der DrawItem-Methode habe ich folgendes programmiert:

void CButtonExt::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rect = lpDrawItemStruct->rcItem;

...
pDC->DrawFrameControl(rect, DFC_BUTTON, DFCS_BUTTONCHECK .... );
...
}

Fᅵr einen einfachen Button funktioniert die Kombination DrawFrameControl
mit rect (rcItem), jedoch wird bei einer Checkbox, die Box auf die
komplette Steuerelementgrᅵᅵe gezoomt/gezeichnet.

Wenn man die Checkbox nicht als "ownerdraw" vom Framework mit dem Flag
"BS_AUTOCHECKBOX" zeichnen lᅵsst, wird die Grᅵᅵe der eigentlichen
Hᅵkchenbox begrenzt, d.h. auch wenn ich das Steuerelement im
"Dialogdesigner" grᅵᅵer mache, bleibt die Grᅵᅵe der weiᅵen Box erhalten.

Ich mᅵchte ein nahezu identisches/ᅵhnliches Aussehen wie durch das
Framework, nur um ein Paar einfache Features erweitert.
Wie ermittle ich diese Werte (Grᅵᅵe, Position)? Sind die fest im
Framework hinterlegt oder gibt es da eine irgendeine Get-Methode bzw.
eine abfragbare Systemeigenschaft (Systemmetrics...)?

MfG
Dirk

Jochen Arndt

unread,
Sep 11, 2012, 11:05:33 AM9/11/12
to
Am 11.09.2012 11:35, schrieb Dirk Noack:

> ich gerade dabei eine Checkbox, genauer gesagt einen Button mit der
> Eigenschaft Checkbox, selber zu zeichnen.
[...]
> Für einen einfachen Button funktioniert die Kombination DrawFrameControl
> mit rect (rcItem), jedoch wird bei einer Checkbox, die Box auf die
> komplette Steuerelementgröße gezoomt/gezeichnet.
[...]
> Wie ermittle ich diese Werte (Größe, Position)? Sind die fest im
> Framework hinterlegt oder gibt es da eine irgendeine Get-Methode bzw.
> eine abfragbare Systemeigenschaft (Systemmetrics...)?

Bei klassischen Check Boxes ist die maximale Größe fix, und zwar 13 x 13
Pixel. Bei Verwendung von Themes kann die Größe ermittelt werden:

SIZE sz;
CRect rectBox = lpDrawItemStruct->rcItem;
if (m_hTheme == NULL ||
GetThemePartSize(m_hTheme,
lpDrawItemStruct->hDC,
BP_CHECKBOX,
RBS_UNCHECKEDNORMAL,
&rectBox,
TS_DRAW,
&sz) != S_OK)
{
sz.cx = sz.cy = 13;
}

Anschließend sollte man die Größe noch justieren, falls die Größe des
Controls kleiner ist als die der CheckBox:

if (rectBox.Height() < sz.cy)
sz.cx = sz.cy = rectBox.Height();

Dann die horizontale Position der Box und die Breite setzen:

if (GetStyle() & BS_LEFTTEXT)
{
if (rectBox.right - sz.cx > rectBox.left)
rectBox.left = rectBox.right - sz.cx;
}
else
{
if (rectBox.left + sz.cx < rectBox.right)
rectBox.right = rectBox.left + sz.cx;
}

Eine abschließende vertikale Zentrierung ist optional, da die Box von
DrawFrameControl() zentriert ausgegeben wird:

if (rectBox.Height() > sz.cy+1)
rectBox.top = (rectBox.Height() - sz.cy) >> 1;
rectBox.bottom = rectBox.top + sz.cy;

rectBox enthält jetzt die Koordinaten zum Zeichnen. Bei der Ausgabe des
zugehörigen Textes diesen dann mit 5 Pixel horizontalem Abstand ausgeben.

Joe


Dirk Noack

unread,
Sep 13, 2012, 2:26:02 AM9/13/12
to
Hallo Jochen,

zunᅵchst danke fᅵr deine Ausfᅵhrungen, die haben mir sehr geholfen in
der Sache voranzukommen.

Jochen Arndt schrieb:
>
> Bei klassischen Check Boxes ist die maximale Grᅵᅵe fix, und zwar 13 x 13
> Pixel. Bei Verwendung von Themes kann die Grᅵᅵe ermittelt werden:
>
> [...]
> rectBox enthᅵlt jetzt die Koordinaten zum Zeichnen. Bei der Ausgabe des
> zugehᅵrigen Textes diesen dann mit 5 Pixel horizontalem Abstand ausgeben.
>

Nachdem ich die Checkbox nun ordnungsgemᅵᅵ gezeichnet bekommen habe,
stehe ich vor dem Rᅵtsel mit der Textausrichtung. Ich will die
Mᅵglichkeit der Texstausrichtung ᅵber die Eigenschaften des
Steuerelementes im "Dialogdesigner" in meiner ownerdraw-Checkbox
implementieren. Soweit gar nicht schwer, da es ja nur die Koordinaten
der Textausgabe entsprechend anzupassen gilt.
Mit der Methode "GetButtonStyle()" versuche ich entsprechend auf
BS_LEFT, BS_RIGHT, usw. zu reagieren, jedoch kommen diese Stile gar
nicht in meiner Klasse an, obwohl in der rc-Datei folgendes
(automatisch) eingetragen wurde:

CHECKBOX "MCE -
Auswahlfeld",IDC_CBX_MCE,51,14,87,16,BS_LEFTTEXT |
BS_RIGHT | BS_MULTILINE

Im PreSubClassWindow() erhalte ich nur 0x00000022 (also BS_LEFTTEXT und
BS_CHECKBOX). Auch wenn ich der Checkbox nicht meine eigene Klasse
sondern den Standard-MFC-CButton zuweise, erhalte ich im OnInitDialog()
des ᅵbergeordneten Fensters nur die 0x22.

Da die Stile > 0xFF (BS_RIGHT, etc.) im WinUser.h durch WINVER bedingt
werden, habe ich ich auch schon meine WINVER im stdafx.h auf 0x0500
erhᅵht ... leider ohne Erfolg.

Der Standard-MFC-BUtton reagiert aber entsprechend den eingestellten
Stilen fᅵr BS_LEFT, BS_RIGHT zur Laufzeit. Wo holt sich die MFC solche
Infos her? Gibt es da noch einen Extended-Style? Im GetStyle() liegen ja
nur die WS_-Eigenschaften.

MfG
Dirk

Jochen Arndt

unread,
Sep 13, 2012, 3:15:44 AM9/13/12
to
Am 13.09.2012 08:26, schrieb Dirk Noack:

> zunᅵchst danke fᅵr deine Ausfᅵhrungen, die haben mir sehr geholfen in
> der Sache voranzukommen.

[...]

> Mit der Methode "GetButtonStyle()" versuche ich entsprechend auf
> BS_LEFT, BS_RIGHT, usw. zu reagieren, jedoch kommen diese Stile gar

GetButtonStyle():
Returns the button styles for this CButton object. This function returns
only the BS_ style values, not any of the other window styles.

Du musst GetStyle() verwenden. Der MSDN Text ist hier etwas irrefᅵhrend.
Es werden nᅵmlich nur die mit BS_TYPEMASK und BS_LEFTTEXT maskierten
Bits zurᅵckgegeben.

Aktivierung von OwnerDraw in PresubclassWindows():

ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);

Beim ermitteln der Textformatierung musst du noch darauf achten, dass
die meisten Flags Kombinationen sind (z.B. BS_RIGHT = 0x200, BS_CENTER =
0x300). Ich verwende folgendes:

DWORD nStyle = GetStyle();
UINT uFormat = 0;
if (nStyle & BS_MULTILINE)
uFormat = DT_WORDBREAK;
else // single line
{
// must set this for DT_BOTTOM and DT_VCENTER
uFormat |= DT_SINGLELINE;
// get vertical alignment
switch (nStyle & BS_VCENTER)
{
case BS_BOTTOM : // bottom align
uFormat |= DT_BOTTOM;
case BS_TOP : // top align; DT_TOP is 0
break;
// case BS_VCENTER : // vertically centered
// case 0 : // default; treat as centered
default :
uFormat |= DT_VCENTER;
}
}
switch (nStyle & BS_CENTER) // get horizontal alignment
{
case BS_RIGHT : // right align
uFormat |= DT_RIGHT;
break;
case BS_CENTER : // centered
uFormat |= DT_CENTER;
break;
// case BS_LEFT : // left align;
// case 0 : // default; treat as left
// default :
// uFormat |= DT_LEFT; // DT_LEFT is 0
}
// Windows 2000/XP: Hide accelerator (no underline for shortcut)
if (lpDrawItemStruct->itemState & ODS_NOACCEL)
uFormat |= DT_HIDEPREFIX;

Joe

Dirk Noack

unread,
Sep 13, 2012, 3:57:01 AM9/13/12
to
Jochen Arndt schrieb:
> GetButtonStyle():
> Returns the button styles for this CButton object. This function returns
> only the BS_ style values, not any of the other window styles.
>
> Du musst GetStyle() verwenden. Der MSDN Text ist hier etwas irrefᅵhrend.
> Es werden nᅵmlich nur die mit BS_TYPEMASK und BS_LEFTTEXT maskierten
> Bits zurᅵckgegeben.

Dann hat mich der MSDN Text wirklich in die Irre gefᅵhrt, denn ich habe
es so interpretiert:
(1) Die Funktion gibt nur BS_-Stile zurᅵck (-> BS_LEFT, BS_RIGHT ist ein
BS_-Stil)
(2) Die Funktion gibt nicht die anderen Fensterstile zurᅵck (->
WS_-Stile ... die will ich ja auch nicht).

Das die "erweiterten" BS_-Stile oberhalb von 0xFF bzw. auᅵer BS_TYPEMASK
und BS_LEFTTEXT) ᅵber GetStyle() zu lesen sind, war mir nicht klar.

>
> Aktivierung von OwnerDraw in PresubclassWindows():
>
> ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);

Ich hatte bisher (geerbt vom Ersteller der vorhandenen Klasse) nur
ModifyStyle(0, BS_OWNERDRAW, SWP_FRAMECHANGED).

>
> Beim ermitteln der Textformatierung musst du noch darauf achten, dass
> die meisten Flags Kombinationen sind (z.B. BS_RIGHT = 0x200, BS_CENTER =
> 0x300). Ich verwende folgendes:

Ok, das hatte ich schon aus einem Newsgroup-Thread mit Dir und Martin
Richter von vor 3 Jahren gelesen und zur Kenntnis genommen.

>
> DWORD nStyle = GetStyle();
> UINT uFormat = 0;
> if (nStyle & BS_MULTILINE)
> uFormat = DT_WORDBREAK;
> else // single line
> {
> [...]
> }
> // Windows 2000/XP: Hide accelerator (no underline for shortcut)
> if (lpDrawItemStruct->itemState & ODS_NOACCEL)
> uFormat |= DT_HIDEPREFIX;
>
>
Das werde ich mal ausprobieren.

Danke!
0 new messages