How do I perform my own redraw in the Paint event of a VB6 PictureBox? - vb6

A coworker is encountering an error when he tries to run a VB6 app we're working on. The error is, "480: Can't create AutoRedraw image". Microsoft's documentation says this is because "There isn't enough available memory for the AutoRedraw property to be set to True. Set the AutoRedraw property to False and perform your own redraw in the Paint event procedure or make the PictureBox control or Form object smaller..."
Making the PictureBox smaller isn't an option. I'd be glad to "...perform my own redraw in the Paint event procedure...", but I'm not sure how to go about it. Can someone show me the way?

Without details this will be a simplistic answer. In general most beginning VB6 programmers use AutoRedraw=True draw in responds to some input. Fill out some data, click draw, and it appears in the picture box.
The click event in the Draw Button is linked do your drawing code. The first step is move the call to the drawing code to the paint event of the picture. The second step is to replace all calls to the drawing code with MyPictureBox.Refresh. Refresh forces the paint event of that picture box to fire.
The main problem you will have to be concerned with is that the paint event is going to be fired everytime the form needs refreshed. Like if a window covering it is moved. This means that any speed issue in your drawing code will be exposed. AutoRedraw=True takes what you drew and puts in a hidden bitmap that the PictureBox uses to display what you drew.
The Paint event will execute each step of your drawing process so you have to make sure you are as fast as possible. Depending on how dynamic your application is the worse slowdown issues will become. If you are displaying a static image then the problem isn't as bad.

Making the PictureBox smaller isn't an option. I'd be glad to "...perform my own redraw in the Paint event procedure...", but I'm not sure how to go about it. Can someone show me the way?
That is easy. You just implement the _Paint()-Event of your Form or PictureBox and draw.
Because you are asking, i think i should clarify what the AutoRedraw-Propeprty does. If it is set to true, you can "just draw your image" any way you want. In multiple steps. Whatever. If it needs to be redrawn, for example, because another windows was on top it, it will be magically done. The down site is, that is slow, for the drawing part.
If AutoRedraw is false, no magic will happen. The Paint()-Event will be fired and you are responsible to draw your image again. This will be much faster, if your window is not "invalidated" (e.g. "covered") often. Or you are doing a lot of drawing.
Or you are running out of memory for the "magic space" ;-)

If you don't mind rewriting your graphics code to use the GDI API - this could be a fairly big task - I found this thread from 2006 in the VB6 discussion group, where Mike Sutton said in answer to a similar problem:
VB's back-buffer implementation uses a
Device Dependant Bitmap (DDB) to store
the image data, which is quite limited
in how large it can be made. On older
OS' this used to be ~16mb uncompressed
data size, on later OS this has been
expanded but is still quite
restrictive.
A workaround for this is to use a
Device Independent Bitmap (DIB) and
manage the GDI resources yourself,
have a look at the DIB article on my
site for an example of how to work
with them.
I haven't tried it myself.

There's usually a drop-down box of events for your control in the forms code window. You need to pick the paint event:
Private Sub object_Paint()
and fill in your your code for drawing on the PictureBox.

Related

CChildView::OnPaint() Refresh Slowing When Painting Many Data Points

