?
Solved

Creating a Transparent "Canvas" Over Form

Posted on 2003-03-01
59
Medium Priority
?
444 Views
Last Modified: 2013-12-26
Hello all.

I am trying to create an application that has a transparent "canvas" (or "layer") over a WebBrowser control.  While being able to see the contents of the WebBrowser control, users could scrible on this canvas.

It would be as if the web page being displayed was the background image to a PictureBox control.  Using GDI API calls, the user could then draw on the control to highlight important information.

I've tried a PictureBox.  While I can get it be transparent (which makes me wonder, since MSDN says I can't do that), the PictureBox.Refresh and PictureBox.Cls will destroy the transparency.  For one reason or another, I can not get it transparent again after calling either one of those.

I've tried creating a custom control, but I don't seem to have access to a hWnd or a hDC to use for drawing.

Can I create a transparent control that will allow me to use the API drawing calls to scrible on it, while the controls under it are still visible?

Many thanks for any help!

Ecks

P.S.
I only have 150 available to me at the moment, but if I can get this figured out by Monday I will gladly up the point value when I have more!
0
Comment
Question by:Ecks
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 24
  • 19
  • 11
  • +1
59 Comments
 
LVL 1

Author Comment

by:Ecks
ID: 8049205
Thought I would throw a few links out that I had found around:

http://www.experts-exchange.com/Programming/Programming_Languages/Visual_Basic/Q_20175501.html
Asks a very similar question (if not the exact same).  It points to the following web address:

http://support.microsoft.com/default.aspx?scid=KB;en-us;q185626
Which says it can't be done and mentions a few tips on working around it.  It points to here:

http://support.microsoft.com/default.aspx?scid=kb;EN-US;185882
But that doesn't help me draw on the object -- just get a transparent layer.

The second link does say this under the resolution:
"... To work around this problem, you can replace the PictureBox control with a custom or third party control that offers the same basic functionality as the PictureBox control but does not exhibit the same SetWindowLong limitation."

So, maybe my question is:
"How do I create a custom control that offers the same basic functionality as the PictureBox control, but does not have the same transparency limitation?" :)

Thanks again for any pointers!!
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049256
Try refreshing the WebBrowser control after clearing the PictureBox.
0
 
LVL 1

Author Comment

by:Ecks
ID: 8049356
Thanks magglass1,

That kind of works, but isn't I can do in this case.  When scribling on the PictureBox I'd have to refresh the browser everytime the a PictureBox.Refresh is fired.  Using a free draw tool (like a pencil) would require a browser refresh at least once millisecond... unless you draw *really* slow. :)

I did try it, and the browser does pop back up.  But I see green (the PB background color) more then I see the browser.

Ecks
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 5

Expert Comment

by:Rhaedes
ID: 8049417
Since you are using a webbrowser control, a different approach is to feed it some JavaScript once the page has loaded to allow the user to 'draw' directly over/into the webbpage (using DHTML) and/or to make the webpage editable so the the user can add notes.
When you say 'scribble' what do you mean exactly? Do you mean text, or do you mean draw free-hand with the mouse? Or both? If you mean text, is it enough that the user can insert text, or would the text have to 'float' over the page? Finally, perhaps all you need is a way of letting the user select something in the HTML document and highlight it.

All of this is achievable, but the difficulty varies, so please be as specific as possible with what you require.

Kindest regards,
Rhaedes
0
 
LVL 1

Author Comment

by:Ecks
ID: 8049465
By "scribble" I mean free draw, text, polygon drawing... and anything else we decide would make a good tool. :)  I, in effect, want to make a Paint program that is transparent.

Can't use DHTML because of several reasons.  Not always being in control of the source document is an easy reason.  Needing to save and load the data points (for playback at any time) is another.

Ecks

P.S.  Is there another forum that I might post a similar question to?  Although I'm using the control in VB (and also in VBA), what might be a good group to post a question of the creation of new control?
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049586
Why do you need to refresh or clear the PictureBox in the first place?  Doesn't the drawing automaticaly get displayed?  Or do you have to refresh as they are drawing?
0
 
LVL 1

Author Comment

by:Ecks
ID: 8049660
If PictureBox.AutoRefresh is set to True; PictureBox.Refresh must be called after each GDI reference, or the graphic will not show up.

