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...
Related
I'm trying to draw a tiled pattern inside a NSScrollView which is itself inside a resizable window (on Mac OS X). The code simply calls [NSColor colorWithPatternImage], CGContextSetFillColorWithColor, and CGContextFillRect.
The problem is that the pattern is drawn relative to the bottom-left corner of the window. This is documented behavior, but causes two unpleasant effects:
When the window is resized, the pattern scrolls up or down in a very surprising manner.
When the scroll view is scrolled, and then scrolled back, the newly drawn pattern doesn't line up with the scrolled (buffered) part of the pattern.
I'm able to mostly fix problem 2 by calling CGContextConvertPointToDeviceSpace, passing in 0,0, and seeing what I get back -- this tells me my scroll offset, which I can then use with CGContextSetPatternPhase to fix the problem. (Though it doesn't completely fix it -- when I scroll quickly, I still see mismatched patterns, for reasons I haven't sorted out yet.)
But addressing problem 1 is proving really thorny. From my drawing code, which only knows the CGContext, I can't find any way to get the window height. (The Device/User space conversion routines seem completely unaffected by window height.)
Short of adding a bunch of plumbing to all the drawing code to pass around a window reference, is there any way to figure out the correct offset so that my pattern will stay put when the window is resized, and scroll properly when the scrollview is scrolled?
Oops -- shortly after posting this, I found at least a partial answer: the current transformation matrix (from CGContextGetCTM) reflects both the window height, and the scroll offset.
(Or at least, it does in my app; I set the CTM very early in the pipeline to give me a top-down coordinate system so I can use much the same code on iOS.)
So, if I just call CGContextGetCTM, and then pass the .x0 and .y0 values of the result to CGContextSetPatternPhase, it mostly works.
I'm still running into some visual glitches when I scroll quickly horizontally, though not vertically -- a very odd effect, which suggests to me that it might be something in my code, or perhaps related to how wide the content area is. I'll dig further.
I made a flyout window in the notification area using WinAPI and my goal was to make it similar to the flyout windows that show up when you click some of the icons in the notification area, like the Volume icon.
I already succeeded in making it look and behave similar to the other ones, but there is one thing I can't seem to figure out. The link area of the flyout windows has a darker blueish background and there is a subtle difference in the look between Windows 7 and Windows 8. A picture of it in Windows 7 can be seen here
http://msdn.microsoft.com/en-us/library/windows/desktop/aa511448.aspx#flyouts
I achieved this by painting this link area of my flyout window manually in the right colors (including the gradient at the topmost part of the section) using the WM_PAINT message, but I just feel like it's too much of a hack, especially because it's not affected by changing themes in Windows. For example, if I set the "Windows Classic" theme this area should be grey and not blue.
So, my question is, am I missing something in how this can be achieved without painting the window manually. I noticed that the details pane in Explorer windows in Win 7 has the same look. I've searched quite a bit for answers but I haven't found anything yet. This is my first time doing a GUI using the WinAPI so I have very little experience, and therefore I'm assuming there is something that I just don't know about.
UPDATE:
I did manage to figure out how to draw this area without painting it manually. It can be drawn by using the OpenThemeData and DrawThemeBackground functions
HTHEME aeroTheme = OpenThemeData(hWnd, L"FLYOUT");
DrawThemeBackground(aeroTheme, hdc, FLYOUT_LINKAREA, 0, &rect, &rect);
This obviously only works when themes are enabled, so for non-themed cases I draw a normal rectangle with the appropriate color.
I'm not an expert in WinAPI so I can't offer any advice on achieving the look you want without manual painting.
However, if you're successfully achieving the appearance for a particular color theme, I'd suggest you look at the GetSysColor function and use this when creating your brushes for painting. This should allow you to get the correct colors based on the theme that has been set. More info (including a swatch table) can be found here.
Hope this helps.
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
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.
I'm using a VB6 PictureBox on my User Control. I set the PictureBox's picture, I set the BorderStyle to 0, and I set the BackColor to the User Control's BackColor. The idea is that I want a "floating" icon. However, I want that icon to appear clickable when the mouse hovers over it.
Two questions:
Which events do I use? MouseMove seems to be the closest to a "MouseOver" event. Are there any cleaner alternatives?
How should I change the style? I've tried a few things, but none of them quite look right.
MouseMove is the correct event in VB6. You'll have to do some work to manually detect when the mouse leaves the client area cleanly. (My experiments in this world, lo those many years ago, always found implementing this behavior to be tricky.)
For changing the style, I'd recommend using GDI to: (a) shift the image one pixel up and to the left; (b) draw a single pixel line in the ButtonHighlightColor along the top and left edges; and (c) draw a single pixel line in the ButtonShadowColor along the bottom and right edges. This is trickier than it sounds, particularly in VB6, so ultimately I'd recommend ...
That you look at vbAccelerator's toolbar controls. They're free, and they'll probably get you most of where you want to be. (And yes, they're "classic" VB -- that is, VB6.)