I am writing an MFC Windows App to plot the motion of a wheeled robot.
In CChildView::OnPaint() I do a pdc->FillRect(ViewRect, &CBrush( RGB(128,128,128) ) );
Then I use pdc->MoveTo and pdc->LineTo to draw all the data points etc. refreshed every 250ms.
Problem is as the robot progresses on its travels the number of data points increases to a level where the OnPaint() function refresh time becomes noticeable.
In a previous DOS app I did years ago I got around this sluggish refresh rate by removing the fill background paint and replaced it with a plot all the data points in the background colour, then painting them all again in there foreground item colour. Thus reducing the number of changed pixels.
Would this method be valid for what I am doing in MFC OnPaint() or is there a better solution please?
Painting in a DOS applications is simple, because you have full control of the process and you don't get paint requests from the system - normally you have to introduce delays if you want to achieve a "motion" effect. In Windows though painting is very different, because you may (or may not) receive paint requests from the system, if the user minimizes/maximizes/restores, moves, unhides etc or programmatically invalidates a window. This causes an "invalid" area on the window surface. If the window contains an invalid area it will receive a WM_PAINT message. It is a low-priority message, posted just before the application is about to enter the idle state, also it is in some way "asynchronous", posted when the system decides so.
First you need to fully understand the invalidating/painting mechanism in Windows. The documentation you must read is: Painting and Drawing. I have posted quite a bit about this, please check my answer here (and the links in the post).
As for your question, I would suggest using a combination of painting and drawing. Many suggest not painting outside the WM_PAINT message (OnPaint()/OnDraw() in MFC), but this is not suitable for all cases, as the message is sent asynchronously, and it's also very hard to implement a really optimized operation, painting only the affected area; you would actually have to paint the invalidated area as well. It is best used to paint the whole client area of the window. You could definitely use it in your app (and it's logically "correct"), but as you have found it's really "wasteful", and has a sluggish and choppy feel. So my proposal is:
Use Painting to paint the entire client area, in response to WM_PAINT messages. Better use OnDraw(), rather than OnPaint() for a CView/CScrollView-derived class. It should paint the background, if any, all additoinal objects (labels, axes etc) and finally all data points.
Use Drawing (GetDC()/ReleaseDC()) to paint only the section that changes, ie a single data point at a time. You will have to create a new worker thread (so as to not block the main/UI thread). It must do the calculations, add the new data point to some list-of-data-points (also used by the UI thread in OnDraw() to paint the whole window) and draw the new data point only. You should use some sort of synchronization (eg Critical Section) to access the data points list, because it is used and modified by more than one threads. As all paint operations should best be performed in the context of the UI thread, you can define a custom message and have the worker thread sending this message (SendMessage()) to the window. The routine handling the message should do the actual drawing, ie paint the new data point.
If implemented correctly this should result in a smooth operation, allowing the window to be moved or resized while the paint operation is in progress, without blocking the window or the application.

Overlay window drawing which appears in screen captures of other applications

We need to overlay a target window with a custom shape and tracks the position of the target window such that the overlay drawing always appears above it. Also, the overlay drawing should appear in screenshots taken using BitBlt or PrintClient by screen-capturing tools like Camtasia, Debut, etc. Also, moving the target window around should not leave traces of the drawing at earlier location. The target window is not made using our code.
So far we've tried several ways but each method has its problems:
1) Layered Window:
Using a layered window as the child/owned window of the target window is the easiest thing and it works. But the problem is on Windows 7 and XP, layered windows do not appear in a BitBlt done without the CAPTUREBLT flag and the screen-capturing tools may call BitBlt without the flag, thereby skipping our window from the capture.
2) Region Window:
The crude approach to support all Windows versions then is to use a region window using SetWindowRgn and make the target window its owner. However, region windows are generally very slow in rendering complex shapes and also impact the performance of other windows, sometimes to the point of freezing the application. Region window also leaves traces on dragging the application window.
3) Subclassing and Drawing on HDC:
Another approach is to sub-class the target window and draw the shape on its HDC on the OnPaint() event inside the window procedure hook. The shape can be drawn on the desktop window instead too. The problem is that applications may draw without a paint event, like when some text is selected using the cursor, and such drawing may erase a part of the custom drawing. Tracking all possible paint events is not a good way to do this.
4) Drawing continuously in a timer:
The last resort is to draw the custom shape on the target window in a timer continuously so the drawing is always above the target, even on text selection. But this may show a bit of flicker when the text is selected. Not to mention, it is very performance heavy to draw constantly.
Question
What is the best way to achieve an overlay drawing which works on all Windows versions (since XP) at the same time appearing in screen-captures. We've exhausted all approaches. Is there some method I'm missing? Can the above mentioned ways be used with some improvement? Is DirectX an option? I'm looking for methods with fast rendering capacity to achieve this. Appreciate any help!
I think the best solution to draw an overlay window, is to use a double-buffered technique GDI, just like in this example:
Overlay Drawing in CScrollView
I have myself the same task, and the only solution was that one. Hope it help you.

Drawing over an image in win32?