If PictureBox.AutoRefresh is set to False; the image will show up, but any movement of the canvas (minimize, maximize, resize, move, etc...) will force a redraw and ... *poof* ... everything disappears.
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049710
Then don't move the canvas. :-) Or if you do, then have it refresh, but only then.
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049715
You would have to set up a routine to sense when the canvas is minimized, maximized, resized, or moved.
0
 
LVL 5

Accepted Solution

by:
JohnMcCann earned 600 total points
ID: 8049719
First

I've tried creating a custom control, but I don't seem to have access to a hWnd or a hDC to use for drawing

These propertys are only available when the usercontrol has these proertys set.

a) WindowLess = False
b) HasDc = true

I know a very neat and easy trick for making transparent UserControls.

I'll explain how then i'll paste the code at the bottom.

We are going to create a usercontrol and use it's mask property to mask out the back color. How we do the is actualy quite simple first we lock the window so that the user does not see anything.  Then we draw the usercontrol as normal.  Take a screenshot  of the controls draw canvas.  We then use the picture of the usercontrol as the maskpicture and tell the usercontrol to mask out the backcolor which leaves anythong you've added or drawn.

In order to prove it works when you create your usercontrol add something to it and make sure it is a different color to the usercontrol.  

1) Create a usercontrol.
2) Set the propertys as above (Should be defaults).
3) Set the AutoRedraw = True
4) Copy the following code straight into the usercontrol code module.


Option Explicit

Private Const RC_PALETTE As Long = &H100
Private Const SIZEPALETTE As Long = 104
Private Const RASTERCAPS As Long = 38

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(7) As Byte
End Type

Private Type PicBmp
    Size As Long
    Type As Long
    hBmp As Long
    hPal As Long
    Reserved As Long
End Type

Private Type PALETTEENTRY
    peRed As Byte
    peGreen As Byte
    peBlue As Byte
    peFlags As Byte
End Type

Private Type LOGPALETTE
    palVersion As Integer
    palNumEntries As Integer
    palPalEntry(255) As PALETTEENTRY ' Enough for 256 colors
End Type

