Text color & SetBkMode(hdc, transparent) 
Author Message
 Text color & SetBkMode(hdc, transparent)

So I'm playing around and getting some things to work with transparency &
whatnot and things are going nicely until... I try to put a color on a bit
of text I'm drawing.  Here's a snippet of bad code I'm using:

'------- Begin Horrible, Not Quite Working and Ugly Code
    hdcOriginal = CreateCompatibleDC(0&)

    fontHeight = Abs(-MulDiv(Me.textInfo(1).Text, GetDeviceCaps(hdcOriginal,
LOGPIXELSY), 72) / (1600 / 360))
    hFont = CreateFont(fontHeight * -1, 0, 0, 0, FW_BOLD, 0, 0, 0,
ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
DEFAULT_PITCH Or FF_DONTCARE, Me.textInfo(0).Text)
    holdFont = SelectObject(hdcOriginal, hFont)
    GetTextExtentPoint32 hdcOriginal, Me.textInfo(2).Text,
Len(Me.textInfo(2).Text), textSize

    bmpOriginal = CreateCompatibleBitmap(hdcOriginal, textSize.X,
textSize.Y)
    SelectObject hdcOriginal, bmpOriginal

    lRet = SetBkMode(hdcOriginal, TRANSPARENT)
    lRet = SetTextColor(hdcOriginal, vbYellow)
    lRet = SetMapMode(hdcOriginal, MM_TEXT)

    With LP
        .lopnColor = vbYellow
        .lopnStyle = 0
        .lopnWidth = 1
    End With
    hRPen = CreatePenIndirect(LP)    SelectObject hdcOriginal, hRPen

    hBrush = CreateSolidBrush(vbYellow)
    SelectObject hdcOriginal, hBrush

    retval = BeginPath(hdcOriginal)
    retval = TextOut(hdcOriginal, 0, 0, Me.textInfo(2).Text,
Len(Me.textInfo(2).Text))
    retval = EndPath(hdcOriginal)
    retval = StrokeAndFillPath(hdcOriginal)

    retval = SelectObject(hdcOriginal, holdFont)
    retval = DeleteObject(hFont)

    DeleteObject hBrush
    DeleteObject hRPen
    .
    .
    .
    .
    .
    BitBlt Me.picDisplay.hDC, 0, 0, textSize.X, textSize.Y, hdcOriginal, 0,
0, vbSrcPaint

'----- Thankfully End Horrifying Code Block

What this gives me is my text like I want it but the text color is white and
it seems... I dunno.  Like it's been shot up.  Not quite solid but with
holes in the text.  And it's still white, not yellow.  I pieced this code
together from examples & trial and error since this isn't the kind of stuff
I normally work on and it almost works, too.... minus the color and solidity
of the text.

Help is much appreciated.

Sam Shults



Sun, 27 Mar 2005 14:39:18 GMT  
 Text color & SetBkMode(hdc, transparent)

Quote:
> So I'm playing around and getting some things to work with transparency &
> whatnot and things are going nicely until... I try to put a color on a bit
> of text I'm drawing.  Here's a snippet of bad code I'm using:
<code snipped>
> What this gives me is my text like I want it but the text color is white
and
> it seems... I dunno.  Like it's been shot up.  Not quite solid but with
> holes in the text.  And it's still white, not yellow.  I pieced this code
> together from examples & trial and error since this isn't the kind of
stuff
> I normally work on and it almost works, too.... minus the color and
solidity
> of the text.

For a start, you've got a big ol' memory leak in there since you're not
dealing with the GDI objects properly.  When you use the Font object with
the DC just above it, it's being used in the correct way i.e:

'***
holdFont = SelectObject(hdcOriginal, hFont)
'***

However when you come to select the Bitmap in the same way:

'***
SelectObject hdcOriginal, bmpOriginal
'***

You've not retained the old Bitmap handle to de-select the bitmap later on.
This will result in the Bitmap not being de-selected from the DC properly
and hence memory leaks.  What you need to do here is change that to:

'***
Dim holdBitmap As Long
holdBitmap = SelectObject(hdcOriginal, bmpOriginal)
'***

Then at the end of your code after you've blitted from the DC (And
presumably finished with the Bitmap?) you can clean up:

