Link to home
Start Free TrialLog in
Avatar of dbrckovi
dbrckoviFlag for Croatia

asked on

Replace Control's Device Context

Hi!

Is it possible to replace a Device Context (DC in the rest of the question) of some control with my own DC?
My intention is to make some control or window draw in memory, and not on screen.
After this is done, I would do some drawing on that image, and only then return the modified image to the screen.

I need something like this, becouse I'm drawing something to control's surface, but the control gets refreshed very often, so I have to repeat that drawing every time the control is refreshed.
This produces constant blinking of my drawing.
To avoid that, I thought maybe it's possible to refresh and redraw the complete control in memory, and paint the result on screen.

Is it possible?

P.S. Please note that I'm a VB6 programmer, and I know little about other languages. I asked this question here in general grogramming area, becouse I think if it can be done,
then it will probably be done with API's and API's are common to all programming languages.
Avatar of Ryan Chong
Ryan Chong
Flag of Singapore image

Hi,

>>so I have to repeat that drawing every time the control is refreshed. This produces constant blinking of my drawing.
How about applying LockWindowUpdate just before and after your process of drawing the control?

like:

Private Declare Function LockWindowUpdate Lib "user32" Alias "LockWindowUpdate" (ByVal hwndLock As Long) As Long

in your control update procedure:

LockWindowUpdate me.hwnd 'or try control.hwnd

'Your update process goes here..

LockWindowUpdate false 'release lock update

Will this works for your situation?
Avatar of dbrckovi

ASKER

Hi!

Thanks, but it's not working.

I'm trying to BitBlt a background to RichTextBox control using AND operator.

Here's my code:
 - create a Picture box, RichTextBox and a timer
 - assign some picture to picture box
 - paste this code:
'------------------------------------------------------------
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long

Private Const SRCAND = &H8800C6

Dim NewDC As Long
Dim RichTextBox1DC As Long

Private Sub Form_Load()
    Dim lPrevBMP As Long
   
    Me.Show
    DoEvents
   
    RichTextBox1DC = GetDC(RichTextBox1.hwnd)
    NewDC = CreateCompatibleDC(RichTextBox1DC)
    lPrevBMP = SelectObject(NewDC, Picture1.Picture.Handle)
   
    BitBlt RichTextBox1DC, 0, 0, Picture1.Width / Screen.TwipsPerPixelX, Picture1.Height / Screen.TwipsPerPixelY, NewDC, 0, 0, SRCAND

    Timer1.Interval = 100
End Sub

Private Sub RichTextBox1_Change()
    RichTextBox1.Refresh
    BitBlt RichTextBox1DC, 0, 0, Picture1.Width / Screen.TwipsPerPixelX, Picture1.Height / Screen.TwipsPerPixelY, NewDC, 0, 0, SRCAND
End Sub

Private Sub Timer1_Timer()
    If Len(RichTextBox1.Text) < 1000 Then
        RichTextBox1.Text = RichTextBox1.Text & "X                     "
    Else
        RichTextBox1.Text = ""
    End If
End Sub
'--------------------------------------------------------------------------------------

If I ommit the Refresh line, BitBlt will "mix" with the image that was there before, but if I enable it, it blinks.
So I thought maybe I can refresh the control im memory, BitBlt the background there, and paint only the final result.

P.S.
Please, don't look for some ActiveX controls which act like RichTextBox and suport background picture. This is not the purpose of my question.
The purpose is to add a background image to any control which normaly has white background, and black text.
Avatar of IceColdas
IceColdas

i think you have 2 ways to do that
1) in the paint event of the control add your code which draws
2) create a custom class for that component and override the paint method
ASKER CERTIFIED SOLUTION
Avatar of Ryan Chong
Ryan Chong
Flag of Singapore image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi!

IceColads:

1) In order for my method to work, the background has to be white. This means that, even if I put it in Paint event, the control has to refresh itself before I can call BitBlt.
2) How do I create a custom class for it? Note that I'm programming in VB6. (I know how to create a class, but I don't see how this can help)

ryancys:

It looks promissing, but it doesn't work. Even the demonstration project doesn't work.
It seems that author screwed up somewhere, becouse VB says SSubTimer6.EMsgResponse type is not defined, and SSubTimer6 class is supposed to be in SSubTmr6.dll file,
which I downloaded, registered, and included in te project.
However, in Object Browser I can see that everything exists.
Hi dbrckovi,

I had tested out the example there, it works for me under WinXP Pro SP2 with VB6.

You may miss something out there? Not sure.. try follow the instructions there.

regards
I probably missed something. I'll try to track down the problem.

Even if I don't make it work, this link contains tons of usefull code, and I'll give you some points for that.

In the meanwhile, I'll leave this question open if someone comes up with something.

I just can't let go of the idea that this can be done by manipulating control's DC in some way. :-)
I mean, in DOS, you could draw something completely in memory, and display only the result. (Maybe DOS is not the best OS for comparing with Windows, but it makes sense)
I think there has to be something similar in Windows.
'----------------------------------------------------------------------------------

Ok. If this is not possible than can you explain to me why the following doesn't work?

I've red that every DC is made of few objects which define it's behaviour. Some of them are Bitmap, Text, Brush, Pen etc.
To assign some object to a DC, we use SelectObject API.

Then why doesn't this work:?
lPrevBMP = SelectObject(RichTextBox1DC, Picture1.Picture.Handle)             '(return value is 0)

Why does it work with NewDC, and not with RichTextBox1DC?
Note that NewDC is created using :        NewDC = CreateCompatibleDC(RichTextBox1DC)

If both DC's are compatible, then why does it work with one, but doesn't with another?
I tested your code, ya, it did blinking on GUI.. i did try to amend your code but no luck so far, hmm...
i dont know if it works in VB6
but in .NET you can declare a class to inherit a certain control.
i.e. class myCustomButton : Button
{
    protected override Paint( ..parameters..)
   {
      //draw the control
   }
}
I've never done anything similar in VB6, and I wouldn't surprise if it wasn't possible.

Although, I might be wrong. (Just becouse I didn't have contact with it, doesn't mean that it's impossible)

OK.
I managed to make it work under VB6 IDE. I don't know what I was missing, but it just worked at one point.
Yesterday night we lost power so my comp got restarted after few weeks of working, and I think this was the reason why it suddenly worked.

Method is still not perfect, but it gives me a lot of code to learn from, and that's why I'm accepting your answer.

Thanks.