Private Declare Function LockWindowUpdate Lib "user32" (ByVal hwndLock As Long) As Long
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 CreateCompatibleBitmap Lib "GDI32" (ByVal hDC As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateCompatibleDC Lib "GDI32" (ByVal hDC As Long) As Long
Private Declare Function CreatePalette Lib "GDI32" (lpLogPalette As LOGPALETTE) As Long
Private Declare Function DeleteDC Lib "GDI32" (ByVal hDC As Long) As Long
Private Declare Function GetCurrentObject Lib "GDI32" (ByVal hDC As Long, ByVal uObjectType As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "GDI32" (ByVal hDC As Long, ByVal iCapabilitiy As Long) As Long
Private Declare Function GetSystemPaletteEntries Lib "GDI32" (ByVal hDC As Long, ByVal wStartIndex As Long, ByVal wNumEntries As Long, lpPaletteEntries As PALETTEENTRY) As Long
Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" (PicDesc As PicBmp, RefIID As GUID, ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long
Private Declare Function RealizePalette 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 Declare Function SelectPalette Lib "GDI32" (ByVal hDC As Long, ByVal hPalette As Long, ByVal bForceBackground As Long) As Long

Private m_Initializing              As Boolean

Private Sub UserControl_Initialize()
   m_Initializing = True
End Sub

Private Sub UserControl_InitProperties()
   m_Initializing = False
   pDraw
End Sub

Private Sub UserControl_Paint()
   If Not m_Initializing Then pDraw
End Sub

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
   m_Initializing = False
   pDraw
End Sub

Private Sub UserControl_Resize()
   If Not m_Initializing Then pDraw
End Sub

Private Sub pDraw()
On Error GoTo Err_Handler

Static bPainting As Boolean

Start_Painting:
   If bPainting Then Exit Sub
   bPainting = True
   LockWindowUpdate hWnd
   With UserControl
      If .MaskPicture <> 0 Then Set .MaskPicture = Nothing
      If .BackStyle <> 1 Then .BackStyle = 1
      If .ScaleMode <> vbPixels Then .ScaleMode = vbPixels
      .Cls
   End With
   DoEvents
         
Draw_Mask:
   Set UserControl.MaskPicture = CreatePictureFromDC(hDC, 0, 0, ScaleWidth, ScaleHeight)
   UserControl.MaskColor = UserControl.BackColor
   UserControl.BackStyle = 0
   
Exit_Handler:
   LockWindowUpdate False
   bPainting = False
   Exit Sub
   
Err_Handler:
   MsgBox TypeName(Me) & " - " & "pDraw" & " - " & Err.Description
   Resume Exit_Handler
End Sub

Private Function CreatePictureFromDC(ByVal hDCSrc As Long, ByVal LeftSrc As Long, ByVal TopSrc As Long, ByVal WidthSrc As Long, ByVal HeightSrc As Long) As Picture
Dim hDCMemory As Long, hBmp As Long, hBmpPrev As Long
Dim hPal As Long, hPalPrev As Long, RasterCapsScrn As Long
Dim HasPaletteScrn As Long, PaletteSizeScrn As Long
Dim typLogPal As LOGPALETTE

    hDCMemory = CreateCompatibleDC(hDCSrc)
    hBmp = CreateCompatibleBitmap(hDCSrc, WidthSrc, HeightSrc)
    hBmpPrev = SelectObject(hDCMemory, hBmp)

    RasterCapsScrn = GetDeviceCaps(hDCSrc, RASTERCAPS) ' Raster
    HasPaletteScrn = RasterCapsScrn And RC_PALETTE ' Palette
    PaletteSizeScrn = GetDeviceCaps(hDCSrc, SIZEPALETTE) ' Size of

   If HasPaletteScrn And (PaletteSizeScrn = 256) Then
      typLogPal.palVersion = &H300
      typLogPal.palNumEntries = 256
      GetSystemPaletteEntries hDCSrc, 0, 256, typLogPal.palPalEntry(0)
      hPal = CreatePalette(typLogPal)
      hPalPrev = SelectPalette(hDCMemory, hPal, 0)
      RealizePalette hDCMemory
   End If

   BitBlt hDCMemory, 0, 0, WidthSrc, HeightSrc, hDCSrc, LeftSrc, TopSrc, vbSrcCopy
   hBmp = SelectObject(hDCMemory, hBmpPrev)
   
   If HasPaletteScrn And (PaletteSizeScrn = 256) Then
      hPal = SelectPalette(hDCMemory, hPalPrev, 0)
   End If
   
   DeleteDC hDCMemory

   Set CreatePictureFromDC = CreatePictureFromBitmap(hBmp, hPal)
End Function

Private Function CreatePictureFromBitmap(ByVal hBmp As Long, ByVal hPal As Long) As Picture
Dim typGUID As GUID
Dim typPicBmp As PicBmp
Dim objIPicture As IPicture

    With typGUID
        .Data1 = &H20400
        .Data4(0) = &HC0
        .Data4(7) = &H46
    End With

    With typPicBmp
        .Size = Len(typPicBmp)
        .Type = vbPicTypeBitmap
        .hBmp = hBmp
        .hPal = hPal
    End With

    OleCreatePictureIndirect typPicBmp, typGUID, 1, objIPicture
    Set CreatePictureFromBitmap = objIPicture
End Function




Good luck.

P.S. Who says you can't make a usercontrol transparent tell me and I'll send the boys round.
0
 
LVL 1

Author Comment

by:Ecks
ID: 8049767
Thanks JohnMcCann, I'm looking over the code now and going to try it out.

I'm am wondering though, why do all of this and not just change the BackStyle to transparent?  Obviously, there is some reason since I can't get it to work that way. ;)
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8049782
When you set the BackStyle to trasparent it masks out the MaskColor.
0
 
LVL 1

Author Comment

by:Ecks
ID: 8049785
Also, I just added the control to a form and VB goes WACKO! It flickers along with the new control... is it supposed to do that? o.O
0
 
LVL 1

Author Comment

by:Ecks
ID: 8049790
AutoRedraw = True

... got it. :P
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8049812
I knew that was coming
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8049818
Oh if you ever get that problem again problably for that reason close the form realy quick and it shouldn't crash.
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049824
I am lost now...  So is it working or do you still need help?  Did you read my last post?
0
 
LVL 1

Author Comment

by:Ecks
ID: 8049825
Sorry for the e-mail flood. :(

Ok, got it up and it is indeed transparent (sweet!), but I still can't seem to get a hDC or hWnd reference.

When I type in the control name, neither property is listed in the pop up window.  If I do ahead and type it in anyway, I get the following error:

    Method or data member not found.

The code that produces this:

    Debug.Print SlideCanvas1.hDC

WindowLess is False
HasDC is True

Oh, and I'm still not sure I understand (totally) the different between BackStyle=Transparent and what this is doing... but I trust ya. :)
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049835
I was just about to comment on the email...  Nothing bad though...
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8049838
You need to add them proertys to the usercontrol


Public Property Get hDC() As Long
   hDC = UserControl.hDC
End Property

Public Property Get hWnd() As Long
   hWnd = UserControl.hWnd
End Property
0
 
LVL 1

Author Comment

by:Ecks
ID: 8049842
magglass1:

Still trying to work things out. :)

Because of the way the data is presented, I really have to have AutoRedraw turned on.  The issues I am having here are during a "playback" feature, which streams data out of a file (because of the amount of data, putting it in memory isn't a good idea).  Attempting to relocate the data that needs to be redrawn really isn't possible.
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049845
I am bored here.  Trying to work on my new program, but I have no points to ask for help.  And it is 0204 in the morning which doesn't help much.
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8049861
magglass1,

Ask your Q anyway, I don't do it for points
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8049863
Because of the way the data is presented, I really have to have AutoRedraw turned on.  The issues I am having here are during a "playback" feature, which streams data out of a file (because of the amount of data, putting it in memory isn't a good idea).  Attempting to relocate the data that needs to be redrawn really isn't possible.

I thought AutoRedraw was on.

If you explain a little better I may know another work round
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049879
Ok John, thanks.  Here is my question.
I am working on an IM Server app. and client app.  I am looking for the best way for them to communicate via TCP by sending strings.  For example, if the server sent the client data, it would have to sort out commands like a ping and sort out IMs from different users.  I could add headings to the strings like "Message:text" but I wouldn't know how to take away the substring "Message:"  Also, it would need to include the from address.  And if I did "From:User1Message:hello:  I could get into problems if the text included any of theses words I am using, unless I make Message: always the last command.  I have no clue how AIM works, and that would probably help me out a bit.  If you have any good meathods for sending and sorting this data, please advise me.
Thanks again.
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049887
You should see my Deleted Items folder in Outlook.  It looks a bit redundant...
0
 
LVL 1

Author Comment

by:Ecks
ID: 8049914
It is on John, I was refering to earlier posts. :)

Ok, I have the user control up and it is kind of working.  Unfortunately I can't see any of the drawings! :(

I am calling the following GDI function several times from a function:
    LineTo hDC, X, Y

It is given the new control's hDC and a proper X/Y, but as the line is supposed to show up... it doesn't.  I thought that "Refresh" might be the issue, so I added the following to my control:

Public Function Refresh()
    UserControl.Refresh
End Function

Still nothing show up.

When I resize, there is a glitch that forms (a line from 0,0 to the current x/y set) -- I'm not concerned about that right now, but when the above "LineTo" call passes through this glitch, you can see the line change.  In other words -- the graphics show up on the glitch, but not on the canvas.

Any ideas?

Thanks for all the help!
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8049949
Ecks,

First the control is making itself transparent then you draw on it and then it makes itself transparent again.  If that made any sense.  So anything you draw on the contyrol is never shown

In order for you to do what you are asking you need to move the methods into the UserControl but bear in mind the logic for drawing apears in the pDraw method..  I can tell you Line is going to be a pain.  i remember seeing an earlier post about the line method and Usercontrols.

I will see if I can find the post for you.
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8049962
magglass1,

I am not to familar with what you are asking.


0
 
LVL 1

Expert Comment

by:magglass1
ID: 8049997
I just need a way to convert a string like "To:BobMessage:Hello!" into the string 'to' which = "Bob" and the string 'message' which = "Hello!"
0
 
LVL 1

Author Comment

by:Ecks
ID: 8050038
John,

I figured it was making itself transparent again.  Just wasn't sure how to fix it. :)

So, I have two function at the moment:

drawPencil -- which just wraps around LineTo
drawArrow -- constructs a Polygon region shaped like an arrow

I send in an "Action" that include a Enum number that tells me which function to call.  Do you have any suggestions on how I can transfer that information into the control so it does the right thing?
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050061
magglass1,

Have a play with these function


VBA.Left()    ' gets text at the left hand side of string
VBA.Mid()    ' Gets text in the middle of a string
VBA.InStr()  ' Identifys where a charcter is in  a string
VBA.Right()  '

Also if you goto into visual basic goto the view menuy -> object browser.  Thenb select VBa from the first drop down combo and select strings from the list at the bottom these are all the in built string functions.
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050078
One possible metod may be to store the user actions in an array and call them during draw.

Example

Private Type MyDrawPencilStruct
   Left as integer
   Etc
End Type

Private Type MyDrawArrowStruct
   Left as integer
   Etc
End Type

drawPencils() As MyDrawPencilStruct
intDrawPencilCount as integer
drawArrows() As MyDrawArrowStruct

Public sub drawPencil()
  intDrawPencilCount = intDrawPencilCount + 1
  Redim drawPencil(intDrawPencilCount)
  with ubound(drawPencils)
     .Left = 0 ' Left is just an example  
  End with
  pDraw
End sub


Private Sub pDraw()
On Error GoTo Err_Handler

Static bPainting As Boolean

Start_Painting:
  If bPainting Then Exit Sub
  bPainting = True
  LockWindowUpdate hWnd
  With UserControl
     If .MaskPicture <> 0 Then Set .MaskPicture = Nothing
     If .BackStyle <> 1 Then .BackStyle = 1
     If .ScaleMode <> vbPixels Then .ScaleMode = vbPixels
     .Cls
  End With
  DoEvents

Draw_Pencils:

Draw_Arrows:
       
Draw_Mask:
  Set UserControl.MaskPicture = CreatePictureFromDC(hDC, 0, 0, ScaleWidth, ScaleHeight)
  UserControl.MaskColor = UserControl.BackColor
  UserControl.BackStyle = 0
   
Exit_Handler:
  LockWindowUpdate False
  bPainting = False
  Exit Sub
   
Err_Handler:
  MsgBox TypeName(Me) & " - " & "pDraw" & " - " & Err.Description
  Resume Exit_Handler
End Sub



0
 
LVL 1

Author Comment

by:Ecks
ID: 8050123
Hm... I was afraid of that.  Potentially a lot of data to be storing in an array.  I can clear them out at each page change though, so it should be too bad.

Just glancing at the code above, it looks like this has to redraw the whole control every time a new pencil/arrow is drawn.  Am I seeing that right?  Course, I think I do that anyway with my 'Refresh' calls, so I don't know why I'm stressing about it. :)

Thanks again!  I'll give the code a try after I let me brain cool down some.
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050159
You are correct about the whole thing being redrawn.

The code is taking a picture of the control with it's backcolor to create the mask then all the code does is remove that color.
0
 
LVL 1

Author Comment

by:Ecks
ID: 8050520
Want to make one last check to see if I might be missing something here:

added this function:
Public Function addPencil(X As Long, Y As Long, nColor As Long)
    PencilToolCount = PencilToolCount + 1
    ReDim PencilToolArray(PencilToolCount)

    With PencilToolArray(PencilToolCount)
        .X = X
        .Y = Y
        .nColor = nColor
    End With

    pDraw
End Function


To work with these variables:
Private Type PencilTool
    X As Long
    Y As Long
    nColor As Long
End Type
Private PencilToolArray() As PencilTool
Private PencilToolCount As Long

Finally added this to 'pDraw' where you specify above:
Draw_Pencils:
    For i = 1 To PencilToolCount
        With PencilToolArray(i)
            UserControl.Line -(.X, .Y), .nColor
        End With
    Next i

Does that look like what you would do?
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050562
Yeap

Did it work ok?
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050634
The method I have been using above is based on a copy of the DC.  To do this properly we should be invering the DC.  I know my method works and one day I will get round to writing the correct function.  The function in question is CreatePictureFromDC which needs to be CreateMaskFromDC.  I use the CreatePictureFromDC function more for doing screen captures of any DC (for creating manuals).
0
 
LVL 1

Author Comment

by:Ecks
ID: 8050640
Nope. o_O

Actually, it works to a point.  The 'Line' function doesn't exactly work, but I think the problem is simply that I am not update the 'CurrentX' and 'CurrentY' positions.

The real problem is that the control flickers.  I am just sending so many requests to it that it can't keep up -- I'm seriously sending it a request every few milliseconds when the pencil is active.  It is kinda hypnotic really.  The drawing really slows down as a result too -- during playback, I get all the way through my slides but the drawing is only half way there. :)