'***
DeleteObject SelectObject(hdcOriginal, holdBirmap)
DeleteDC hdcOriginal
'***

The same memory leak is also there with the Pen and Brush objects.  The
lifespan of a GDI object should be as follows:

Created
    Selected into DC (Application should retain the old handle)
        Used
    De-selected from DC (Appliction should select old handle back into DC)
Destroyed

The application is not required to remember the old handle when de-selecting
the GDI object from the DC since we already know it's the handle to the GDI
object we created earlier.  Indeed, it's actually more important to remember
the old handle rather than the one we created, if you're not checking for a
bad handle then this is perfectly valid code:

'***
Dim oldPen As Long
oldPen = SelectObject(hdcOriginal, CreatePenIndirect(LP))
' Use DC here..
DeleteObject SelectObject(hdcOriginal, oldPen)
'***

I don't advise doing it this way, but it does highlight the point that it's
very important to retain the old handle and memory leaks will build up real
quick if you don't.
If you want a more in-depth overview on DC's and their use then head over to
my page where you'll find the "Basic introduction to Device Context's (DC's)
in VB" tutorial which walks you through all this and creates you a class to
encapsulate it all.
Also, if you're not checking the return value of the API calls you don't
need to retain their results so:

'***
retval = BeginPath(hdcOriginal)
'***

Is the same as:

'***
BeginPath hdcOriginal
'***

If you prefer it with the parenthesis on then you can also use:

'***
Call BeginPath(hdcOriginal)
'***

Finally, the reason why you're getting the {*filter*} overlay problem is that
you're using the vbSrcPaint ROP (Raster opperation) in the final BitBlt()
call.  What this does is to perform a Boolean Or on both the source and
destination colours which can result in come very odd effects.  Change this
is "vbSrcCopy" instead which will just blit the DC's colours.  If you don't
want the background of the DC when you blit it then you can BitBlt() the
background of whatever it's drawing to to the DC before you draw the text.
This way, when you draw the DC to the picture box (I guess that's what
picDisplay is) then it will still have the old background as the background
on the Text DC.  If you're just drawing over a flat colour then you can use
the FillRect() API call instead to blank the background of your DC
If you need any further help on any of this then let me know.
Hope this helps,

    Mike

 -- EDais --

 - Microsoft Visual Basic MVP -
WWW: http://www.*-*-*.com/




Sun, 27 Mar 2005 17:45:09 GMT  
 Text color & SetBkMode(hdc, transparent)
Hey, thanks (again) for the reply.  I cleaned up the code per your
suggestions and changed over to vbSrcCopy and now I'm getting solid white
letters but still no color.  I'll repaste the code I'm using below:

---------------------------------------------------
    hdcOriginal = CreateCompatibleDC(0&)

    fontHeight = Abs(-MulDiv(Me.textInfo(1).Text, GetDeviceCaps(hdcOriginal,
LOGPIXELSY), 72) / (1600 / 360))
    hFont = CreateFont(fontHeight * -1, 0, 0, 0, FW_BOLD, 0, 0, 0,
ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
DEFAULT_PITCH Or FF_DONTCARE, Me.textInfo(0).Text)
    holdFont = SelectObject(hdcOriginal, hFont)

    GetTextExtentPoint32 hdcOriginal, Me.textInfo(2).Text,
Len(Me.textInfo(2).Text), textSize

    bmpOriginal = CreateCompatibleBitmap(hdcOriginal, textSize.X,
textSize.Y)
    SelectObject hdcOriginal, bmpOriginal

    SetBkMode hdcOriginal, TRANSPARENT
    SetTextColor hdcOriginal, vbYellow
    SetMapMode hdcOriginal, MM_TEXT

    hRPen = CreatePen(0, 1, vbYellow)
    oldPen = SelectObject(hdcOriginal, hRPen)

    hBrush = CreateSolidBrush(vbYellow)
    oldBrush = SelectObject(hdcOriginal, hBrush)

    BeginPath hdcOriginal
    TextOut hdcOriginal, 0, 0, Me.textInfo(2).Text, Len(Me.textInfo(2).Text)
    EndPath hdcOriginal
    StrokeAndFillPath hdcOriginal

    SelectObject hdcOriginal, holdFont
    DeleteObject hFont

    SelectObject hdcOriginal, oldPen
    DeleteObject hRPen

    SelectObject hdcOriginal, oldBrush
    DeleteObject hBrush

    BitBlt Me.picDisplay.hDC, 0, 0, textSize.X, textSize.Y, hdcOriginal, 0,
0, vbSrcCopy
    UpdateWindow hdcOriginal, True

    SelectObject hdcOriginal, holdBitmap
    DeleteObject bmpOriginal
    DeleteDC hdcOriginal
----------------------------------------------------

I've actually used GetPixel and looped through hdcOriginal before BitBlt'ing
and it's still showing just 0, -1 and White as the colors being used.  I
keep thinking there's something really dumb I'm missing but I can't see what
it might be.  I've looked at a few other examples and while I don't see one
that uses CreateCompatibleBitmap along with CreateCompatibleDC in the way
I'm using (bitblt'ing from the memory dc & bmp) it's still somewhat
similiar.



