ESRI Map object - Is it possible to disable the MouseWheel event handler? - c++

I've posted this on the ESRI support forum, but no one has come back with a solution as yet.
Background: I'm maintaining a C++ map display application that makes use of ESRI ArcGIS components (version 9.3.1 SP1). It instantiates a Map object (esriCarto::Map), queries for the IActiveView interface, and calls Activate to pass in the view window client area (and a whole bunch of other properties are also set via various interfaces). It is then used in the middle of a sequence of drawing operations to render the final display image.
Problem: The WM_MOUSEWHEEL event seems to be picked up in the Map object (or a child object?), and is causing odd behaviour. What's supposed to happen in the app is that the view window receives this message, then calls a 'zoom' method to trigger appropriate redrawing. What actually happens is that the message passes through the view window's PreTranslateMessage, then the display area glitches, then view window's OnMouseWheel handler is called to handle the zoom.
By 'glitches', I mean the view window turns white briefly, then the previous image is redisplayed. This did not happen in a previous version of the app that integrated with ArcGIS 9.2, and none of the app's own drawing code is being called while this glitching effect is happening. It also doesn't happen if the window's zoom function is called via an alternative context menu option.
Having read around the reference info for a while, I suspect that the Map's child ScreenDisplay object is responding to the mouse wheel event and doing something we don't want it to do to the view area - I also suspect there's a way of telling it not to, but I can't seem to find it. I do have a workaround, i.e. to handle the zoom in the view window's PreTranslateMessage, and prevent the message going any further, but that feels like a bit of a hack.
So, can any kind and clever person please point me at a way of telling the Map object to ignore mouse wheel events?

Better late than never...you can disable the mouse wheel on a MapControl by calling IMapControl4::put_AutoMouseWheel(VARIANT_FALSE) on your MapControl object.

Related

When resizing, make the window transparent with a dotted-line border

I'm asking this question ahead of time, since I haven't gotten around to attempting an actual, real implementation yet. Win32 (C++) is turning out to be a colossal pain to program. But, my question is this:
I want to make my application's window become fully transparent with a dotted perimeter when resizing the window. How would I accomplish this? Think of what happens in Windows 3/3.1 (I believe it was this version) when resizing a window. Everything goes transparent, with a dotted-outline where the mouse is moving, then it repaints the entire contents. That's what I'm trying to achieve.
A while ago, I tried handling the WM_(ENTER/EXIT)SIZEMOVE messages and make use of SetWindowLong() to set the WS_EX_TRANSPARENT extended style, but my window became (indefinitely) pass-through, and when the window's focus was killed, it could never again regain focus.
Do I need to handle other messages like WM_NCLBUTTON(DOWN/UP)? I have a boolean flag to tell me when to halt drawing during resizing, and the logic for determining when I'm resizing works perfectly, but I cannot get the visuals to work. I'm not sure which parts of the Win32 API to actually use. I've done some research, and uxtheme.lib/.h seems promising, but I'm not sure how that would work with WM_NCPAINT, which I have been using with (some) luck.
EDIT
I need to clarify something, in case anyone was confused or unsure of what I meant. What I meant by the Windows 3.1/3 resizing scenario is that once WM_ENTERSIZEMOVE has occurred, the window (controls, caption, frame) should be made entirely invisible, and the window's nonclient-region's perimeter should display a dotted-outline of sorts. Then, only until the resize has been finished, when WM_EXITSIZEMOVE has occurred should the entire window (controls, caption, frame) be fully redrawn, updated, and returned to its normal, functional state. Sorry for any miscommunication!
I found the answer... After so long, finally found it. Here's where I found it! http://www.catch22.net/tuts/win32/docking-toolbars-part-2# - Hope it helps anyone else possibly in my shoes!
And it turns out that the solution was rather simple. In fact, the core concept of what is explained is near-completely what I was thinking, yet I just had no idea how to implement it. The solution involves overriding the default WM_NCLBUTTONDOWN, WM_MOUSEMOVE, WM_LBUTTONUP (specifically when initiating a window movement) messages, and drawing a patterned rectangle which follows the position of the cursor. Then, afterwards, calling SetWindowPos or some other similar function to relocate the window.
Basically, block Windows from attempting to display anything graphics related until the resizing has been finished. Then, and only then, make Windows move the entire window in one huge, foul swoop.
Based on Remy's comment, there is a global option and corresponding registry setting for this, so perhaps try setting the registry setting when the move starts and restoring it when the move finishes.
Unfortunately this doesn't work as Windows appears only to pick up the setting on restart, broadcasting WM_SETTINGCHANGE also doesn't trigger it, which is a pity as doing something yourself that the OS already has an implementation of do is rather a poor state of affairs.

