dcsimg
Results 1 to 18 of 18

Thread: Picture1.Picture = Picture1.Image problem

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Picture1.Picture = Picture1.Image problem

    I always thought that when you draw on a picturebox you are actually drawing on the Image property and not the Picture property and so you need to set the picture property the same as the image property using Picture1.Picture = Picture1.Image if you want the drawing to become the permanent picture.

    I'm drawing on a picturebox using Picture1.Paint and I have AutoRedraw set to False then when the drawing is finished I want to save the picture so I have to set the picture property same as image property then use SavePicture to save the picture.

    The problem is that when I use Picture1.Picture = Picture1.Image the picture disappears (blanks out) but there is a picture handle (I see this when I hover the mouse over the .Picture property of Picture1. When I go to save the picture I get no error such as invalid property but no picture is saved.

    If I set AutoRedraw to True I don't have this problem but it takes forever to do the drawing and you can't see it being drawn until it has finished so I use AutoRedraw = False to speed up the process and then at the end of the drawing I set AutoRedraw = True then I do Picture1.Picture = Picture1.Image but then I have the problem described above.

    Code:
      '
      '
      Picture1.AutoRedraw = False
      '
      '
      Picture1.Paint ..................
      '
      '
      Picture1.AutoRedraw = True
    
      Picture1.Picture = Picture1.Image
      '
      '

  2. #2
    Junior Member Derp!'s Avatar
    Join Date
    Jan 2019
    Posts
    21

    Re: Picture1.Picture = Picture1.Image problem

    Worst case scenario, why not simply make the picturebox invisible until the drawing is complete or draw to an invisible canvas and then transfer the picture to the visible picturebox?

  3. #3
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,445

    Re: Picture1.Picture = Picture1.Image problem

    The picturebox has three levels of drawing.
    The .Picture is the lowest level, so would normally serve as a background image.
    The .Image is a back buffer, controlled by the AutoRedraw boolean.
    If AutoRedraw is set to True, then you don't get paint events. Everything you draw is drawn in the .Image backing store, and if the picture needs to be refreshed (where you would normally get a paint event), the picture is just refreshed from the .Image backbuffer automatically with no notification, which is why it is called AutoRedraw.

    If AutoRedraw is set to false, then you are drawing on the screen, in the area "above" the picturebox. This is temporary (non-persistent), and can be wiped out by any number of actions. When part of this screen area is wiped our, or needing to be redrawn for any reason, the Paint event is triggered so that you can redraw this area, so makes it a software driven persistence, assuming you redraw everything you need in the paint event.

    Since AutoRedraw is false, then nothing is drawn in the .Image backbuffer, so saving the .image to .picture accomplishes nothing in that case.

    If you really wanted to save what was drawn on the screen while autoredraw was false, you could save the .hdc value with AutoRedraw set to false, then set AutoRedraw to True (so the .hdc will change to the .image backbuffer), and then use bitblt to copy from the saved .hdc to the current .hdc, which will transfer the screen image "above" the picturebox to the .Image context. You could then set .Picture to .Image. Or you could use Picturebox.Paint to paint from the .image to the .Picture context as an alternative.

    With a picturebox, you might want to use all three levels for certain cases, i.e. have a static background image loaded in .Picture, and a clearable semi-permanent drawing that is done "on top" of the background, drawn with AutoRedraw set to true, and then have regularly updated dynamic data drawn "on top" of those two, such as numeric readouts, needles, game characters, etc...

  4. #4

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: Picture1.Picture = Picture1.Image problem

    That's a very good idea about what you said to BitBlt the saved hdc onto a picturebox

    Code:
      '
      '
      Picture1.AutoRedraw = False
      '
      '
      Picture1.Paint ..................
      '
      '
      '
      SaveHDC = Picture1.hdc
    
      Picture1.AutoRedraw = True
      
      BitBlt Picture1.hDC, 0, 0, Picture1.ScaleWidth, Picture1.ScaleHeight, SaveHDC, 0, 0, vbSrcCopy
    
      Picture1.Picture = Picture1.Image
       '
       '
    Works great. Thanks alot

  5. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,392

    Re: Picture1.Picture = Picture1.Image problem

    Quote Originally Posted by Code Dummy View Post
    If I set AutoRedraw to True I don't have this problem but it takes forever to do the drawing
    Based on your other posts, the slowdown is probably related to drawing the picturebox pixel by pixel. Unfortunately, that is absolutely the slowest method you coud pick from.

    There are more efficient ways to work with graphics, especially if we are talking about changing just 1 color... Following are a few of them and are mostly off the table if we are talking about images with transparency.

    1. Use FloodFill API. With MS Paint, it is like using the paint bucket

    2. If the total number of colors of the image is less than 256, one can use palleted images and change a color simply by changing the color table: SetDIBColorTable API

    3. TransparentBlt. Choose a color to be changed, fill target DC with new color, then TrasparentBlt

    4. MaskBlt. May require more effort if you have many different image shapes.

    5. GDI+ has similar functions to those above

    May want to research a couple of the above.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,392

    Re: Picture1.Picture = Picture1.Image problem

    @ Code Dummy. Regarding DIB color tables, it is really easy but takes a bit of setup. Attached project is for you to play with. It may not apply to your situation if I misinterpreted your previous posts.

    The project changes 2 colors of the bitmap simply by changing its color table. The original bitmap is modified so if important, you'll need to return the original color table at some point. You can modify the project to change any number of color table entries.

    The sample project contains a bitmap that is 2 colors, but has a 16 color table. Can use bitmaps up to 256 colors. I saved the bitmap via MS Paint using the option 16 colors. This guarantees the image has a color table. Bitmaps saved via MS Paint as 256 colors also have a palette.

    Anyway, the setup I was talking about... Great, we have a palette, but we don't know where our colors are inside the palette. The sample project has a FindPaletteColor function to locate the index by the desired color. This means you absolutely need to know the color you are looking for. If needed, bring the bitmap into MS Paint, use the eye-dropper tool to select a color & the "edit colors" table to see the RGB values. If you get it wrong, an invalid index is returned. Once we have an index, we set the desired color by that index whenever we want.

    The code is really small. If you think you can use this and have questions, just ask.
    Attached Files Attached Files
    Last edited by LaVolpe; Jun 17th, 2019 at 10:39 AM. Reason: updated/simplified sample project
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,551

    Re: Picture1.Picture = Picture1.Image problem

    In a sense there is another "layer" in a PictureBox.

    Create a Form with a PictureBox. At design-time set its Picture property to a GIF with transparency.

    Then either at design-time or in code a run-time, change the BackColor. The new color shows behind the Picture.

  8. #8
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,445

    Re: Picture1.Picture = Picture1.Image problem

    Yes, I guess I didn't think of that as a layer, but the background color is certainly the bottom layer, and is visible when you have a transparent gif.
    I've taken advantage of that myself in some older code examples back in the day.

    The example in this post used a transparent gif drawn in two pictureboxes, one with white background, and one with black, as a simple method of emulating a transparent blit type operation without having to create a true mask.

    This snippet of code is where I copied the Pictures from pictureboxes with a black background color to a picturebox with a white background, so each showed the background through the transparent areas, as you mentioned.
    Code:
     'Copy our images. Image 0 will be in boxes 0 and 1 'one serves as sprite, the other as mask
     'Image 1 will be in boxes 2 and 3.
     'etc...
      Picture3(1).Picture = Picture3(0).Picture  'Copy our first image (on a black background) to the white background box
      Picture3(3).Picture = Picture3(2).Picture  'Copy our second image (black backround) to the white background box
    One advantage with having the same image in the two pictureboxes is that either one can be considered the image and the other the mask. It really doesn't matter which one you draw first, and which is drawn second. You just draw the one with a black background using vbSrcPaint, and the one with the White background using vbSrcAnd.

  9. #9

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: Picture1.Picture = Picture1.Image problem

    Quote Originally Posted by passel View Post
    If AutoRedraw is set to false, then you are drawing on the screen, in the area "above" the picturebox. This is temporary (non-persistent), and can be wiped out by any number of actions. When part of this screen area is wiped our, or needing to be redrawn for any reason, the Paint event is triggered so that you can redraw this area, so makes it a software driven persistence, assuming you redraw everything you need in the paint event.
    What I don't understand is if your are drawing on the screen, in the area "above" the picturebox then why is it that if you move the Form with the picturebox around the drawing stays with the area in the picturebox. I would think that anything drawn on the screen is not part of the app and therefore would stay "as is, where it is drawn" when you move the picturebox

  10. #10
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,445

    Re: Picture1.Picture = Picture1.Image problem

    When you move the form (and the "windows" on the form, i.e. buttons and pictureboxes, etc.), windows saves itself some work, because it copies the screen area of the form and moves it. So, your temporary drawing is preserved in that case, since your area of the screen was copied and moved, so not wiped out.
    But, other windows that you positioned over, or dragged over may have been wiped out and had to be redrawn.

    If you dragged another window over your form, so that that window had to be drawn in your screen space, then you would see that your temporary screen level drawings would be wiped out, if you don't redraw them.

  11. #11

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2017
    Posts
    550

    Re: Picture1.Picture = Picture1.Image problem

    OK, makes sense. Why not then just do all this in the Paint event instead of in a procedure or the button event

    Code:
       '
       '
    Private Sub cmdCommand1_Click()
     Form_Paint
    End Sub
    
    Private Sub Form_Paint()
      '
      ' Put all the code from Command1_Click here
      '
    End Sub

  12. #12
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,392

    Re: Picture1.Picture = Picture1.Image problem

    Quote Originally Posted by passel View Post
    If you dragged another window over your form, so that that window had to be drawn in your screen space, then you would see that your temporary screen level drawings would be wiped out, if you don't redraw them.
    Not so much on modern systems. But if the form was minimized or dragged mostly off-screen or some other action forces a refresh, then it should erase. Modern systems seem to temporarily cache more & more stuff.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  13. #13
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,445

    Re: Picture1.Picture = Picture1.Image problem

    That's true. I thought about verifying my statement in regards to win10 since the desktop is a fully composited screen, meaning all the window elements are drawn in offscreen buffers and then composited into a desktop backbuffer and flushed to the screen.
    That means that the particular behavior I mentioned doesn't occur with win10, unless like LaVolpe says, you drag the form at least partially off screen, and then release it so that form is clipped, and the portion outside the screen bounds is lost. If you then drag it back on the screen to reveal the portion that was clipped, you have only a partial drawing.

    Likewise, if you had a translucent form in earlier versions of window, and you bitblt from the screen to a picturebox to capture a portion of the screen, the translucent color would usually not be captured as part of the image, but since now the different window layers are composited into the screen, the translucent color is now captured. That affected the way one of my programs worked.

    Bottom line, the screen itself is no longer a single frame buffer in modern OS's so the built in multiple window backing stores can lessen the work of window applications from having to redrawn windows by using extra memory instead.

    But, this still means on the VB level, drawing with AutoRedraw set to False does not draw to the .Image context of VB's picturebox. form, or user control, and that its persistence is at the whim of the OS.

  14. #14
    Hyperactive Member
    Join Date
    Feb 2017
    Posts
    410

    Re: Picture1.Picture = Picture1.Image problem

    passel:

    Wanted to quibble a bit with this portion of your statement re .Image and AutoRedraw = False
    and that its persistence is at the whim of the OS
    As I see it .Image is a hidden CompatibleDC and CompatibleBitMap that is integral to (part of) object Picturebox.
    It contents -- including Empty being defined as contents - remains with the Picturebox and its contents persists until object Picturebox is destroyed
    or cleared by the User. I believe the OSes only involvement is the standard Picturebox message loop which in effect defines where drawing occurs based on AutoRedraw = True or False.

    My take:
    ' Picture1.Image can be cleared using:
    ' - Picture1 = LoadPicture() '<< Loads an Empty BitMap and clears both .Picture and .Image
    ' - Picture1.Picture = LoadPicture() '<< Same as above
    ' - Picture1.Image = LoadPicture() '<<Invalid / does NOT Work as cannot directly get to .Image
    ' - Set Picture1.Picture = Nothing

  15. #15
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,551

    Re: Picture1.Picture = Picture1.Image problem

    A lot of this is covered in the VB6 documentation. For example, see Creating Persistent Graphics with AutoRedraw and nearby articles.

    This is also in your October 2001 MSDN CD docs, and at least there you don't have to worry about broken links or the pages being taken down forever in a few months.

  16. #16
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,445

    Re: Picture1.Picture = Picture1.Image problem

    Quote Originally Posted by vb6forever View Post
    passel:

    Wanted to quibble a bit with this portion of your statement re .Image and AutoRedraw = False


    As I see it .Image is a hidden CompatibleDC and CompatibleBitMap that is integral to (part of) object Picturebox.
    It contents -- including Empty being defined as contents - remains with the Picturebox and its contents persists until object Picturebox is destroyed
    or cleared by the User. I believe the OSes only involvement is the standard Picturebox message loop which in effect defines where drawing occurs based on AutoRedraw = True or False.

    My take:
    Perhaps you misunderstood my context. It was in regards to what you draw when AutoRedraw is false.

    When AutoRedraw is False, anything you draw has no effect on the .Image backing store. How long that drawing remains on the screen is up to the OS.

    With earlier OS's it was quite easy to wipe out drawing done while AutoRedraw was False by mearly dragging a window across the window you drew in. Now, more OSes maintain additional backing stores for the windows being drawn, independent of the .Image and .Picture layers of the picturebox, so now drawing done with AutoRedraw = False has more persistence then it did in the past, because the OS itself is maintaining back buffers for the windows on the screen.

    This essentially means you have multiple screen contexts, associated with the windows being maintained, so as long as the window is within the bounds of the screen, its screen image is maintained in a backing buffer and is not disturbed by other windows that use that same area of the screen, i.e. the screen you see is a composite of the the multiple screen images of the windows being maintained by the OS.
    Last edited by passel; Jun 19th, 2019 at 01:48 PM.

  17. #17
    Hyperactive Member
    Join Date
    Feb 2017
    Posts
    410

    Re: Picture1.Picture = Picture1.Image problem

    passel:

    Thanks for responding. Re:
    Perhaps you misunderstood my context.
    It appears I did in reading post #16. My apologizes.

    I can confirm with Window7 (32 bit) pro, that picturebox graphics created with either AutoRedraw = False or True that the graphics
    appear to persist when covered / uncovered by another Form. I would expect AutoRedraw = True to always persist. I also would expect
    when AutoRedraw = False and any calls initiated from Picture1.Paint that "at least the appearance" that they persist to the user would be expected --
    even if the OS got involved (erased them before they were recreated).

    Re:
    When AutoRedraw is False, anything you draw has no effect on the .Image backing store. How long that drawing remains on the screen is up to the OS.
    This is where my hangup was "that drawing" - where I read it as referring to the ".Image backing store" where the caveat being AutoRedraw = False which would refer to OTHER THAN .Image.
    Last edited by vb6forever; Jun 19th, 2019 at 02:23 PM.

  18. #18
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,551

    Re: Picture1.Picture = Picture1.Image problem

    Try to minimize then restore. When a top-level window like a Form gets minimized a lot of transient resources get released. Overlapping isn't as hard and fast about that, and it probably depends on the display driver and how much buffer space it has available.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width