Quote:
> > So I'm playing around and getting some things to work with transparency
&
> > whatnot and things are going nicely until... I try to put a color on a
bit
> > of text I'm drawing.  Here's a snippet of bad code I'm using:
> <code snipped>
> > What this gives me is my text like I want it but the text color is white
> and
> > it seems... I dunno.  Like it's been shot up.  Not quite solid but with
> > holes in the text.  And it's still white, not yellow.  I pieced this
code
> > together from examples & trial and error since this isn't the kind of
> stuff
> > I normally work on and it almost works, too.... minus the color and
> solidity
> > of the text.

> For a start, you've got a big ol' memory leak in there since you're not
> dealing with the GDI objects properly.  When you use the Font object with
> the DC just above it, it's being used in the correct way i.e:

> '***
> holdFont = SelectObject(hdcOriginal, hFont)
> '***

> However when you come to select the Bitmap in the same way:

> '***
> SelectObject hdcOriginal, bmpOriginal
> '***

> You've not retained the old Bitmap handle to de-select the bitmap later
on.
> This will result in the Bitmap not being de-selected from the DC properly
> and hence memory leaks.  What you need to do here is change that to:

> '***
> Dim holdBitmap As Long
> holdBitmap = SelectObject(hdcOriginal, bmpOriginal)
> '***

> Then at the end of your code after you've blitted from the DC (And
> presumably finished with the Bitmap?) you can clean up:

> '***
> DeleteObject SelectObject(hdcOriginal, holdBirmap)
> DeleteDC hdcOriginal
> '***

> The same memory leak is also there with the Pen and Brush objects.  The
> lifespan of a GDI object should be as follows:

> Created
>     Selected into DC (Application should retain the old handle)
>         Used
>     De-selected from DC (Appliction should select old handle back into DC)
> Destroyed

> The application is not required to remember the old handle when
de-selecting
> the GDI object from the DC since we already know it's the handle to the
GDI
> object we created earlier.  Indeed, it's actually more important to
remember
> the old handle rather than the one we created, if you're not checking for
a
> bad handle then this is perfectly valid code:

> '***
> Dim oldPen As Long
> oldPen = SelectObject(hdcOriginal, CreatePenIndirect(LP))
> ' Use DC here..
> DeleteObject SelectObject(hdcOriginal, oldPen)
> '***

