OnPaint is not a member of wxWindows? - c++

I'm using my own variant of a wxPanel which itself makes use of its own paint-method to draw a custom image m_image:
void wxImagePanel::OnPaint(wxPaintEvent & evt)
{
wxPaintDC dc(this);
dc.SetBackground(*wxWHITE_BRUSH);
dc.Clear();
dc.DrawBitmap(*m_image,6,4,false);
wxWindow::OnPaint(evt);
}
The final call to wxWindow::OnPaint(evt) is there to let wxWidgets draw some GUI-elements on top of that image.
This works and compiles well with Windows, but when trying to build this application with Linux (Ubuntu 22.04LTS), I get an error:
error: ‘OnPaint’ is not a member of ‘wxWindow’
335 | wxWindow::OnPaint(evt);
| ^~~~~~~
The same happens when I try wxPanel::OnPaint(evt).
So, how can it happen that this does not compile for Linux only? Can't OnPaint() be found in wxWindow?

You should never call the base class event handler directly and not only because it may not exist but because the event handling logic in wxWidgets is more complex, in general, than that. Instead, you should either process the event (which you will typically do for wxEVT_PAINT, it doesn't make much sense to paint the window yourself and then do something else) or not, and in the latter case you need to call evt.Skip() to let the event handling code know that it should keep processing the event.
Again, for wxEVT_PAINT events you almost never want to do this anyhow. But for some other events, e.g. focus ones, you almost always do need to call Skip().

Related

QPainter and paintEvent : what is the use of QPaintEvent *event?

I have a school project involving creating a simple GUI and coloring graphs using a minimal number of colors. I am working with a classmate, and so far, we have laid out different ideas regarding how we will store the graphs in memory, and how to implement different coloration algorithms.
To create the GUI, we are using Qt, as I used it for another project before, it is free, and I generally find the documentation generally well detailed. Besides, I knew it had a drawing module, although I never used it.
After reading and the documentation and some examples, I was able to draw some basic shapes where I wished inside of a set area of a widget, and get them to correctly respond to resizing the widget.
To draw what I wish, I can write the paintEvent method this way, and just never use *event
void DrawArea::paintEvent(QPaintEvent *event)
{
//method body
}
Or I can write it this way, and it works too
void DrawArea::paintEvent(QPaintEvent *)
{
//method body
}
So, i have two questions :
How does the widget knows when to call the paintEvent method ?
If I'm not mistaken, every widget has a paint event, and I am
overwriting it ? If it's wrong please correct me, maybe that is the
reason why I don't really understand the way this pointer work.
What is the QPaintEvent pointer ? (I mean, what does it represent ?)
Thanks for any insight you may give me
So much text and so little questions...
You should learn about events handling in window systems (keywords are event loop, event queue and so on; in terms of Windows OS events are named "messages"). It is simple and useful thing to know.
In short, your program asks OS for new tasks time after time. If they exist, some information about it is provided, and you should handle them. Otherwise OS stops the program until such tasks will appear.
It means that OS notifies you to handle paint events when you are ready to do it.
QPaintEvent provides additional information about the event. At present it can give you a region to redraw. It may be used for painting optimization in some cases. But in simple cases it is not used.

DeferWindowPos weird behaviour

This happens with all ActiveX controls. If I reposition an ActiveX control with DeferWindowPos
HDWP hdwp = BeginDeferWindowPos(1);
DeferWindowPos(hdwp, m_pActiveX->GetSafeHwnd(), NULL, left, top, width, height, SWP_NOZORDER);
EndDeferWindowPos(hdwp);
it goes there but then moves/resizes to its old rectangle once you click anywhere inside the control. If I use MoveWindow instead
m_pActiveX->MoveWindow(left, top, width, height);
this doesn't happen.
It doesn't happen with any other type of control, only with ActiveX controls, but it happens with all of them. I made a test to confirm this, creating a new ActiveX control project and didn't make any changes, and the problem was still there.
You never got an appropriate answer. I'll try to help out a bit here.
The issue is that MFC hides a lot of the trickiness with hosting an ActiveX control within it's framework. Specifically, if you step into the MoveWindow call, it is not simply a wrapper around the Win32 MoveWindow function. It calls into the OLE Control Container support classes. This basically says, if we have a control site interface, then call COleControlSite::MoveWindow, otherwise call the standard Win32 MoveWindow. The same occurs with several other window functions handled by CWnd etc. For example COleControlSite::SetWindowPos handles hiding/showing the control, then calls COleControlSite::MoveWindow to move it, and then finally calls ::SetWindowPos (with the move/show flags masked out) to handle the rest.
Once within COleControlSite::MoveWindow, you will notice it does several things: it calls SetExtent, updates it's internal m_rect member, and then calls SetObjectRects.
Bypassing these for ActiveX controls using the Win32 API directly (eg via DeferWindowPos) causes some of these crucial steps to be missed. Depending on how your code is layed out, usually you can handle this yourself.
What is this ActiveX control?
Apart from that consider that DeferWindowPos is meant for positioning multiple windows at the same time. The concept being you enter the begin statement, change a bunch of window positions for a new layout, then end to actually move and apply the new positions and sizes.
If you aren't updating multiple windows consider using SetWindowPos instead.
Consider also that you may be getting a message to move, resize, or change the windows position while you are deferring. To prevent this if that is what is happening pass the SWP_NOSENDCHANGING flag in each call to DeferWindowPos so that it is not sent or handle the message and clear all the bits in the WINDOWPOS struct received to prevent unwanted changes.
It is also possible for this call to fail ... are you checking the return value?

Globally intercept window movement

I am having trouble getting a global system hook to work. I want to be notified whenever a window is moving, as early as possible, and change the window size. This means the CBT hook HCBT_MOVESIZE won't cut it, it only happens after the window has been moved. I want to hook the actual movement of the window, and be able to change the window size during the move.
The hooks are set from a DLL, and the callback function is within that DLL. This is what I've tried.
WH_CALLWNDPROC. It does alert me when a window is moved (WM_MOVING is received for windows from other applications), but I cannot change the contents of the message.
WH_CALLWNDPROCRET Same as WH_CALLWNDPROC.
CBT hook HCBT_MOVESIZE. Event happens to late.
WH_GETMESSAGE. Never receive WM_MOVE, WM_MOVING or WM_WINDOWPOSCHANGING. This hook would allow me to change the messages.
Update: Windows event hooks seem to allow me to capture it:
hWinEventHook = SetWinEventHook(EVENT_SYSTEM_MOVESIZESTART,
EVENT_SYSTEM_MOVESIZEEND, NULL, WinEventProc,
0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
However, this creates a different problem: changing the size of the window using SetWindowPos() does not work (it changes size alright, but immediately changes back to its previous size), even though I use SWP_NOSENDCHANGING. Ideas?
Update 2: Subclassing seems to work, however Visual Studio crashes after each program run (so does a lot of other windows). It works well if I place breakpoints and walk through the "unsubclassing", but not when I let the program run by itself. Ideas?
I have a CBT hook (it was there from earlier), and whenever HCBT_ACTIVATE is sent for a new window, I remove any previous subclassing using SetWindowLongPtr() (this has to run on 64-bit as well), and then subclass the new window. If I put a breakpoint anywhere, and immediately resume the session when it breaks, everything works fine. However, when I do not have any breakpoints, Visual Studio crashes when the program exits.
Hm, I would've thought that HCBT_MOVESIZE is precisely what you want, given that the MSDN says this about CBT hooks:
The system calls this function before activating, creating, destroying,
minimizing, maximizing, moving, or sizing a window.
and in particular:
HCBT_MOVESIZE
A window is about to be moved or sized.
(these quotes were taken from http://msdn.microsoft.com/en-us/library/ms644977%28VS.85%29.aspx)
...so I'd have thought that you get the HCBT_MOVESIZE call in time. The hook function which handles HCBT_MOVESIZE is also allowed to return an integer so that the system can determine whether the operation is allowed or should be prevented. Hence, given that the HCBT_MOVESIZE hook should get an option to prevent the operation, I'd say it's called before the move event occurred.
Are you really sure the hook function is called after the move event? If you do a GetWindowRect call on the particular handle within your hook function, does the returned rect equal the rectangle which is passed to the hook function?
Hooks are pretty heavy. You only want to use them when you absolutely have to.
That said, you could use one of the basic hooks simply as a way to get into the process. Once in the process, you could subclass the window you're interested in and handle the sizing messages in your subclass proc rather than trying to catch everything at the hook level.
Depending on what you want to do in response to the resize, you might need some interprocess communication.

What is the equivalent (if any) to the C++/Windows SendMessage() on the Mac?

Is there an equivalent function to SendMessage in the Mac OS?
Ironically, every method call in Objective-C is the equivalent of SendMessage. Objective-C is at heart a message passing system.
So you just say:
[window myMessage]
and the myMessage routine will be executed by passing myMessage to the Window object and having it process that method...
It's also possible the closer thing to what you really want to do would be to use Notifications to message between components.
If you don't have the Window object around at compile time, the compiler may complain it doesn't know if Window can handle the message you are sending. For those cases you can use:
[window performSelector:#selector(myMessage)]
There are alternate versions of this call that allow passing objects as parameters.
It depends on what message you'd be sending with SendMessage(). Most events in Cocoa go through -[NSApplication sendEvent:] for example, or SendEventToEventTarget() if you wanted a lower-level version. For other messages, such as resizing, movement, etc. you would need to look at the appropriate methods of NSWindow (such as -setFrame:animated:) or NSApplication.
Generally speaking, instead of using a funnel routine and function constants as SendMessage() does, in Cocoa you just get hold of the relevant object and call its methods.
On a higher level, if you are talking about the Carbon Event Manager, you would use the function 'SendEventToEventTarget'
See http://developer.apple.com/documentation/Carbon/Reference/Carbon_Event_Manager_Ref/Reference/reference.html

OnKillFocus() override in MFC triggering at odd times

I need to know when my Window goes out of input focus, so I overloaded the OnKillFocus() method of the CWnd.
However it doesn't invoke this method when I focus another application (alt+tab), or even minimize the window. But it DOES invoke the method when I restore it from being minimized. Are these the intended times for it to trigger this method?
I think you'll need a CWnd::OnActivateApp() handler if you need to be sure of being notified when your application is switched out.
OnKillFocus() is normally only used consistently for controls that have a concept of gaining the focus - buttons, edit boxes, list boxes, etc. Normally CWnd does not accept the focus, so you can't rely on that - I'm surprised you get it at all.
In addition to WM_ACTIVATEAPP mentioned above, there's also WM_ACTIVATE when switching between windows within the same application you might want to trap.