Previous | Home | Up | Next |
Not all LVT programs need to have one and only one top-level window. In this
chapter, we will extend our scribble
program to use multiple
windows.
When using multiple windows, we need to dedice if we wish to continue to have a main window -- which will cause the program to exit when it is closed -- or if we want to have several, independant windows, and not exit the program until the all of them are closed. In the latter case, we need to handle exiting the program ourselves.
One way in which we can accomplish this is to use the fact that an App
object keeps track of how many top-level windows are open. Once this reaches 0,
we can terminate the application by calling
App::Exit
. This is not the only
way to do it, but it is the simplest. This is the method we'll use for our
modified scribble
program.
Our new ScribblerWnd
class
definition looks like this:
// Global application object App app; #include <lvt/lvt.h> using namespace LVT; class ScribblerWnd : public Wnd { public: ScribblerWnd(); protected: virtual bool OnCreate(); virtual void OnDestroy(); virtual void OnMenuCommand(int id); virtual void OnPaint(); virtual void OnLButtonDown(int x, int y); virtual void OnLButtonUp(int x, int y); virtual void OnMouseMove(int x, int y); private: std::vector<Polyline> m_lines; bool m_mouseDown; };
Our new class definition is identical to the old one with the addition of two new message handlers:
OnCreate
and OnDestroy
. In addition, our App
is now global, instead of being local to main
.
Let's look at the implementation of the two new message handlers:
bool ScribblerWnd::OnCreate() { // Create our main menu. Menu mainMenu, fileMenu; fileMenu.Append("New", MENU_FILE_NEW); fileMenu.Append("Close", MENU_FILE_CLOSE); fileMenu.AppendSeparator(); fileMenu.Append("Exit", MENU_FILE_EXIT); mainMenu.Append("File", fileMenu); mainMenu.Append("Clear", MENU_EDIT_CLEAR); SetMenu(mainMenu); return true; } void ScribblerWnd::OnDestroy() { // The window has been destroyed, so destroy the object. delete this; // Exit the app if no windows are left. if (app.WndCount() == 0) app.Exit(); }
Wnd::Create
calls the OnCreate
message handler. In OnCreate
we can do any additional initialization we need
for our window object. In this case, we initialize the window's menu, and increment the
window count. We then return true
to allow creation to succeed. Returning
false
causes creation to fail, and Wnd::Create
to return false
.
In OnDestroy
we commit suicide with delete this
.
This is not the only way to ensure that our window objects are destroyed when they are closed, but it
is easy to implement, and safe in our case, since as we will see later, we create our
ScribblerWnd
objects with new
.
Once the object is destroyed, we check the number of open windows with App::WndCount
.
Once it reaches 0, we terminate the message loop with App::Exit
.
Our menu is slightly different from last time, so let's look at the new OnMenuCommand
handler:
void ScribblerWnd::OnMenuCommand(int id) { ScribblerWnd *newWnd; // Do default menu command processing. Wnd::OnMenuCommand(id); switch (id) { case MENU_FILE_NEW: newWnd = new ScribblerWnd; newWnd->Create("MultiScribble"); newWnd->Show(); break; case MENU_FILE_EXIT: app.Exit(); break; case MENU_EDIT_CLEAR: // Erase all the polylines in our list and redraw the window. m_lines.clear(); Redraw(); break; } }
Our handler for MENU_EDIT_CLEAR
is the same as in our previous example. For
MENU_FILE_NEW
, we create a new ScribblerWnd
object, and then create and show it. Since we are not passing the window in to
App::Run
, we are responsible for showing the
window ourselves.
For MENU_FILE_EXIT
, we simply call App::Exit
,
which closes any open windows, and terminates the message loop.
That covers all of our multiple window handling. The only thing left is main
, which we'll
look at now:
int main(int argc, char *argv[]) { LVT::App myApp; ScribblerWnd myWnd; myApp.Init(&argc, &argv); myWnd.Create("Scribble"); myWnd.Show(); myApp.Run(); return 0; }
The new main
function is virtually identical to the previous one, with the exception that
we do not pass our initial window into App::Run
, and therefore
we must show our window explicitly.
Now that you understand the basics of working with LVT window opjects, we're ready to move on to more sophisticated drawing programs, which is the topic of the next section.
Previous | Home | Up | Next |