> I don't advise doing it this way, but it does highlight the point that
it's
> very important to retain the old handle and memory leaks will build up
real
> quick if you don't.
> If you want a more in-depth overview on DC's and their use then head over
to
> my page where you'll find the "Basic introduction to Device Context's
(DC's)
> in VB" tutorial which walks you through all this and creates you a class
to
> encapsulate it all.
> Also, if you're not checking the return value of the API calls you don't
> need to retain their results so:

> '***
> retval = BeginPath(hdcOriginal)
> '***

> Is the same as:

> '***
> BeginPath hdcOriginal
> '***

> If you prefer it with the parenthesis on then you can also use:

> '***
> Call BeginPath(hdcOriginal)
> '***

> Finally, the reason why you're getting the {*filter*} overlay problem is that
> you're using the vbSrcPaint ROP (Raster opperation) in the final BitBlt()
> call.  What this does is to perform a Boolean Or on both the source and
> destination colours which can result in come very odd effects.  Change
this
> is "vbSrcCopy" instead which will just blit the DC's colours.  If you
don't
> want the background of the DC when you blit it then you can BitBlt() the
> background of whatever it's drawing to to the DC before you draw the text.
> This way, when you draw the DC to the picture box (I guess that's what
> picDisplay is) then it will still have the old background as the
background
> on the Text DC.  If you're just drawing over a flat colour then you can
use
> the FillRect() API call instead to blank the background of your DC
> If you need any further help on any of this then let me know.
> Hope this helps,

>     Mike

>  -- EDais --

>  - Microsoft Visual Basic MVP -
> WWW: http://www.*-*-*.com/





Tue, 29 Mar 2005 02:29:41 GMT  
 Text color & SetBkMode(hdc, transparent)

Quote:
> Hey, thanks (again) for the reply.  I cleaned up the code per your
> suggestions and changed over to vbSrcCopy and now I'm getting solid white
> letters but still no color.  I'll repaste the code I'm using below:

<snip>

Quote:
> I've actually used GetPixel and looped through hdcOriginal before
BitBlt'ing
> and it's still showing just 0, -1 and White as the colors being used.  I
> keep thinking there's something really dumb I'm missing but I can't see
what
> it might be.  I've looked at a few other examples and while I don't see
one
> that uses CreateCompatibleBitmap along with CreateCompatibleDC in the way
> I'm using (bitblt'ing from the memory dc & bmp) it's still somewhat
> similiar

Much better!  Your machine will be thankful :)
The Bitmap select is still a little off though, you've not retained the old
handle when you select it into the DC despite referencing it when you clean
it up at the end!  Also for future reference the following two lines:

'***
SelectObject hdcOriginal, holdBitmap
DeleteObject bmpOriginal
'***

Can be re-written as:

'***
DeleteObject SelectObject(hdcOriginal, holdBitmap)
'***

If "bmpOriginal" was the last thing you selected into the DC which is the
case here.  All the API objects can be de-selected and destroyed using this
shorthand notation, it just helps reduce some of the clutter.
Also, you're calling a method called "UpdateWindow", is this the API call or
your own method?  If it's the API call then take it out since it requires
the handle to a window handle and you're passing it a DC handle, if it's
your own method then ignore this.
Finally the source of your problem though (Which I missed the first time,
apologies for that..) is that you're passing CreateCompatibleBitmap() the
handle to your newly created DC.  What happens behind the scenes when you
create a DC is that Windows creates the DC and selects all the default
objects into it so there can never be a case when a DC is asked for an
object is doesn't have - There will _always_ be something there.  In the
case of the Bitmap, since they take up so much memory the opted for the
smallest Bitmap possible, a 1*1*1 Bitmap (Actually, ironically this _isn't_
the smallest Bitmap possible, a 16, 24 or 32-bit 1*1 Bitmap would actually
be 8 bytes smaller due to the way they store their data and palette, but hey
;)
As such when you pass your newly created DC to CreateCompatibleBitmap(), it
queries the internal Bitmap (The 1*1*1 placeholder) and assumes that you
want it to create a Bitmap compatible with that, i.e. another 1-BPP Bitmap!)
In this case you don't want a 1 BPP Bitmap since you're wanting to use RGB
colour in there so we'll need to pass it the handle of another DC with a
'good' Bitmap selected into it.  The easiest way of doing this is to pass it
the desktop window's DC which you can do with the following:

'***
Dim DeskWnd As Long, DeskDC As Long

DeskWnd = GetDesktopWindow()
DeskDC = GetDC(DeskWnd)
bmpOriginal = CreateCompatibleBitmap( _
    DeskDC, textSize.X, textSize.Y)
ReleaseDC DeskWnd, DeskDC
'***

That should be all you need, if you find any more problems then post back
here and we'll take another look.
Hope this helps,

    Mike

 -- EDais --

 - Microsoft Visual Basic MVP -
WWW: Http://EDais.earlsoft.co.uk/




Tue, 29 Mar 2005 03:13:34 GMT  
 Text color & SetBkMode(hdc, transparent)
Awesome!  That did the trick right there.  I was driving myself nuts trying
different things to get it to work so that's a real load of my mind.

And UpdateWindow is mine.  I guess I need to rename it since there's an
actual function called that.  It's just RedrawWindow with "RDW_ERASE Or
RDW_INVALIDATE Or RDW_ALLCHILDREN Or RDW_UPDATENOW" as the flags.

