Borland Online And The Cobb Group Present:


July, 1995 - Vol. 2 No. 7

ObjectWindows programming - Centering dialog boxes in an OWL application

One of the greatest advantages that Windows applications have over their DOS counterparts is device independence: You don't need to worry about the specific characteristics of the video system or printer you're using. Instead, Windows provides a layer of abstraction that you can use to interface devices that you've never seen or used.

However, while device independence is a very good thing, there are times when you need to know the specific capabilities of an output device. For example, if you want to center a dialog box, you'll need to position the window yourself, since Windows doesn't provide a built-in centering function.

Since the dimensions of the current screen could be 640 x 480, 800 x 600, 1024 x 768, or some other resolution, you'll need to know something about the screen settings before calculating a position that's truly centered. In addition, if your application changes the default screen-mapping system (the coordinate system that Windows uses to specify screen positions), specifying an absolute screen position might place the dialog box off the screen!

Fortunately, you can use the Windows function GetSystemMetrics() to retrieve information about the current coordinate system and the current screen size. In this article, we'll show how you can create a custom dialog box class for the ObjectWindows Library (OWL) that uses this information to automatically center dialog boxes on the screen.

Saved center

To calculate the center of the current Windows screen, you need to access two global system values, or system metrics­­the height (SM_CYSCREEN) and the width (SM_CXSCREEN) of the current screen. Using these two values, the size of the dialog box, and some simple math, you can calculate an origin that will position the dialog box in the center of the screen.

To retrieve the height of the screen, you call

GetSystemMetrics(SM_CYSCREEN)

Likewise, to retrieve the width of the screen, you call

GetSystemMetrics(SM_CXSCREEN)

You'll use these two values to calculate and save the coordinates of the center of the screen.

To calculate the correct X-axis origin for a dialog box, you need to subtract half of the dialog box's width from the horizontal center of the screen. To calculate the correct Y-axis for a dialog box, you subtract half of the dialog box's height from the vertical center of the screen.

Once you've determined the new origin for a dialog box, you can use the member function MoveWindow() to reposition the dialog box in the centered location. If you call this function inside the dialog box's SetupWindow() member function, the movement of the dialog box won't be visible.

Finally, you should wrap this centering behavior inside a new class that you derive from the TDialog class. This allows you to derive dialog box classes from the new class instead of from TDialog and to take advantage of the centering behavior automatically.

Programmer-centered

Now let's create a simple OWL application that takes advantage of an automatically centered dialog box class. To begin, launch the Borland C++ 4.0 or 4.5 Integrated Development Environment (IDE).

When the IDE's main window appears, choose New Project... from the Project menu. In the New Project window, enter \CENTER\CENTER.IDE in the Project Path And Name entry field, choose Application from the Target Type list box, choose Windows 3.x (16) from the Platform combo box, and select the OWL check box in the Standard Libraries section. Click OK to create the new project.

When the Project window appears, double-click on the name center [.cpp] to open an editing window for that file. When the editing window appears, enter the code from Listing A.


Listing A: CENTER.CPP

#include <owl/applicat.h>
#include <owl/framewin.h>
#include <owl/owlpch.h>
#include <owl/eventhan.h>
#include "ctrdlog.h"

class TNewDialog : public TCenteredDialog
{
  public:
    TNewDialog(TWindow* parent, int resId) :
      TCenteredDialog(parent, resId) {}
};

class TCenterApp : public TApplication
{
  public:
    TCenterApp() {}
    ~TCenterApp() {}

  protected:
    void InitMainWindow()
    { TFrameWindow* frame =
	new TFrameWindow(0, "Center Test");
      frame->AssignMenu(1);
      SetMainWindow(frame);
    }

    void ShowDialog()
    { TNewDialog* dialog =
	new TNewDialog(GetMainWindow(), 1000);
      dialog->Execute();
      dialog->Destroy();
    }
    DECLARE_RESPONSE_TABLE(TCenterApp);
};

DEFINE_RESPONSE_TABLE1(TCenterApp, TApplication)
  EV_COMMAND(101, ShowDialog),
END_RESPONSE_TABLE;

int OwlMain(int, char**)
{
  return TCenterApp().Run();
}

When you finish entering the code, choose Save from the File menu. In the Project window, right-click on the center [.cpp] node and choose Add Node from the pop-up menu. In the Add To Project List dialog box, enter CTRDLOG.H in the File Name entry field and click OK. Double-click on the name center [.h] to open an editing window for this file, and then enter the code from Listing B.


Listing B: CTRDLOG.H

#include <owl/dialog.h>

class TCenteredDialog : public TDialog
{
 public:
  TCenteredDialog(TWindow* parent, int resId) :
    TDialog(parent, resId) {}
  void SetupWindow()
  {
   TDialog::SetupWindow();
   TPoint newOrigin(GetSystemMetrics(SM_CXSCREEN) / 2,
		       GetSystemMetrics(SM_CYSCREEN) / 2);
   TRect tempRect = GetWindowRect();
   newOrigin.x -= tempRect.Width() / 2;
   newOrigin.y -= tempRect.Height() / 2;

   MoveWindow(TRect(newOrigin, tempRect.Size()));
  }
};

When you finish entering this code, choose Save from the File menu. In the Project window, right-click on the center [.rc] file, and choose Text Edit from the pop-up menu's View submenu. In the editing window for this file, enter the resource description from Listing C.


Listing C: CENTER.RC

1000 DIALOG 2, 12, 104, 43
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Am I off center?"
{
 DEFPUSHBUTTON "OK", IDOK, 27, 14, 50, 14
}

1 MENU
{
  POPUP "Window"
  {
    MENUITEM "Show", 101
  }
}

When you finish entering this code, choose Save from the File menu. In the Project window, right-click on the center [.def] node and choose Delete Node from the pop-up menu. Click Yes in the confirmation dialog box to delete the node.

Finally, choose Run from the Debug menu to build and test the application. When the application runs, choose Show from the Window menu. You'll see the simple dialog box centered on the screen, as shown in Figure A. Click OK to close the Am I Off Center dialog box. Double-click on the Center Test window's System menu icon to close the window and return to the IDE.

Figure A - You can use the TCenteredDialog class to create dialog boxes that always center themselves on the screen.

Conclusion

As high-performance video systems become more popular, it's more difficult than ever to predict the resolution of the screen that's displaying your program. By deriving your dialog box classes from the TCenteredDialog class we've created here, your dialog boxes will center themselves no matter what the resolution of the target system might be.

Return to the Borland C++ Developer's Journal index

Subscribe to the Borland C++ Developer's Journal


Copyright (c) 1996 The Cobb Group, a division of Ziff-Davis Publishing Company. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis Publishing Company is prohibited. The Cobb Group and The Cobb Group logo are trademarks of Ziff-Davis Publishing Company.