I wrote the code for the Arrows too.  While there is a glitch there too (I just ported code, so I probably didn't change something) they do actually work.

So... all your stuff works great!  My stuff doesn't. ;)

I've got another plan in my head -- based in part on the 'pDraw' code you posted, and some custom ActiveX control work I've been trying.  I have to decide if I'm still sane enough to attempt it tonight.
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050671
The correct function for creating the mask may help (CreateMaskFromDC).  As the mask picture should be a lot smaller.

I've been meaning to do it for sometime and may do tommorow.  If i create the code I will post it for you to try and see if that makes a difference.

I've just had one last thought bear  with me for 10mins
0
 
LVL 1

Author Comment

by:Ecks
ID: 8050681
Many thanks for all the info!

I was wondering too, could you help me to understand why simply putting the BackStyle of a control to "Transparent" doesn't work?

When I have it as Opaque, I can draw on it.  But when I set it to Transparent, none of the drawing shows up.  I thought BackStyle just cut out the background color.  Does it also (in effect) remove parts of the control that do not have anything on them?
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050684
Your problem will stem from the control being redrwn som any times as you stated.  As aa new mask is created each time.

Unfortunatly I cannot see anyway around this as every mask needs to be different.

0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050700
When you set the BackStyle to transparent it uses the picture you set as the transparent picture and the color you set as the transparent color.

In the above case we create the mask picture from the DC.
And set the maskcolor to the backcolor effectively removing any of the background left after drawing.
0
 
LVL 1

Author Comment

by:Ecks
ID: 8050857
Thanks John, I get it now. :)

