Drawing over an image in win32? - winapi

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

Related

How to make CGWindowListCreateImage render correct background color?

Capturing an image of an off-screen window with CGWindowListCreateImage is a common way to create QuickLook style zoom-in animations, but this seems create an image with the wrong background colour, slightly lighter than the real window.
This causes a flash at the end of the animation which kind of ruins the effect.
Does anyone have any idea why this happens and what can be done about it?
EDIT: I created a demonstration app for this problem. It is a bit large and complex for a Stack Overflow question, but the relevant code is probably in the ZoomingWindow.m methods takeSnapshot and makeAndPrepareSnapshotWindow.
Setting the window appearance to textured in Interface Builder fixed this. Of course that also changes the color of the window, but that is acceptable in this particular case.

How to save drawings in Livecode?

I'm a bit of a Livecode newbie so I apologize if this is obvious. But I created a stack. Added fields, buttons, code etc. Then I drew and painted some images. Saved. When I reopened the stack, all my image work was gone! aqrrg. Happened twice. Why?
Make sure you add an image object before drawing. Adjust it to the size you need, then draw on the image object and it will be saved with your stack. If you fail to add an image object first, your drawing will disappear, not sure if this is a bug or not, but it isn't logical because you do see the drawing.

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.

Changing the background of an edit control on getting focus

I want to change the background color of an edit control (i.e. regular EDIT window class) in that control's EN_SETFOCUS. I know that I should handle WM_CTLCOLOR, do SetBkColor() on the DC I get, and return a handle to a brush with the background color. HOWEVER, when I do that from EN_SETFOCUS, my control isn't invalidated or redrawn properly. Basically I get a 1-pixel border in the wrong color around my text; so a rectangle within the black border that is already around the control itself. If I move my mouse cursor over the control, some parts of that wrong border are redrawn correctly, and sometimes the whole artifact disappears after a small amount of time, as if some timer is causing a complete redraw.
I have tried invalidating the control in various places, RedrawWindow, SelectRgn(NULL) on the DC, playing with wS_CLIPCHILDREN and -SIBLINGS of the dialog, invalidating the dialog on the rect the control is at, but none of this works. I have also found a vague reference to a similar problem online in a post from 2001 (!) but no solution. Has anyone ever encountered this? Any ideas on other things I could try?
FWIW, this is using VS9 on WinXP, and using MFC, but I've also send messages 'by hand' and that didn't change anything, I don't think MFC in this case is the culprit. Of course I could be wrong :)
Edit:
Code of the dialog of the screenshots below (minimal sample) is here: http://pastebin.com/zepdhdp5 . This is a small wizard-generated app - nothing special, the full source code can be downloaded from https://www.dropbox.com/s/d8nxaryoo0vclue/edit_control_redrawing_sample.zip .
The control looks like this after it gets focus:
and like this when it loses focus:
As you can see, it looks like there a border around the text area that doesn't get invalidated.
I have tried to reproduce this with pure win32, but when I don't use commonctrl6, it doesn't exhibit the problem. I can't manage to get commonctrl6 to work in win32 though, so I'm suspecting now that it's got something to do with that.
Well what do you know - after another day of intermittently attempting various things and trying different angles in google searches, I found the magic keyword: non-client area invalidation. Which led me to http://forums.codeguru.com/showthread.php?307470-Invalidate-NC-area , which contains the solution:
SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_DRAWFRAME);
(in the SetFocus/KillFocus handlers)
My theory of what's going on is that the commonctrl6 visual styles manager treats the border around the edit control as non-client area, and miscalculates the area to be invalidated by one pixel when the control gets the focus. SWP_DRAWFRAME seems to be the only thing that forces a complete update of the control, RedrawWindow() with RDW_FRAME didn't cut it.
Ah well, hopefully my question here at least saves someone down the line from wasting his time like I have...

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

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.

Resources