Now I'm going to try another post and see if I can get some ideas on that.
Once again, thanks a lot.

Sam



Quote:
> > Hey, thanks (again) for the reply.  I cleaned up the code per your
> > suggestions and changed over to vbSrcCopy and now I'm getting solid
white
> > letters but still no color.  I'll repaste the code I'm using below:

> <snip>

> > I've actually used GetPixel and looped through hdcOriginal before
> BitBlt'ing
> > and it's still showing just 0, -1 and White as the colors being used.  I
> > keep thinking there's something really dumb I'm missing but I can't see
> what
> > it might be.  I've looked at a few other examples and while I don't see
> one
> > that uses CreateCompatibleBitmap along with CreateCompatibleDC in the
way
> > I'm using (bitblt'ing from the memory dc & bmp) it's still somewhat
> > similiar

> Much better!  Your machine will be thankful :)
> The Bitmap select is still a little off though, you've not retained the
old
> handle when you select it into the DC despite referencing it when you
clean
> it up at the end!  Also for future reference the following two lines:

> '***
> SelectObject hdcOriginal, holdBitmap
> DeleteObject bmpOriginal
> '***

> Can be re-written as:

> '***
> DeleteObject SelectObject(hdcOriginal, holdBitmap)
> '***

> If "bmpOriginal" was the last thing you selected into the DC which is the
> case here.  All the API objects can be de-selected and destroyed using
this
> shorthand notation, it just helps reduce some of the clutter.
> Also, you're calling a method called "UpdateWindow", is this the API call
or
> your own method?  If it's the API call then take it out since it requires
> the handle to a window handle and you're passing it a DC handle, if it's
> your own method then ignore this.
> Finally the source of your problem though (Which I missed the first time,
> apologies for that..) is that you're passing CreateCompatibleBitmap() the
> handle to your newly created DC.  What happens behind the scenes when you
> create a DC is that Windows creates the DC and selects all the default
> objects into it so there can never be a case when a DC is asked for an
> object is doesn't have - There will _always_ be something there.  In the
> case of the Bitmap, since they take up so much memory the opted for the
> smallest Bitmap possible, a 1*1*1 Bitmap (Actually, ironically this
_isn't_
> the smallest Bitmap possible, a 16, 24 or 32-bit 1*1 Bitmap would actually
> be 8 bytes smaller due to the way they store their data and palette, but
hey
> ;)
> As such when you pass your newly created DC to CreateCompatibleBitmap(),
it
> queries the internal Bitmap (The 1*1*1 placeholder) and assumes that you
> want it to create a Bitmap compatible with that, i.e. another 1-BPP
Bitmap!)
> In this case you don't want a 1 BPP Bitmap since you're wanting to use RGB
> colour in there so we'll need to pass it the handle of another DC with a
> 'good' Bitmap selected into it.  The easiest way of doing this is to pass
it
> the desktop window's DC which you can do with the following:

> '***
> Dim DeskWnd As Long, DeskDC As Long

> DeskWnd = GetDesktopWindow()
> DeskDC = GetDC(DeskWnd)
> bmpOriginal = CreateCompatibleBitmap( _
>     DeskDC, textSize.X, textSize.Y)
> ReleaseDC DeskWnd, DeskDC
> '***

> That should be all you need, if you find any more problems then post back
> here and we'll take another look.
> Hope this helps,

>     Mike

>  -- EDais --

>  - Microsoft Visual Basic MVP -
> WWW: Http://EDais.earlsoft.co.uk/





Tue, 29 Mar 2005 03:40:46 GMT  
 
 [ 5 post ] 

 Relevant Pages 

1. Multiple Text Colors / Fore Colors In A VB4 Text Box

2. Display Only Text Box - Text Color/Background Color

3. How to efficiently filter colors out of a hDC

4. BitBlitting from Picture.hDC to Printer.hDC

5. rich text box & colors

6. Get hDc for controls that don't expose hDc property

7. Q: how to get text name of printer from hDC

8. Printing text to a hDC

9. SetBkColor, SetBkMode

10. Setting a color transparent

11. Whats the deal with BackColor = Color.Transparent ?

12. Transparent Color in Bitmaps

 

 
Powered by phpBB® Forum Software