Link to home
Start Free TrialLog in
Avatar of tezi
tezi

asked on

Erasing certain portion of picture box from Transparent Blit function

I have two picture boxes Pic1 and pic2 and pic2 is inside pic1.
I call a transparent blit function to make pic2 appear in pic1 as transparent:
TransparentBlt pic1.hdc,pic1.hdc,pic2.hdc,R,40,0,vbWhite

I can let the user changes pic2  through a command button and everytime it is changed, i can just pic1.cls and call the transparent blt function again with new coordinates.
But the PROBLEM is i also let the user modify pic1 (as in Paint) whereby the user can draw lines or dots on pic1.
So how can I keep track of what is drawn just now so that when i cls the pic1, i still get the existing picture with whatever which was drawn and only pic2 changes?
Or how do I just erase that certain portion of pic2 which is blit on pic1?

pls help!
Avatar of Mirkwood
Mirkwood

Not very clear question.
Why not keep the original of pic1 stored somewhere else.
So pic1 is the original
So pic2 is the modified pic1
and pic3 is the transparent version
You might also disable the mouse while it's over the picture box... set the "Locked" property to True, or otherwise prohibit mouse entry into the picture box.

Just an idea...
You might try setting Pic1's AutoRedraw property to True.  However,  this could interfer with your users drawing on it in the first place (but it is easy enough to try).
Avatar of tezi

ASKER

What I want is:
pic1 now contains pic2 which has been blit transparently on pic1. So now I would like the user to be able to change the location of pic2 (for example 3 pixels to the right)

But if I call back the transparent blit function, the previous blit picture will still be there and my current pic2 will just overlay on it. I wanted to erase the previous blit picture location.
The cls method does not apply as I can let the user draw on pic1. So if I just cls the pic1, I would lost track of the location of what the user draws.

Any ideas on how to clear that particular portion of pic2? Or is there a method to keep track of what is drawn?
would appreciate if example of codes is given...
Try the following:
-copy of the current contents of pic1 to another picture (paintpicture/bitblt?)
-cls picture1
-copy it backed but now shifted to the right position (paintpicture/bitblt?)
Mirkwood's suggestion is the easiest, but depending on the size of the picture in Pic1 it could be slow, you could amend his suggestion to only bitblt the rectangle that is going to be covered by Pic2 to another hidden picture, do this before you bitblt Pic2 to it's location on Pic1.  Then when you are about to move Pic2 again, bitblt the hidden saved Pic1 rectangle back to it's position in Pic1, bitblt the new rectangle that is going to be covered by Pic2 to the hidden picture, then bitblt pic2 to the new location.

You'll have to keep track of the coordinates of the old location and the new location, but it should be faster bitblt-ing just a small rectangle of Pic1 than the whole contents of Pic1 and this should keep the amount of "flash" down.  

MD
Ok, I couldn't understand the question completely, but it seems to me that the following lines may help you (sorry if you already know what I will say):

When Pic.Autoredraw is set to false, anything you draw on the picture remains visible (as opposed to that when Autoredraw is true, the contents of the picture is reset to the original picture). So, the original contents of the picture is kept in Pic.Picture property and the actual contents in Pic.Image property.
I suppose your Pic.Autoredraw is False as you want to draw on the picture.

Ok, sorry if I've wasted some of your time, but who knows, I may have helped.
Avatar of tezi

ASKER

i haven't try the suggestions yet... but have you all guys taken into account that I need to have the previous blit picture on pic1 removed first, then only i changed the contents of pic2....

just to remind, no overlaying of the blit pictures...

Avatar of tezi

ASKER

mdougan, are you suggesting to me that I should use the bitblt method from the hidden picture to blit exactly on pic1 so that pic1 will be disappear from view?
can you give me example of code to perform this?

The technique I'm talking about is a well known technique for doing animation.  Basically you have a background (in your case this is Pic1) that you want to save a rectangle from.  Then you paint (BitBlt) something (Pic2) on top of that background.  Now, when you want to move Pic2 to another location you need to restore the background to it's previous state, and you do this by copying the rectangle that you saved back to where you had first painted Pic2.  Then you can save background at the next location for Pic2 and so on.  I don't have a code sample, but I'll do a pseudo code example below:

public Sub SaveBackground(X as Long, Y as Long, W as Long, H as Long)

    BitBlt(from Pic1, X, Y, for W, and H, to PicSave, 0, 0, W, H)

end sub

public Sub RestoreBackground(X as Long, Y as Long, W as Long, H as Long)

    BitBlt(from PicSave,0, 0, for W, and H, to Pic1, X, Y, W, H)

end sub    

Then, in your code somewhere say you have a loop that is going to move Pic2 5 times to the right:

Dim i as Integer
Dim X as Long
Dim Y as Long
Dim W as Long
Dim H as Long

W = Pic2.Width
H = Pic2.Height

