[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] NDEBUG

From: Vadim Zeitlin
Subject: Re: [lmi] NDEBUG
Date: Fri, 24 Oct 2014 16:16:38 +0200

On Fri, 24 Oct 2014 02:13:45 +0000 Greg Chicares <address@hidden> wrote:

GC> On 2014-10-23 12:39Z, Greg Chicares wrote:
GC> [...]
GC> >> GC> The reason why I ask is that I'm wondering if there's some way I 
GC> >> GC> (optionally) enable messages like this in the production system (say,
GC> >> GC> only with a special command-line argument).
GC> I could use some advice here. Clearly I can copy this code from 'wx_test':
GC>   wxLogWindow(NULL, "Log Messages", true, false)
GC> into Skeleton::OnInit(), and (subject to some command-line switch) see the
GC> log messages. But I'm not sure about the best way to do this.

 This depends on what exactly is the goal here and I'm not quite sure about
this. Do we want to have all messages logged by wxWidgets shown in the
window? Or maybe only those that are not otherwise shown to the user? And
maybe in this case we don't even want to show the window at all unless
there are any messages to show in it?

 wxLogWindow is a very simple class and one I wouldn't have added to
wxWidgets today (but did in 1998...) because there are many slightly
different ways of using it, but it doesn't really allow to customize its
behaviour much. In the non toy programs I personally typically use custom
log targets exclusively nowadays, maybe using wxLogTextCtrl but often not
even that.

 And, in fact, my TODO list does include replacing wxLogWindow with a
custom log target for the GUI test program, notably because I'd like to
indicate tests success/failure with colours. Perhaps I should push this to
the front of the list just to show you how can this be done?

GC> I'm not even sure where to create the log window. I suppose I should create
GC> it as early as possible, so that I don't miss any log messages arising in
GC> OnInit(). To make the log window conditional on a command-line argument, I
GC> need to write it after ProcessCommandLine() (which, at least for now, does
GC> not call any wx functions, so no wx diagnostics will be missed).

 The only 100% reliable way to ensure that no log messages are missed is to
override wxApp::CreateTraits() virtual method to return an object deriving
from wxAppTraits and overriding its CreateLogTarget() method to return a
custom log target (this design perfectly illustrates than in programming
all problems can be solved by an extra level of indirection -- except the
one of having too many levels of indirection that we have here).

 Doing it like this ensures that any log message, i.e. any call to
wxLogError() or similar functions, will go through the custom log target.
However it's more complicated than just creating a wxLogWindow because your
log target can be used before the main window exists or after it is
destroyed and needs to handle both cases gracefully. Usually the best is to
avoid displaying the log messages during the program startup and just
collect them in some internal buffer and then put them into wxLogWindow or
similar once the GUI is fully initialized. As for the messages at shutdown,
I don't have any really good solution here and so they typically end up
being displayed in message box.

GC> Would it be better to create the log window after
GC>   frame_ = new(wx) wxDocMDIParentFrame(...
GC> so that I can make that frame its parent?

 It is indeed better to make it child of the main frame because it will be
minimized (and restored) when the main frame is in this case, which is
usually the desired behaviour.

GC> or after the frame is shown:
GC>   frame_->Show(true);
GC> in case that matters?

 It shouldn't.

GC> I was thinking it might be nicer to view the log in a child window. But
GC> OTOH it's not enormously nicer. And anyway it didn't behave like an MDI
GC> child, and maybe it's silly to hope that it would.

 wxLogWindow definitely wouldn't, but we can, of course, create a custom
log target that would. I'm not sure I like this idea though, sometimes it's
useful to view the logs while working with the application and for this you
need to be able to put it near the main application window, not inside it.

GC> What if I combine those two ideas: create wxLogWindow as early as possible,
GC> and then Reparent() it? The documentation indicates that wxLogWindow is not
GC> a wxWindow, but maybe I can call wxLogWindow::GetFrame() and Reparent() the
GC> result, making it a child of my wxDocMDIParentFrame? Or am I fighting too
GC> hard against the tide here?

 I'm afraid you are. Reparenting a wxFrame wouldn't make it a
wxMDIChildFrame, nor can a frame be made a child window of one. Even if
this could be done somehow (and I seriously doubt it), it would be much
more difficult than just defining a custom log target.

GC> Anyway--I experimented a little with creating the wxLogWindow at various
GC> times, and adding a few wxLogMessage() and wxLogDebug() calls...and the
GC> outcome seemed to vary if I created wxLogWindow late in OnInit(). Some
GC> messages that preceded wxLogWindow creation were shown as messageboxes,
GC> but others (like the
GC>   'SendMessage(WM_MDISETMENU)' failed with error 0x00000008
GC> message mentioned here:
GC>   http://lists.nongnu.org/archive/html/lmi/2014-10/msg00077.html
GC> ) didn't show up at all. Is this just the way the logging system works
GC> by design--showing only the highest-priority messages in a messagebox?

 Yes, exactly. Debug messages (such as WM_MDISETMENU) are never shown to
the user like this.

GC> And, if I really want to see every single log message, is this experiment
GC> just telling me to create the wxLogWindow as early as possible?
GC> Suppose I create wxLogWindow early, with the 'show' argument set to false,
GC> and then Show() it later--will that prevent me from losing any messages?

 No, but it would prevent you from making it a child of the main frame.
This is not a tragedy, but it would break the minimize-and-restore-with-
parent behaviour mentioned above.

 Also, it's rare but possible that log messages are generated before
OnInit() is called, so the possibility of losing them still remains
present. Only overriding CreateLogTarget() as explained above guarantees
that no messages are lost.

GC> Is there any function that tells me whether or not any messages have been
GC> logged? I was thinking it might be nice to show the log window only if it
GC> would not be empty. I can't really say whether this (or other ideas above)
GC> would be good until I see it, but I'm not even sure whether it can be done.

 Just about anything can be done with a custom log target and showing the
window as soon as it gets the first (or a new, in case it had been hidden
before) message is straightforward to do.

GC> One last question: is wxLogWindow one of those classes that should be
GC> instantiated only on the heap, and never on the stack?

 If you rely on wxLog deleting it, then yes. If you ensure that you call
wxLog::SetActiveTarget() to replace it before it's deleted on the program
shutdown, then it's not, strictly speaking, necessary. But it's still
usually more convenient.

 To summarize, with wxLogWindow you get somewhat useful but not ideal
behaviour with very little effort. If you want to do something more, the
best thing to do is to define a custom log target: it's not difficult (just
a bit involved because of all of these layers) and allows you to do
precisely what you want.

 I hope this message was helpful rather than [even more] confusing and
please let me know if you'd like to know anything more about this or if
you'd like me to actually do anything about it.

 Thanks and good luck,

reply via email to

[Prev in Thread] Current Thread [Next in Thread]