I've already tried and failed on another attempt; working with a PictureBox in a custom ActiveX control.  I can't get the PictureBox transparent though, which is frustrating as that would have been a great way to do it.

Now I'm on to a new attempt here.  I am using a PictureBox with AutoRedraw set to False and things are showing up.  In order to get this method to be usable though, I need to work with the Paint event to redraw items when needed.

When working with the Paint event, can I get access to the the dimensions of the region needing to be updated; or am I stuck with repainting the whole thing?
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050900
I don't think you can directly in the usercontrol I think you need to be subclassing.

How do you make the PictureBox transparent?

Another way may be

1) Create a usercontrol as before.
2) Create a memDC
3) Work with the memDC for creating the transparent image.
4) BitBlit or PaintPicture on to the DC during the paint function.
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8050908
Another function that may be of help

Private Declare Function TransparentBlt Lib "msimg32.dll" (ByVal hdc 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 nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal crTransparent As Long) As Boolean

Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long) As Long

Typical usage

TransparentBlt(Picture2.hdc, 0, 0, Picture2.ScaleWidth, Picture2.ScaleHeight, Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, GetPixel(Picture1.hdc, 0, 0))

Masks out all pixels of a given color.

Typically GetPixel(SourceDC,0,0) 'Top left pixel.
0
 