for i = 1 to 5
     SaveBackground((i * 50), 50, W, H)
     BitBlt(from Pic2, 0, 0, W, Ht, to Pic1, (i*50), 50, W, H)
     Sleep(100)
     RestoreBackground((i*50), 50, W, H)
next i

Now, the things I have as parms for the BitBlt are not correct, they're just there to show you what you are trying to do, you'll have to look BitBlt up to get the correct parms, but this pseudo code should give you the right idea.  Also, since you want to let the user move Pic2 around, you probably wont be doing this in a loop, so you'll need to save the old position of Pic2, and the new position of Pic2 and then do this Save and Restore just before you BitBlt Pic2 to the new location (then move the new position variables into the old position variables for the next time they move.

Hope this helps?

MD
Avatar of tezi

ASKER

well mdougan
i'm almost close to a solution. Just one thing, actually i also allow the user to draw on pic1.
So i thought of saving the pic1.picture which includes the drawn lines  with the SavePicture method but it can't. I guess it only saves the pic1.picture property and not what is drawn on it.
How bout the adjustment of the autoredraw property, should I set it to True or False to save what is drawn?
I tried both ways but still fails to save what is drawn on pic1 to pic1.picture...

does the bitblit method copies what is drawn on the background as well? haven't tried it yet...

just hoping that the above suggestion would work so that I can use the Savepicture method to save the drawn things... and i just change the background just as you suggested.

any comments?
I believe that BitBlt will copy anything that is drawn on Pic1 to the SavePic hidden picture, and then BitBlt back from SavePic to Pic1 will restore what the user has drawn.  But I haven't tried this to be sure.  There is also the chance that if you wanted to save what the user has drawn, that you could BitBlt the whole Pic1 to SavePic, and then (because I think that BitBlt puts the image in the "picture" property, that you could then do a Savepicture on SavePic to save the image to a file.  I'll see if I can test this out sometime today, and I'll be able to confirm or deny it!