First of all, keep in mind that I am a beginner in win32, so I am very likely to be missing the obvious.
I am working with Code::Blocks, C++, win32. I am making a program that:
would load an image from a file
would load some info from another file and draw it over the image.
The program would then draw additional stuff over the image later on. Also, I don't need this drawing to be actually incorporated into the image, the image only acts as a reference for the drawing.
I have managed to display the image in a child (static) window and I have successfully drawn the info onto the main window. When I wanted to combine the two so the drawing would go over the image, however, I got stuck - I didn't know what window to draw to and which message to process for the drawing. I have searched the Internet for any hints, examples, anything, but I found nothing. (This is probably because I didn't know exactly how to describe my problem.)
I have been trying different things over the past few days, like drawing to the static control with the image, and trying to paint to a transparent static control on top of the one for the image, but nothing worked.
If anyone could give me any hints, that would be great! Thanks!
Trap the WM_PAINT message for the window you want to draw. In the handler, add code draw the image (BitBlt function perhaps) first and then the drawing you want. You must also handle WM_ERASEBKGND message which is used to erase the background of the window when re-sizing etc.
Refer: WM_PAINT message, WM_ERASEBKGND message

Cocoa drawing issues

I'm working on an application that does some drawing on the screen based on information received over the network. 
My problem is that sometimes those events come in at a rate higher than I can draw and I'm experiencing a delay. Now the problem isn't with the delay it's with the type of delay that builds up. 
If I would draw based on events such as clicking with the mouse and dragging this doesn't happen and I assume it's because of the way events are delivered. How could I find out when the view is "ready" to draw again because then I could discard some of the events received over the network and draw just the most recent ones. 
Right now I have a transparent window that is on "top" of the window hierarchy. 
Im drawing on an NSImage that is the size of the screen an after each drawing operation I make a setneedsdisplayinrect call to the view in which the drawing happens. When I receive the drawrect call I draw the portion of the image which is included in the dirty rect. 
My attempt of solving this is a bit of a hack since I don't know another way to do it. I set a Boolean to true after each setneedsdisplayinrect and I set it to false in drawrect. If I get a subsequent event to draw on the image I just ignore it of the Boolean is set to true. 
What other alternatives of doing this do I have? 
I thought of using cashapelayers and modifying their path but I'm not sure how efficient shape layers are once the path gets big. I also thought of using multiple shape layers for different portions of the path that are separated (not continuous) but if I want to clear the drawing and i remove the layers if there are many I noticed a bit of a performance hog. 
The only other way I could think of is drawing with open gl but considering the nature of the OpenGL view (screen size and transparent) I'm not sure how much of a performance issue will this be. 
Any tips would be greatly appreciated. 
Thanks. 
I figured it out :)
From the object that managed the network connection I was sending events out using the main dispatch queue. Which from what I understand - I might be wrong about this - can span across multiple iterations of the runloop. What I needed was to dispatch events during each iteration of the run loop and by creating a custom run loop source that would signal the main runloop every time I get a new event over the network connection it greatly improved my performance.

Qt - Drawing a Rect/Frame out of a bigger Pixmap image

I've been banging my head about this seemingly easy task and I could really use some help.
I have a wide Image loaded in the gui (using the designer..) and I want to be able to draw only a portion of it, a rectangle.
I need to be able to change this rectangle position over the large image, in order to draw a different part of the larger image at will. In this process the rect must maintain its size.
Using the Ui::MainWindow object I'm able to access the label holding the image and a solution that involves using this option is preferred (in order to keep up with the rest of the code I've already written )
Any solution will be much appreciated :)
Thanks,
Itamar
I would definitely (for ease of use) just place an empty label as placeholder in Designer.
Then implement the paintEvent for this label (delegate it to your own method). You'll have also have to look into QPainter, QPixMap, etc... Should be doable based on these hints and the documentation.
If you want more, I suggest you provide a small code snippet to work upon.
If you want to do this more or less purely through designer, you could put a QScrollArea where you want the portion of the image to appear. If you set the scroll area's scrollbar policy to be never shown, you can then manually change what part is visible via the scroll area widget. However, this would probably be more complex that creating a derived widget and reimplementing the paint function.

Resources