LVL 1

Author Comment

by:Ecks
ID: 8051010
> How do you make the PictureBox transparent?

Top side defines:
'** form transparency declarations *'
Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

'** form transparency constants *'
Private Const WS_EX_TRANSPARENT = &H20&
Private Const GWL_EXSTYLE = (-20)

The actuall (in Initialize):
Call SetWindowLong(picBox.hWnd, GWL_EXSTYLE, WS_EX_TRANSPARENT)

-----------

If you check out the second link, in the second message, it actually says this doesn't work.  The only time this method has failed for me though is when using code from the MSDN site (and when not using a direct PictureBox or Form, like a custom control).

The transparency disappears very easily on a PictureBox though.  Transparency on a form is a little more stable, but I can break it really quick if I want (or don't want, more often). :)

I can't seem to get the TransparentBlt function working.  I am making the following call...

Call TransparentBlt(SlideCanvas.hdc, 0, 0, SlideCanvas.ScaleWidth, SlideCanvas.ScaleHeight, Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, GetPixel(Picture1.hdc, 0, 0))

Picture1 is loaded with a 5x5 pink bitmap, the scalewidth is also 5x5 pixels

I've tried setting SlideCanvas to all pink background, and I've loaded the same 5x5 bitmap into it as well.  Can't get the pink to disappear.  I'm looking around at a few sites, but I'm afraid I'll just end up seeing the background of the PictureBox, and not what is behind it. :(

Thanks again for all the help!
0
 
LVL 5

Expert Comment

by:Rhaedes
ID: 8051356
Wow. I woke up this morning to find 45 new emails from this question alone. You guys have been busy!
I see you're pretty advanced with this, so I'll just sit out, but for the record, Ecks, the two objections you state for not using DHTML are not really valid. DHTML is client-side, so you can feed the Script into the document AFTER it is loaded, even though you do not have control over the source. Also, there are different ways of 'recording' the modifications made, so that they will 'play back' when you navigate to the same page again. Moreover, a quick google search will come up with free script that will draw shapes etc on your document, which you can use from VB.
I understand you don't want to use DHTML, so that's fine, but if you want some demo code to prove what I am suggesting is possible, I'll be happy to provide it!

Kindest regards,
Rhaedes
0
 
LVL 1

Expert Comment

by:magglass1
ID: 8051370
Thanks John, will try out those string functions.
0
 
LVL 1

Author Comment

by:Ecks
ID: 8051681
Rhaedes,

If you know of some demo code, I would love to see it.
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8051696
Ecks,


There was an ewrror in one of the posts they may cause you problems

Redim drawPencil(intDrawPencilCount)
 

Should be

Redim Preeserve drawPencil(intDrawPencilCount)

Sorry.

Otherwise you will always only have the last pencil drawn in the array.
 
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8051708
Call TransparentBlt(SlideCanvas.hdc, 0, 0, SlideCanvas.ScaleWidth, SlideCanvas.ScaleHeight, Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, GetPixel(Picture1.hdc, 0, 0))

Looks ok

Check the AutoRedraw and if it is set to false are you calling refresh.


Just remembered I think you may need to call DoEvents first to get thet transparency

0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8051734
An example of TransparentBit

Create a new exe
Add two picture boxes
Add a picture with a lot of backcolor in it to pic1
Set both there scalemodes to vbPixels
Make sure Pic2 AutoRedraw = False (For this example)

Paste code into code window

Private Declare Function TransparentBlt Lib "msimg32.dll" (ByVal hdc 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 nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal crTransparent As Long) As Boolean
Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long) As Long

Private Sub Form_Load()
    Picture1.ScaleMode = vbPixels
    Picture2.ScaleMode = vbPixels
End Sub

Private Sub Picture2_Paint()
    DoEvents
    TransparentBlt Picture2.hdc, 0, 0, Picture2.ScaleWidth, Picture2.ScaleHeight, _
            Picture1.hdc, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, GetPixel(Picture1.hdc, 0, 0)
End Sub



0
 
LVL 5

Expert Comment

by:Rhaedes
ID: 8051748
Okay, I'll knock up some code for the DHTML approach and post it. One other thought: what about converting the HTML into RTF (using say http://www.cena.dgac.fr/~sagnier/info/formats/conversions/htm2rtf.htm ) and then simply drawing in it?

Kindest regards,
Rhaedes
0
 
LVL 5

Expert Comment

by:Rhaedes
ID: 8053335
Okay, here's the DHTML approach. I insist that this is just for example's sake: to show that it is possible to do, and that you can 'playback' what you record. It's simple and memory hungry, but was fast to write!
As it stands, it just lets you draw lines freehand over the document in different colours. Whenever you navigate back to a page you have previously scribbled on, the scribbles appear again as they were when you left the page.
With a little more time, you can add anything you want, from drawing shapes to adding boxes with notes (see http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm for some nice free script).

First create a directory somewhere to keep the scribble logs and change the LogDir line in the Form_Load sub accordingly.
Then take a form, and add the following:
-a webbrowser (WebBrowser1).
-a TextBox (Text1). This is where you type your URL
-a commandbutton (Command1). This is the button you press to make the webbrowser navigate to the URL in Text1. (Alternatively just hit return in the textbox)
-a ComboBox (Combo1). This is to change the colour of the scribbles.

Add the HTML Object Library, and paste the code below into a form.

Kindest regards,
Rhaedes



Private WithEvents Hdoc As HTMLDocument
Dim LogDir As String
Dim CurrentURL As String
Dim MouseIsDown As Boolean
Dim myScribbles As String

Private Sub Command1_Click()
WebBrowser1.Navigate2 (Text1.Text)
End Sub

Private Sub Form_Load()
LogDir = "c:\SOMEWHERE\myLog\" 'Must have final slash!

Combo1.AddItem ("red")
Combo1.AddItem ("green")
Combo1.AddItem ("blue")
Combo1.AddItem ("black")
Combo1.ListIndex = 0

Text1.Text = "http://www.google.com"
Command1_Click

End Sub

Private Sub Form_Unload(Cancel As Integer)
On Error Resume Next
Print #1, myScribbles
Close #1
End Sub

Private Sub Hdoc_onmousedown()
MouseIsDown = True
End Sub

Private Sub Hdoc_onmouseup()
MouseIsDown = False
End Sub

Private Sub Hdoc_onmousemove()
If MouseIsDown = False Then Exit Sub
Freehand
End Sub

Private Sub Freehand()
myX = Hdoc.parentWindow.event.clientX
myY = Hdoc.parentWindow.event.clientY

myXoffset = Hdoc.body.scrollLeft
myYoffset = Hdoc.body.scrollTop

newpoint = "<div style=""color:" + Combo1.Text + ";position:absolute;top:" + Str(myY + myYoffset - 6) + ";left:" + Str(myX + myXoffset - 6) + """>*</div>" + vbNewLine
Hdoc.body.innerHTML = Hdoc.body.innerHTML + newpoint
myScribbles = myScribbles + newpoint
End Sub

Private Sub Text1_KeyPress(KeyAscii As Integer)
If KeyAscii = 13 Then Command1_Click
End Sub

Private Sub WebBrowser1_DocumentComplete(ByVal pDisp As Object, URL As Variant)
On Error Resume Next
Print #1, myScribbles
Close #1
CurrentURL = Replace(URL, ":", "")
CurrentURL = Replace(CurrentURL, "/", "")
Set Hdoc = WebBrowser1.Document
If Dir(LogDir + CurrentURL + ".txt") <> "" Then Replay
Record
End Sub

Private Sub Record()
Open (LogDir + CurrentURL + ".txt") For Output As #1
End Sub

Private Sub Replay()
Open (LogDir + CurrentURL + ".txt") For Input As #1
Do While Not EOF(1)
Line Input #1, someHTML
Hdoc.body.innerHTML = Hdoc.body.innerHTML + someHTML
myScribbles = myScribbles + someHTML
Loop
Close #1
End Sub
0
 
LVL 5

Expert Comment

by:Rhaedes
ID: 8053451
...Even easier, why not convert the HTML file to an image, and then scribble over the image. Since in your original proposal I don't think you can use the links etc in the file (you can with the DHTML approach) why not simply do a google search for one of the many HTML2JPG apps and dlls out there. Just thinking out load. And I think John deserves the points whatever you decide to do.

Kindest regards,
Rhaedes
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8129206
I have another though that may solve your problem.

Basically it involves drawing stright onto the mask.

How I would it is first create your mask during the initalize event and during the Draw event update your mask.


0
 
LVL 1

Author Comment

by:Ecks
ID: 8129284
Thanks John,

I was thinking about this the other day and how I need to close it out -- thanks for reminding me. :)

I've actually moved away from this problem at the moment, to work on learning the new goodies in Windows Media 9, so I still don't have it solved just right.  The accepted answer helped me understand the most about the paint process though, so I snagged that for an answer.

I'll give the last suggestion a shot when I fix all our new problems. o_O

Thanks again everyone!
0
 
LVL 5

Expert Comment

by:JohnMcCann
ID: 8129323
No problem
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction While answering a recent question (http://www.experts-exchange.com/Q_27402310.html) in the VB classic zone, I wrote some VB code in the (Office) VBA environment, rather than fire up my older PC.  I didn't post completely correct code o…
When designing a form there are several BorderStyles to choose from, all of which can be classified as either 'Fixed' or 'Sizable' and I'd guess that 'Fixed Single' or one of the other fixed types is the most popular choice. I assume it's the most p…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…
Suggested Courses
Course of the Month13 days, 4 hours left to enroll

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question