I also believe that you want to keep the autoredraw property to false.  Because when you have autoredraw set to true, then VB actually keeps a copy of the original contents of Pic1 in memory, and whenever the screen needs repainting, it repaints Pic1 (so, if you haven't saved what the user has drawn, you would lose it).  I think this would get in the way of what you are trying to do.  However, whenever I'm having trouble with pictures etc. I always try changing that first, just to see if it makes a difference.

I'll get back to you later.

MD
ASKER CERTIFIED SOLUTION
Avatar of mdougan
mdougan
Flag of United States of America 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
Avatar of tezi

ASKER

mdougan,
i still can't get your codes to run, because the NewX,NewY ,OldX and OldY has not been assigned values...
and I am busy at the moment.
so can you give me the whole workable codes with the values of the X and Y?

actually I'm still doubtful whether it will work because what I wanted to use is the Transparent Blit function and whatever is drawn previously can still be seen...

I'm also running out of time to give a working copy to the user...
worst come to worst, I think I'll disable this function until I can get it done.

another thing, where are you actually referring  to for this directory? VB\SAMPLES\COMPTOOLS\CALLDLLS

Thank you for your time.
Hi,

The code I gave you above did work for me in VB 5.0.  As far as not initializing OldX, OldY, NewX, NewY, I was counting on VBs initialization of numeric variables to zero.  So, each of these values starts out at zero.  So, nothing happens until the user presses the left or right or up or down arrows.  When that happens, depending on which arrow was pressed, the value of NewX or NewY is incremented or decremented by 5 (if this wasn't a quick and dirty example, I'd check to make sure that NewX and NewY were not less than zero, and if so, make them zero).

I'm not familiar with the transparent blit function that you are talking about, but I assume that you would use it at the place where I'm blitting Pic2 onto Pic1, and I think everything else should work exactly the same (because you still need to save the background before blitting Pic2 on top of it).  

' Draw pic2 onto pic1
   RC = BitBlt(Pic1.hDC, NewX, NewY, Pic2.Width, Pic2.Height, Pic2.hDC, 0, 0, SRCCOPY)

(replace this call with your transparent blit)

The path I gave you for the sample was slightly wrong.  It should be:
VB\SAMPLES\COMPTOOL\CALLDLLS

where comptool does not have an "s" at the end.  This should be under your VB directory.  By default, VB is installed under Program Files\DevStudio, so, the whole path should be:

C:\Program Files\DevStudio\VB\SAMPLES\COMPTOOL\CALLDLLS

That is assuming that you told VB to install the sample programs when you installed it.  

Make sure you read through my instructions above carefully.  You need to make sure that Pic2 is smaller than Pic1 (and I made SavePic bigger than both) to get this sample to work.

Let me know if you still can't get it to work for you.

MD
Avatar of tezi

ASKER

Hi mdougan,
I still can't get the codes running, I don't know why?! Even the form_keydown event is not working...
Can you just mail me your copy of the testing program?
My email account is
tanyujin@usa.net

Thank you in advance!
I'll look for it, but I think it was on a different development machine.  Check to make sure that your form has the Keypreview property set to true.  

Also, I'm using VB 5.0, so, the declare statements are the 32-Bit versions.  If you are using VB3.O or VB4.0 16-bit, then the declare statements have to change.

MD
Avatar of tezi

ASKER

Hi mdougan

your codes work very perfectly, however there is one big major problem. I also have a few other picture boxes blit on pic1. So when I save the background, I also manage to save them as well. This is a good thing.

The bad thing is when I paste back the background on pic1, the partially "cut" pic3 which is blit on pic1 and is copied on picsAve will appear with the border. so pic3 looks kinda cut off into half.

One more thing, the user can draw inside the blit pictures. And when the background is pasted on it, the drawn lines is gone. :-(

ANy ideas?


Avatar of tezi

ASKER

Just to ask for your opinion Mdougan...
Alright, what is your opinion if I try like this...

I create a pictemp same size as pic1. I will put it on top of pic1 but I set the pictemp Visible = False and Enabled = False.

So everything will still be blit on pic1. However, when the user starts to draw, I will bitblt everything to pictemp. Then I set the Visible = True but the Enabled = False.
Now I cls pic1. So now pictemp can be seen but the user is actually drawing on pic1. Therefore, pic1 will contain whatever which is drawn.

Now when the user moves some other picture boxes, for eg pic3 or pic4 (inside pic1), I just cls the whole pictemp, blit everything all over again for the new locations and blit whatever which is drawn in pic1 to pictemp.

What do u think of this? coz I really in time pressure now. Thanks in advance.
Yikes!?!  This thing is getting pretty complicated!  Perhaps you can tell me in more detail what your application does, and maybe we can think about other possible ways you can do this.  If you want to keep the thread here, that's fine, or you can e-mail me at mdougan@earthlink.net

MD

P.S. I was getting a problem with the border thing when I had a 3D border on Pic2.  Turn off the 3D and any Border Style for the little pics.
Avatar of tezi

ASKER

mdougan

it's not exactly borders.... i 've already turn off all borders...the pic1 just appear with a white line( as a result of the pasting) on pic3... so pic3 (which is also a blit one on pic1 looks "cut into half"...

well probably there are other solutions...
what do u think of the one I suggested?
I think you are on the right track, but I don't think I'd put pictemp on top of pic1, I think I'd put it on the bottom.  I would have the background picture there, and anytime the user "draws" on anything - Pic1 or Pic2 or Pic3, I would actually draw in two places, Pic1, 2 or 3 AND on PicTemp.  Then, whenever you are restoring the background, just blit it from the PicTemp (instead of PicSave as we had in the code above).  Do you get what I'm suggesting?

MD
Avatar of tezi

ASKER

mdougan

I am confused about the sequence of events which should come first already...

if you copy what was drawn on pic1 and  pictemp, how do you cls everything, blit everything to its new locations and yet blit back whatever which is drawn on pic1?

shouldn't either one of the picture boxes, eg pictemp be a buffer to just store the drawn lines or dots and nothing else?

can you just brief me on the sequence on which should happen first?
I guess it depends on if you are giving the user the chance to clear the background of all of the drawing.  If so, then you do need to store a clean background somewhere.  But what I would do is this:

Put a background picture in Pic1 and PicTemp
(put PicTemp exactly under Pic1)

Everytime the user draws on Pic1, or 2 or 3, draw on those pics, but also draw on PicTemp - so that PicTemp has all of the user's drawings on it (plus the background).  When you want to clear the user's drawings, restore the background picture for Pic1 and PicTemp - either from another Picture or load the bmp again.

Everytime the user moves Pic2 or 3, then you can skip what we did before about blitting to PicSave (because we have already saved the drawing by drawing to PicTemp), however, in the step where you restore the background by blitting from PicSave to Pic1, then you would blit from PicTemp to Pic1 instead.  And you would blit the exact rectangle from PicTemp that you are trying to restore in Pic1.  So, change the code above to:

' you can get rid of the first time save code

' Restore saved rectangle to Pic1
'(note PicSave changed to PicTemp, and now using OldX
' and OldY instead of 0, 0)
   RC = BitBlt(Pic1.hDC, OldX, OldY, Pic2.Width, Pic2.Height, PicTemp.hDC, OldX, OldY, SRCCOPY)

' get rid of the save step, no longer necessary

' Draw pic2 onto pic1
   RC = BitBlt(Pic1.hDC, NewX, NewY, Pic2.Width, Pic2.Height, Pic2.hDC, 0, 0, SRCCOPY)

The only thing that is tricky, is that when the user draws on Pic2 or Pic3, you have to translate the coordinates to the proper coordinates on Pic1 to do the drawing (on Pic1 and PicTemp) - you do this by adding the X coordinate in the MouseDown for Pic2 to the Left property for Pic2 to give you the X coordinate on Pic1, same for the Y and the Top property.