Is there a safe way to paint a little extra onto a subclassed control?

Let's say you want to add a little extra graphical info to a Windows control. For example, you want to add drag/drop functionality to a listview (using the procedure discussed here), but with horizontal lines signaling the drop/insertion points as the user drags an item. (The control belongs to your own application.)
Is there a safe way to subclass the control and draw onto it directly? In my limited experimentation in trying to do this, I encountered some problems. First, it wasn't clear whether I should call BeginPaint and EndPaint during the WM_PAINT message, since the control itself would be calling those functions once the message was passed along to the default procedure. I also inevitably encountered flickering, since some areas were being painted twice.
I thought a safer way would be just to create a transparent overlay window and draw on that, since that would avoid conflicts with the default paint procedure, but I thought I'd ask before going down that road. Thanks for any advice.

MFC GUI custom control: how to draw cursor updates in response to mouse moves?

I have a custom Windows control subclassed from CButton (no idea why that was selected--this is 17-year-old code; no semblance of button functionality is present).
Its DrawItem( LPDRAWITEMSTRUCT pdis ) method is called by CButton::OnChildNotify in response to WM_DRAWITEM. It renders its scene with the DC CDC::FromHandle( pdis->hDC ).
The mouse event method OnMouseMove() calculates the new cursor position and calls RedrawWindow( NULL, NULL, RDW_INVALIDATE ). A cursor that follows the mouse duly appears at the new mouse position. It works fine, but it's slow. In fact, only the previous and new cursor cells need be redrawn (if that) yet the graphic updates start to lag as the entire scene is rendered many times.
I thought in my OnMouseMove() method, instead of repainting the entire scene, could just paint the cells in question. It already has the exact X and Y coordinates of the cells and pointers to their data. I thought CPaintDC(this) would provide a DC that allowed this, but it doesn't paint. (Doesn't crash either, which is a rare joy.)
My hazy recollection is that the "optimal" way to do this would be to invalidate just the areas of the two cells, and the DrawItem() method would eventually be told these areas were invalidated, and rather than totally repainting it could just work out from the coordinates which cells they were (not an easy operation btw) and repaint them, and that would streamline not only this cursor problem but also ensure only a few cells be painted were the partially-obscured control partially revealed. But time pressure doesn't allow and the use cases don't seem to call for this to be optimized.
So the question is: is there some nice way for OnMouseMove() to re-render a single control immediately, and if so with what DC? (For instance can I cache the DC that I've received in DrawItem() via FromHandle()?
Right now the only idea I have is to have an object member pointing to a single cell to be redrawn, to call RedrawWindow() with this RDW_UPDATENOW flag, and have DrawItem(), if that flag be set, do just that one item. That would result in DrawItem() getting a DC that presumably would work in the way it always has. Seems like a real hack though, is there a better way?
In a Windows application, it is customary to perform all rendering in response to a WM_PAINT (or WM_NCPAINT) message. Code that needs to trigger a repaint marks part or all of window's client area as dirty, by calling InvalidateRect (and friends). The system is optimized for this approach, coalescing multiple requests into a single update region, and subsequently issuing a WM_PAINT message, when there is no more important work to do (like handling input).
This works reliably, and is usually easier to implement than spreading the rendering across several places. It is, however, perfectly legal to deviate from this, and perform rendering anywhere in your code. While WM_PAINT messages can still arrive at any time, it is desirable to have the out-of-band rendering produce identical visual results as the WM_PAINT handler would, to prevent visual artifacts.
All rendering goes through an abstraction called a device context (DC). When handling a WM_PAINT message in an MFC application, a suitable DC can be obtained by constructing a CPaintDC instance. When rendering anywhere else you cannot use a CPaintDC, but need to use a CClientDC instead (or a CWindowDC, to render the non-client area as well). In general, rendering code need not know, which type of DC it is rendering to, and can usually be reused without change.

AFX_WM_DRAW2D messages when screen is asleep

I have a problem with a progress bar that is implemented through adding a D2D object in MFC library.
I set up a message map to my function that keeps redrawing the progress bar based on some calculations:
BEGIN_MESSAGE_MAP(CProgressControl, CStatic)
ON_WM_PAINT()
ON_REGISTERED_MESSAGE(AFX_WM_DRAW2D, &CProgressControl::OnDraw2D)
END_MESSAGE_MAP()
My problem is that when the user locks out of the computer and the screen is asleep my drawing function does not seem to be called. It seems that the D2D notification message AFX_WM_DRAW2D is never sent to redraw when the screen is asleep.
I have tried to search for information on this online but did not find anything good about what might happen differently when the screen is asleep. I would appreciate any insight anyone might have on this.
Seems to me like this could be a normal behavior. Do you get any messages when your app is minimized or the computer is locked? I suspect that not.
Anyways, why should this bother you? Obviously your progress bar is invisible at the time, so why bother with the panting? You should be happy - Windows has an optimization for your program.
However if you do anything else besides painting in the painting messages, then I'd advise moving it elsewhere, as it is not that right place for it anyway. Paint message handlers should ONLY contain paint logic, and be prepared to be called at any time (or not at all).
Search the MFC sources for AFX_WM_DRAW2D and you'll see in wincore.cpp that the message is sent from a method called CWnd::DoD2DPaint() inbetween the render target's BeginDraw and EndDraw calls.
Therefore call DoD2DPaint to force a repaint. I did this on the sample CMFCD2DWalkthroughView (http://msdn.microsoft.com/en-us/library/gg482848.aspx) in the OnSize method to ensure that the gradient is updated and painted when the window is resized instead of the size/paint being out of sync.

Can I run code *after* a built-in wxWidgets event is handled?

I suspect there must be a built-in way to do this, but my Google-fu has failed me.
I'm using a wxScrolledWindow, and I have to paint an unscrolled background picture behind the contents each time the window is scrolled. I've made a scroll handler like this...
void homewindow_t::onScroll(wxScrollEvent &evt) {
Refresh();
evt.Skip();
}
...which works to force it to redraw the entire window each time. Unfortunately, it draws the window before the scroll is handled, so the background is repainted and then scrolled up or down, screwing up the alignment. The documentation suggests that Refresh just invalidates the screen, meaning that the scroll handler must be forcing a redraw.
The only way around this that I can see is to handle the scrolling code myself, which I'd rather not do if I don't have to.
Ideas, suggestions, clues...?
The only general solution I've found to running code after an event is handled is to post a second, different event to the event queue before skipping the current event (so that it gets handled by the default handler), and handle that when it comes up.
However, perusing the wxWidgets source code, I've found an answer to my specific problem: there's a function, wxScrolledWindow::EnableScrolling. Although it's not obvious from the name, this will enable or disable the "physical scrolling," which is what forces the instant redraw. So calling EnableScrolling(false, false); in the window's constructor solves the issue entirely.
To paint a "fixed" background in wxScrolledWindow you should just offset the DC origin to compensate for scrolling before drawing it (and then reset it back, of course), there is really no need to deal with events at all.
However if you really need to define a "post handler", then there is a way to do it, see this blog post. While the API described in it will only be available in wx 2.9.5, you do the same thing in the previous wx versions manually using wxEVT_IDLE.