Objective Toolkit User’s Guide
Stingray® Studio
Version 11.2.0 OBJECTIVE TOOLKIT USER’S GUIDE
THIS MANUAL
© Copyright 1997-2014 Rogue Wave Software, Inc. All Rights Reserved.
Rogue Wave and Stingray are registered trademarks of Rogue Wave Software, Inc. in the United States and other countries. All other trademarks are the property of their respective owners.
ACKNOWLEDGMENTS This documentation, and the information contained herein (the "Documentation"), contains proprietary information of Rogue Wave Software, Inc. Any reproduction, disclosure, modification, creation of derivative works from, license, sale, or other transfer of the Documentation without the express written consent of Rogue Wave Software, Inc., is strictly prohibited. The Documentation may contain technical inaccuracies or typo- graphical errors. Use of the Documentation and implementation of any of its processes or techniques are the sole responsibility of the client, and Rogue Wave Software, Inc., assumes no responsibility and will not be liable for any errors, omissions, damage, or loss that might result from any use or misuse of the Documentation
ROGUE WAVE SOFTWARE, INC., MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THE DOCUMENTATION. THE DOCUMENTATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. ROGUE WAVE SOFTWARE, INC., HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS WITH REGARD TO THE DOCUMENTATION, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHER- WISE, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL ROGUE WAVE SOFTWARE, INC., BE LIABLE, WHETHER IN CONTRACT, TORT, OR OTHERWISE, FOR ANY SPE- CIAL, CONSEQUENTIAL, INDIRECT, PUNITIVE, OR EXEMPLARY DAMAGES IN CONNECTION WITH THE USE OF THE DOCUMENTATION.
The Documentation is subject to change at any time without notice.
ROGUE WAVE SOFTWARE, INC.
Address: 5500 Flatiron Parkway, Boulder, CO 80301 USA
Product Information: (303) 473-9118 (800) 487-3217 Fax: (303) 473-9137 Web: http://www.roguewave.com CONTENTS
1Chapter 1 Introduction to Objective Toolkit
1.1 Welcome to Objective Toolkit 1
1.2 Product Features 2 1.2.1 MFC Extension Classes 2 1.2.2 Full Source Code 3 1.2.3 Compatibility and Build Options 3
1.3 Location of Samples 4 1.4 Supported Platforms 4 1.5 Getting Help 4 1.5.1 Documentation 4 1.5.2 Knowledge Base 5 1.5.3 Professional Services 5 1.5.4 Technical Support 5 1.6 Licensing Restrictions 5
2Chapter 2 Objective Toolkit Quick Start
2.1 Overview 7 2.2 Installation 7 2.3 Building Objective Toolkit 7 2.3.1 Using the Build Wizard 8 2.3.2 DLL naming issues 9 2.3.3 Compiler Flags 9 2.3.4 Build Target Naming Conventions 10 2.3.5 Build Configuration Options 11 2.3.6 To build the 32-bit or 64-bit libraries 11 2.3.7 Miscellaneous Build Issues 12 2.3.8 Building the Samples 13 2.3.9 Automatic linking 13 2.3.10 To incorporate Objective Toolkit into your application 14
Contents iii 2.4 Distributing Objective Toolkit Applications 16
2.5 Basic Tutorial—MaskEdit Control 17
2.6 Using Component Headers to Increase Application Build Performance 21 2.6.1 The Component Headers 21 2.6.2 To use the component headers in your project 23
3Chapter 3 The Objective Toolkit AppWizard
3.1 Overview 25
3.2 Creating a Skeleton Application 27
4Chapter 4 Simple Controls
4.1 Overview 33 4.2 Browse Edit Controls 33 4.2.1 Browse Edit Classes 34 4.2.2 Using the Browse Edit Classes 35 4.2.3 Customizing the Browse Edit Control 36 4.3 Browse Edit Sample 36
4.4 Button Controls 37
4.5 Button Class Hierarchy 38 4.5.1 SECOwnerDrawButton 38 4.5.2 Using SECOwnerDrawButton 38 4.5.3 Customizing SECOwnerDrawButton 39 4.5.4 SECBitmapButton 39 4.5.5 Using SECBitmapButton 39 4.5.6 SECBitmapButton alignment 40 4.5.7 SECMenuButton 40 4.5.8 Using SECMenuButton 40 4.5.9 SECMenuButton Menu Placement 41 4.5.10 SECWellButton 41 4.5.11 Using SECWellButton 42 4.5.12 Customizing SECWellButton 42
4.6 Calculator Control 43 4.6.1 SECCalculator 43 4.6.2 SECPopupCalculator 44 4.6.3 Using SECCalculator 44 4.6.4 Customizing SECCalculator 44 4.6.5 Calculator Sample 45
iv 4.7 Calendar Control 46 4.7.1 To incorporate the SECCalendar class into your code 46 4.7.2 SECCalendar Key Methods 47 4.7.3 Customizing SECCalendar 48 4.7.4 SECCalendar Sample 48
4.8 Color Well Control 49 4.8.1 SECColorWell 50 4.8.2 SECPopupColorWell 51 4.8.3 ColorWell Sample 52
4.9 Currency Edit Control 53 4.9.1 SECDropEdit 53 4.9.2 SECCurrencyEdit 53 4.9.3 Using SECCurrencyEdit 53 4.9.4 SECCurrencyEdit::Format 54 4.9.5 SECCurrencyEdit Messages 55 4.9.6 SECCurrencyEdit Sample 56
4.10 Date/Time Edit Control 57 4.10.1 SECDateTimeCtrl 58 4.10.2 SECDTGadget 58 4.10.3 Date Formats 59 4.10.4 Null Data Entry Mode 60 4.10.5 Using SECDateTimeCtrl 61 4.10.6 Date/Time Edit Control Sample 63
4.11 List Box Edit Control 64 4.11.1 SECListBoxEditor 65 4.11.2 SECListBoxFileEditor 65 4.11.3 SECListBoxDirEditor 65 4.11.4 Using the List Box Edit Classes 66 4.11.5 Customizing the List Box Edit Classes 66 4.11.6 Extending the Editable List Box Classes 67 4.11.7 Editable List Box Sample 68
4.12 Marquee Control 69 4.12.1 Using SECMarquee 69 4.12.2 Customizing SECMarquee 70 4.12.3 Marquee Sample 71
4.13 Masked Edit Control 72 4.13.1 SECMaskEdit 72 4.13.2 Using SECMaskEdit 72 4.13.3 Creating a Mask to Use with SECMaskEdit 73 4.13.4 Mask Edit Sample 74
v 4.14 Extended Progress Control 75 4.14.1 Using SECProgressCtrl 75 4.14.2 Customizing SECProgressCtrl 76 4.14.3 Extending SECProgressCtrl 76
4.15 Enhanced ComboBox with AutoComplete 77 4.15.1 The Enhanced ComboBox Class 77 4.15.2 Using SECComboBoxEx 77
5Chapter 5 Look and Feel Styles
5.1 Overview 79
5.2 Microsoft Vista Classic Style 80
5.3 Visual Studio .NET/Office XP Style 81 5.3.1 Enabling .NET/Office XP Styles 82
5.4 Microsoft Office 2003 Style 83 5.4.1 Enabling Office 2003 Styles 88
6Chapter 6 Customizable Toolbars
6.1 Overview 89
6.2 The Customizable Toolbar Classes 91 6.2.1 SECCustomToolBar 91 6.2.2 SECToolBarManager 92 6.2.3 SECToolBarsBase 92 6.2.4 SECToolBarsDlg 92 6.2.5 SECNewToolBar 93 6.2.6 SECToolBarsPage 93 6.2.7 SECToolBarCmdPage 93 6.2.8 SECToolBarSheet 93
6.3 The Toolbar Button Classes 94 6.3.1 SECStdBtn 94 6.3.2 SECStdMenuBtn 95 6.3.3 SECTwoPartBtn 95 6.3.4 SECTBTextBtn 95 6.3.5 SECWndBtn 95 6.3.6 SECComboBtn 96 6.4 Comparing SECToolbar to SECCustomToolBar 96
6.5 Toolbar Button Map 97 6.5.1 STD_BUTTON 97
vi 6.5.2 STD_MENU_BUTTON 98 6.5.3 TEXT_BUTTON 98 6.5.4 TEXT_BUTTON_EX 99 6.5.5 TWOPART_BUTTON 99 6.5.6 COMBO_BUTTON 99 6.6 Toolbar Button Styles 100 6.6.1 Button style macros 100 6.6.2 Button State Macros 100 6.7 Creating New Button Types 101
6.8 Customization Dialogs 102 6.8.1 Creating SECCustomToolBars—Arguments and Cautions 103 6.8.2 The Effect of Modifying Toolbars on Persistence 103
6.9 Using the Customizable Toolbar Classes 104 6.9.1 To incorporate customizable toolbars into your application 104 6.9.2 To implement toolbars with the flat cool look with a toolbar manager 105 6.9.3 To implement toolbars with the flat cool look without a toolbar manager 106 6.9.4 To implement button groups 106 6.9.5 To use multiple toolbar bitmap resources with the toolbar manager 107 6.9.6 To find a button on a customizable toolbar 107 6.9.7 To use the button map 107 6.9.8 To implement a text button 108 6.9.9 To implement a text button with styles 108 6.9.10 To implement a combo button 109 6.9.11 To implement a twopart button 109 6.9.12 To implement a bitmap button using styles 109 6.9.13 To make a customizable toolbar dockable 110 6.9.14 To reposition customizable toolbars at run time 110 6.9.15 To obtain a pointer to a specific customizable toolbar 110 6.9.16 To iterate the customizable toolbars 110 6.9.17 To implement the toolbar customization dialog 111 6.9.18 To invoke the toolbar customization dialog with a toolbar button 112 6.9.19 To hide and show customizable toolbars 112 6.9.20 To set the docking order of customizable toolbars 112 6.9.21 To changing the font for text buttons 112 6.9.22 To save and restore customizable toolbars 113 6.9.23 To draw owner-draw controls embedded in a vertically docked toolbar 113
7Chapter 7 Menu Bars
7.1 Overview 115
7.2 Menu Bar Classes 117 7.2.1 SECMenuBar 117 7.2.2 SECMDIMenuBar 117
vii 7.3 Customizing the Display of Menu Pop-ups 118
7.4 Menu Button Map Macros 119
7.5 WM_EXTENDCONTEXTMENU 120
7.6 Using the Menu Bar Classes 121 7.6.1 To Incorporate Objective Toolkit Menubars Into Your Code—Simple Case 121 7.6.2 To Incorporate Objective Toolkit Menubars Into Your Code--Advanced Case 122 7.6.3 To Implement SECMenuBar Or SECMDIMenuBar Without a Toolbar Manager 125 7.6.4 To remove the close button from a floating menu 126 7.6.5 To switch between menus 126 7.6.6 To use bitmap menus without the cool-look toolbars 127 7.6.7 To use bitmap menus in context menus 128
7.7 MenuBar Sample 130
8Chapter 8 Docking Windows
8.1 Overview 131
8.2 Features of Docking Windows 132
8.3 Flat-Style Drawing 134
8.4 Auto-Hide Docking Windows 135 8.4.1 Features 135 8.4.2 Creating Auto-Hide Docking Windows 137
8.5 The Docking Window Classes 138
8.6 Docking Window Frame Classes 139 8.6.1 SECFrameWnd 139 8.6.2 SECMDIFrameWnd 139 8.6.3 SECMDIChildWnd 139
8.7 Docking Window Control Bar Classes 140 8.7.1 SECControlBar 140 8.7.2 SECDialogBar 140 8.7.3 SECControlBarManager 140 8.7.4 SECDockState 140
viii 8.8 Message Routing Issues 141
8.9 Extended ControlBar Styles 142
8.10 Embedding CViews in Docking Windows 144
8.11 Using the Docking Window Architecture 145 8.11.1 To create an application with Objective Toolkit docking windows 145 8.11.2 To incorporate Objective Toolkit docking windows into an existing MDI application 145 8.11.3 To incorporate Objective Toolkit docking windows into an existing SDI application 146 8.11.4 To use Objective Toolkit docking windows inside an OLE IP server 146 8.11.5 To create a docking window based on a dialog resource 148 8.11.6 To create a docking window not based on a dialog resource 149 8.11.7 To set the style of a docking window 149 8.11.8 To make a docking window dockable 149 8.11.9 To create a non-dockable control bar 150 8.11.10 To dock a docking window that is floating 150 8.11.11 To float a docking window that is docked 151 8.11.12 To make an SECDialogBar size diagonally when floated 151 8.11.13 To receive notifications when the docked state of a docking window changes 151 8.11.14 To hide a docking window 152 8.11.15 To control the docking location of a docking window 152 8.11.16 To determine where a docking window is docked 152 8.11.17 To determine the row and column of a docked window 153 8.11.18 To modify a control bar’s context menu 153 8.11.19 To add a toolbar to a control bar 154 8.11.20 To access controls in the docking window inside a message handler 154 8.11.21 To route messages to the client area of SECControlBar 154
8.12 Customizing Objective Toolkit Docking Windows 155 8.12.1 Key Extended Control Bar Members 155 8.13 Docking Windows Sample 155
9Chapter 9 Image Classes
9.1 Overview 157 9.2 The Image Classes 158 9.2.1 SECImage 158 9.2.2 SECDib 159 9.2.3 SECGif 159 9.2.4 SECJpeg 159 9.2.5 SECPcx 159 9.2.6 SECTarga 159 9.2.7 SECTiff 159
ix 9.3 SECImage Format 160
9.4 Using the Image Classes 161 9.4.1 To read an image from a file 161 9.4.2 To view GIF/TIFF images 161 9.4.3 To display an image 161 9.4.4 To convert an image 162 9.4.5 To copy an image 163 9.4.6 To manipulate an image 163 9.4.7 To write an image to a file 164 9.4.8 To convert to a CBitmap object 164 9.4.9 To convert from a CBitmap object 164 9.4.10 To create from a CDC object 165 9.4.11 To load an image from a resource 165 9.4.12 To stream image data 166
9.5 Key Image Methods 168 9.6 Image Sample 168
10Chapter 10 MDI Alternatives
10.1 Overview 169
10.2 Benefits of MDI Alternatives 170 10.2.1 Multiple Top-level Interface (MTI) 170 10.2.2 MTI Class – SECToplevelFrame 172 10.2.3 Floating Document Interface (FDI) 175 10.2.4 Workbook Document Interface (WDI) 177
11Chapter 11 Shortcut Bar
11.1 Overview 185
11.2 The Shortcut Bar Classes 187 11.2.1 SECShortcutBar 187 11.2.2 SECBar 188 11.2.3 SECListBar 188 11.2.4 SECShortcutListCtrl 188
11.3 Shortcut Bar Styles 189
11.4 Shortcut Bar Notification Messages 190
11.5 Shortcut Bar Callbacks 190
11.6 Using SECShortcutBar 191 11.6.1 To incorporate an SECShortcutBar into your application 191
x 11.6.2 To add selectable icons to a shortcut bar 191 11.6.3 To embed a window in a shortcut bar 192 11.6.4 To change the way the bars are drawn 192 11.6.5 To allow shortcut bars to behave like buttons 193 11.6.6 To enable context menus in a shortcut bar 193 11.6.7 To have the shortcut bars display the focus rectangle 194 11.6.8 To enable/disable animated scrolling 194 11.6.9 To receive notifications when an icon in the SECShortcutListCtrl is clicked 194 11.6.10 To determine which icon is clicked in an SECListBar window 195 11.6.11 To change the orientation of the shortcut bar at run time 196 11.6.12 To embed an SECShortcutBar into a splitter pane 196 11.7 Shortcut Bar Samples 196
12Chapter 12 Framework-Tailored Shortcut Bars
12.1 Overview 197
12.2 The Shortcut Bar Classes 199 12.2.1 ATL 199 12.2.2 MFC 199
12.3 Shortcut Bar Styles 200
12.4 Using the Shortcut Bar 201 12.4.1 Using the Windowed Shortcut Bar 201 12.4.2 Using the Non-Windowed Shortcut Bar 201 12.4.3 Setting visual aspects of the shortcut bar 202 12.4.4 Adding a context menu to the shortcut bar 202 12.5 Shortcut Bar Sample 203
13Chapter 13 Tabbed Windows
13.1 Overview 205
13.2 The Tabbed Window Classes 207 13.2.1 SECTabControlBase 207 13.2.2 SECTabControl 207 13.2.3 SEC3DTabControl 208 13.2.4 SECTabWndBase 208 13.2.5 SECTabWnd 208 13.2.6 SEC3DTabWnd 209
xi 13.3 Tabbed Window Styles 210
13.4 Tab Control Notification Messages 212
13.5 Using SECTabWnd and SEC3DTabWnd 213 13.5.1 To add SECTabWnd or SEC3DTabWnd to a frame window 213 13.5.2 To add a tabbed window to a dialog 214 13.5.3 Removing the 2D Tab Scroll Buttons 214 13.5.4 To put 3D tabs on the side or top of the tabbed window 214 13.5.5 To enable scroll bars in the 2D tabbed window 215 13.5.6 To add keyboard accelerator support 215 13.5.7 To add a window to the tabbed window 216 13.5.8 To create and add a view to the tabbed window 216 13.5.9 To remove a tab 217 13.5.10 To access the CWnd associated with a tab 217 13.5.11 To change the font of a tab 218 13.5.12 To receive user event notifications from the tabbed window 218 13.5.13 To get a pointer to the SECTabWnd from a contained view 218 13.5.14 To insert a splitter window into a tabbed window 219 13.5.15 Problem with Tabbed Windows in Docking Views 219
13.6 Tabbed Window Sample 220
14Chapter 14 Tree Control & Tree View
14.1 Overview 221
14.2 The Tree Control Classes 222 14.2.1 SECTreeCtrl 222 14.2.2 SECListCtrl 222
14.3 The Tree View Classes 223 14.3.1 SECTreeView 223 14.3.2 SECListView 223
14.4 Tree Control Data Structures 224 14.4.1 TV_ITEM 224 14.4.2 NM_TREEVIEW 224 14.4.3 TV_HITTESTINFO 225
14.5 Tree Item States 226
14.6 Tree Control/Tree View Styles 228
14.7 Tree Control Notifications 232
14.8 Using the Tree Control Classes 234 14.8.1 To create a tree control in a dialog 234 14.8.2 To create a tree control dynamically 234 xii 14.8.3 To add a tree item 235 14.8.4 To create multiple columns 235 14.8.5 To set the text on subitems of multi-column trees 236 14.8.6 To create a standard image list for tree items 236 14.8.7 To create a state image list for tree items 236 14.8.8 To create a tree item with a state image 236 14.8.9 To change a state image on a tree item 237 14.8.10 To add an overlay image to a tree item 238 14.8.11 To find out which items are selected 238 14.8.12 To specify different colors for tree items 238 14.8.13 To specify different fonts for tree items 239 14.8.14 To update the tree control 239 14.8.15 To incorporate SECTreeCtrl into an application already using CtreeCtrl 240
14.9 Tree Control Samples 241
15Chapter 15 User Interface Extensions
15.1 Overview 243 15.2 Bitmapped Dialog 243 15.2.1 Using SECBitmapDialog 244 15.2.2 Customizing SECBitmapDialog 244 15.3 Gradient Caption Extension 245 15.3.1 The Gradient Caption Classes 245 15.3.2 SECFrameWnd 245 15.3.3 SECMDIFrameWnd 246 15.3.4 Using the Gradient Caption Feature 246
15.4 Keyboard Shortcuts 247 15.4.1 The Keyboard Shortcut Classes 247 15.4.2 SECShortcutTable 247 15.4.3 SECCommandList 247 15.4.4 SECShortcutDlg 247 15.4.5 Using the Keyboard Shortcut Classes 248 15.4.6 Keyboard Shortcut Sample 251
15.5 Splash Window 252 15.5.1 The SECSplashWnd Class 252 15.5.2 Using SECSplashWnd 253 15.5.3 SECSplashWnd Samples 253
15.6 Custom Status Bar 254 15.6.1 Using SECCustomStatusBar 254 15.6.2 Customizing SECCustomStatusBar 257
xiii 15.7 Thumbnail Classes 259 15.7.1 The Thumbnail Classes 259 15.7.2 Using the Thumbnail Classes 261 15.7.3 Thumbnail Sample 261
15.8 Tip of the Day Dialog 262 15.8.1 The SECTipOfDay Class 262 15.8.2 SECTipOfDay Resource IDs 262 15.8.3 Using SECTipOfDay 263 15.8.4 SECTipOfDay Sample 265
15.9 Tray Icon Class 266 15.9.1 To incorporate the Tray Icon Class into your application 266 15.9.2 To add notification handlers for mouse events 267 15.9.3 To animate a tray icon 268 15.9.4 Tray Icon Sample 268
15.10User-Tools Menu 269 15.10.1 The User-Tools Menu Classes 269 15.10.2 Using the User-Tools Menu Classes 270 15.10.3 User-Tool Menu Sample 271 15.11Workspace Manager 271 15.11.1 The Workspace Manager Classes 271 15.11.2 Using SECWorkspaceManagerEx 273 15.11.3 Using SECWorkspaceManager 278 15.11.4 Workspace Manager Samples 279
15.12Full-Screen View 280 15.12.1 The Full-Screen View Class 280 15.12.2 SECFullScreenView Styles 281 15.12.3 Using the SECFullScreenView Class 281 15.12.4 SECFullScreenView Sample 283
16Chapter 16 Utility Classes
16.1 Overview 285 16.2 Compressed File I/O 285 16.2.1 SECCompressFile 285 16.2.2 Using SECCompressFile 286 16.2.3 SECCompressFile Sample 286
16.3 Encrypted File I/O 287 16.3.1 Electronic Codebook (ECB) 287 16.3.2 Output Feedback Mode (OFB) 287 16.3.3 The SECCryptoFile Classes 287
xiv 16.3.4 The Encryption Algorithm 288 16.3.5 Limitations 290 16.3.6 Using SECCryptoFile 290 16.3.7 SECCryptoFile Sample 291
16.4 Safe Multi-Threaded Trace Output 292 16.4.1 Use of the Multi-Threaded Logging Class 292
16.5 File System Access 294 16.5.1 SECFileSystem 294 16.5.2 Using SECFileSystem 294 16.5.3 SECFileSystem Sample 296
16.6 Random Number Generation 297 16.6.1 The SECRandom Class 297 16.6.2 Using SECRandom 298 16.6.3 SECRandom Sample 299
16.7 Formula Engine 300 16.7.1 Features of the Formula Scanner 300 16.7.2 Use of the Formula Engine Class 300
16.8 Win32 Registry Access 302 16.8.1 The SECRegistry Class 302 16.8.2 Using SECRegistry 302 16.8.3 SECRegistry Sample 305
17Chapter 17 Data Extraction Classes
17.1 Overview 307 17.1.1 Building the Libraries 307 17.1.2 Using Regular Expression Libraries 309
17.2 Data Extraction Framework 310
17.3 Example: Setting Up a Scanner 311 17.3.1 Introduction to the Deals Sample 311 17.3.2 Declaring the Processor 311 17.3.3 Implementation Details 313
xv 17.4 Note on Exceptions 320
18Chapter 18 View Classes
18.1 Overview 321
18.2 The Zoom and Pan View Classes 321
18.3 SECZoomView 322 18.3.1 SECPanView 322 18.3.2 SECPanWnd 322
18.4 Zoom Modes 323
18.5 Using the View Classes 324 18.5.1 To incorporate zooming support into an application 324 18.5.2 To incorporate panning support into an application 324 18.5.3 To incorporate a panning overview window to an application 325 18.5.4 Key Zooming Methods 325 18.5.5 Key Panning Methods 326
18.6 Zooming/Panning Sample 328
19Chapter 19 ActiveScript Hosting Framework
19.1 Overview 329
19.2 Overview of JavaScript 330 19.3 VBScript 330 19.4 Hosting an Active Script 330 19.5 ActiveScript Classes 331 19.5.1 SECAAppObj 331 19.5.2 SECAFormObj 331 19.5.3 SECAScriptHost 331 19.5.4 SECAScriptOccManager 332 19.5.5 ActiveScriptErrorHandler 332
19.6 Using the ActiveScript Framework 333 19.6.1 ActiveScript and Type-libraries 333 19.6.2 To prevent the Objective Toolkit library from automatically including ScriptHost.tlb as resource 333 19.6.3 To incorporate scripting into your application 333
xvi 19.7 ActiveScript Sample 335
20Chapter 20ActiveHost Form Scripting and Editing Framework
20.1 Overview 337
20.2 ActiveHost Classes 338 20.2.1 SECScriptHostDoc 338 20.2.2 SECScriptHostView 338 20.2.3 SECAFloatDocTemplate 338 20.2.4 SECADlgFrame 338
20.3 Using the ActiveHost Form Editing Framework 339 20.3.1 To incorporate ActiveHost into your application 339 20.4 The ActiveHost Sample 339
21Chapter 21 Advanced Docking Windows
21.1 Overview 341
21.2 Advanced Docking Windows Architecture 342
21.3 Advanced Docking Windows Features 343 21.3.1 Docking Inside an MDI Child Frame 343 21.3.2 Floating MultiDock Mode 343 21.3.3 Realtime Drag Mode 343 21.3.4 Alternate Border Layout Logic 343 21.3.5 Advanced Docking Configurations 344
21.4 Advanced Docking Windows Splitter Styles 345
21.5 Using the Advanced Docking Windows Architecture 347 21.5.1 To incorporate advanced docking windows into your application 347 21.5.2 To create dockable device context nodes 350 21.5.3 To use docking insertion constraints 351 21.5.4 To adjust the border sizing 353 21.5.5 To use ‘real-time’ drag mode 354 21.5.6 To use floating multidock mode 354 21.5.7 To use alternate border layout logic 354 21.5.8 To integrate a dockable node inside an MDI child frame 356
xvii 21.6 Advanced Docking Windows Examples 358
22Chapter 22 Docking Views
22.1 Overview 359
22.2 Features of Docking Views 360
22.3 Issues when Docking a CView 361
22.4 Docking Views Options 362
22.5 The Docking Views Classes 363 22.5.1 SECDockableFrame 363 22.5.2 SECFrameBar 363 22.5.3 SECMDIChildWnd 364 22.5.4 SECMultiDocTemplate 364
22.6 Architectural Overview 365
22.7 Docking Views Containment Model 366
22.8 WM_SYSCOMMANDEX 368
22.9 Docking Views and MDI Alternatives 369 22.10Using the Docking Views Architecture 369 22.10.1 To incorporate docking views into your application 369 22.10.2 To set docking view styles 369 22.10.3 To toggle the presence of the docking button on a dockable view frame 369 22.10.4 To disable right mouse double-clicks on the docking view caption bar 371 22.10.5 To create an initially docked view 371 22.10.6 To start an application with no initial view 372 22.10.7 To put a splitter in a docking view 372 22.10.8 To dock a view 373 22.10.9 To float a view as an MDI child 373 22.10.10 To obtain a pointer to the view 373 22.10.11 To control the initial size and position of a docking view as it is docked 374
23Chapter 23 Layout Manager Framework
23.1 Overview 375
23.2 Issues with Resizable Windows 376
23.3 Benefits of the Objective Toolkit Layout Manager 377 23.3.1 Objective Toolkit Layout Manager: MFC Integration 377 23.3.2 Objective Toolkit Layout Manager: Strong Architecture 377 23.3.3 Objective Toolkit Layout Manager: Ease of Integration 377 xviii 23.4 Layout Manager Architecture 379 23.4.1 Layout Nodes 379 23.4.2 Window Listeners 382 23.4.3 Layout Factory 382 23.4.4 Splitter Node 382
23.5 Layout Algorithms 383 23.5.1 Alignment Layout 383 23.5.2 Scale Layout 383 23.5.3 Grid Layout 384 23.5.4 GridBag Layout 384 23.5.5 Relative Layout 385
23.6 Using the Layout Manager 387 23.6.1 Adding Layout Management to Your Applications 387
23.7 Layout Manager Examples 388 23.7.1 Scale Layout in a Dialog 388 23.7.2 Relative Layout in a Dialog 388 23.7.3 Grid Layout, Alignment Layout and Splitter in a Formview 389 23.7.4 To specify min/max sizes for layout nodes 390 23.7.5 To implement a custom layout manager 390 23.8 Layout Manager Sample 390
24Chapter 24 Microsoft Agent Extensions
24.1 Overview 391 24.2 Overview of Microsoft Agent Technology 391
24.3 Agent Extension Classes 392 24.3.1 SECAgentCharacterExPtr 392 24.3.2 IAgentApp 392 24.3.3 SECAgentApp 392 24.3.4 SECAgentCharAct 393 24.3.5 SECAgentNotifySink 393
24.4 Using the Agent Extension Classes In Your Applications 394 24.4.1 Agent Extensions Sample 394
xix 25Chapter 25 Namespace Extension Wizard
25.1 Overview 395 25.2 Installing Stingray Namespace Extension Wizard 395
25.3 Creating a Skeleton Namespace Extension 396 25.4 Selecting Namespace Options 396 25.4.1 Show Up 396 25.4.2 Register For 396 25.4.3 Support UI Object 397
25.5 Tutorial 398 25.5.1 Create the Skeleton Namespace Extension Project 398 25.5.2 Work Through the Generated Code 399 25.5.3 Change The Data Structure For PIDL 401 25.5.4 Implementing CreateEnumIDList() 401 25.5.5 Modify CNSExtCompView::InitList() 403 25.5.6 Give Each Node an Informative Name 407 25.5.7 Change the Default Context Menu Handling 408 25.5.8 Give Node An Icon 410
26Chapter 26 TheHyperlinkClasses
26.1 Overview 413
26.2 Using the Hyperlink Classes 414 26.3 Customizing the Hyperlink Control 415 26.4 Sample 415
27Chapter 27 Web Browser Extensions
27.1 Overview 417 27.2 Feature List 417 27.2.1 Getting the IWebBrowser2 Interface in IE 417 27.2.2 Init IWebBrowser2 with HTML in Memory 418 27.2.3 Retrieve HTML in IWebBrowser2 418 27.2.4 CHTMLView Extensions 418 27.2.5 Miscellaneous Utility Functions 419
xx 27.3 Sample 419
28Chapter 28 The APP ATL Object
28.1 Overview 421 28.1.1 Overview of Asynchronous Pluggable Protocol 421
28.2 Objective Toolkit APP ATL Object Classes 422 28.2.1 SECPlugProt 422 28.2.2 SECPlugProtImp 422 28.2.3 FileDownloadInfo 422 28.2.4 SECWorkerThreadFetchObject 422 28.2.5 WorkerThreadMain 422
28.3 Using the Objective Toolkit APP ATL Object in Your Applications 423 28.4 Sample 423
29Chapter 29 ATL and Objective Toolkit Components
29.1 Overview 425
29.2 Wrapping Objective Toolkit Components in an ATL ActiveX Control 426
29.3 An Example: An ATL ActiveX Control Built From SECTreeCtrl 427 29.3.1 Pre-Build Set-Up 431 29.3.2 Building Your Control 433 29.3.3 Testing Your Control 433
29.4 Further Extensions 439 29.5 Sample Code 440
30Chapter 30 Introduction to Objective Toolkit for ATL
30.1 Overview 441
30.2 Features and Benefits 442 30.2.1 Features of Objective Toolkit for ATL 442
30.3 COM Collection Classes 443
30.4 Threading Classes 445
30.5 Interface Token Class 446
30.6 Functors 447 30.6.1 Constructing Functors 447
xxi 30.6.2 Invoking Functors 447 30.6.3 Interface Tokens and Functors 448 30.6.4 Threads and Functors 448
30.7 SAFEARRAY Classes 449 30.7.1 COtlSimpleSafeArray 449
30.8 RGSEdit 451 30.8.1 Changing What Gets Registered 451 30.8.2 Editing a Registry Script 452 30.8.3 Adding Keys 452 30.8.4 Editing Keys 452 30.8.5 Deleting Keys 452 30.8.6 Adding Values 452 30.8.7 Editing Values 453 30.8.8 Managing Categories 453 30.8.9 Launching RGSEdit from the IDE 454
30.9 Microsoft Message Queue Class 455 30.9.1 Requirements 455 30.9.2 Creating a queue 455 30.9.3 Opening a queue 455 30.9.4 Receiving Messages 456 30.9.5 Sending Messages to a Queue 456 30.9.6 Cleanup 457
30.10XML Helpers 458 30.10.1 Creating an XML Document From Scratch 458 30.10.2 Opening an Existing XML Document 458 30.10.3 Adding Tags 458 30.10.4 Saving the XML Document to a File 458 30.10.5 Reading Tag Values 459 30.10.6 Trace Output 459
30.11Internet Explorer Band Object Wizard and Classes 460 30.11.1 Changing Size Constraints 460 30.11.2 Context Menu Commands 460
30.12Desktop Application Toolbar Class and Object Wizard 462 30.12.1 Creating an AppBar 462 30.12.2 Docking and Layout 462 30.12.3 Appbar Tab Window Control 462 30.12.4 Creation 463 30.12.5 Message Reflection 463 30.12.6 Image List 463 30.12.7 Selection Notification 463
xxii 30.13Window Layout Manager for Composite Controls 464 30.13.1 Layout Manager Algorithms 464 30.13.2 Scale Layout 464 30.13.3 Relative Layout 464 30.13.4 Adding Layout Management to Your Applications 465
30.14COM Task Allocator Memory Debugging Tools 466 30.14.1 Using the Task Allocator Debugger 466
30.15Marshaling Classes 467 30.16Software Requirements 469 30.17Distributing Objective Toolkit for ATL Applications 469 Index 471
xxiii xxiv Chapter 1 Introduction to Objective Toolkit
1.1 Welcome to Objective Toolkit
Objective Toolkit is a set of MFC extension classes that enhance your current Visual C++/Microsoft Foundation Class programs. Objective Toolkit provides support for a variety of graphical user interface controls, views, and utilities. You can extend its object-oriented classes quickly and easily.
Unlike other C++ class libraries, Objective Toolkit classes are completely compatible with the Mic- rosoft Foundation Class (MFC) classes. The Objective Toolkit classes work seamlessly with the MFC classes and, in many cases, inherit from existing classes such as CView or CWnd.
Objective Toolkit is fully compatible with the latest 32-bit and 64-bit releases of Microsoft Visual Studio (see Section 1.3, “Supported Platforms.”).
Objective Toolkit components enable you to dedicate your efforts to creating a viable application, instead of modifying the GUI, by providing you with extension classes for common user-interface features.
Chapter 1 Introduction to Objective Toolkit 1 1.2 Product Features
The following sections describe some of the major features of Objective Toolkit.
1.2.1 MFC Extension Classes
Simple Control Classes. Objective Toolkit consists of a variety of powerful classes that provide advanced GUI components, such as:
Owner-draw, bitmap, menu, and well buttons.
Color well, pop-up color well, masked edit, browse edit, and editable list box controls.
2-D and 3-D tab controls/tabbed windows.
Calculator, calendar, currency, and date/time edit controls.
Custom status bar, custom toolbar, and a tree control with enhanced functionality.
The source code for every window and control class is in the Src\Toolkit\Controls subdirectory.
User Interface Extensions. Objective Toolkit includes a number of user-interface extensions that address high-level UI design issues. A user-interface extension is a class or set of classes that enhances the look, configuration capability, or information content of your user interface. The source code for all MDI alternatives and enhancements is in the Src\Toolkit\UI subdirectory.
Image Classes. Objective Toolkit contains a group of classes that let you read, write, convert between, and manipulate popular image formats. Supported formats include DIB, GIF, JPEG, PCX, TGA, and TIFF. The source code for each image class is in the Src\Toolkit\Image subdirectory.
Docking Windows Architecture. The extended control bar architecture is a set of MFC extensions that augment the docking window features available in MFC version 4.x. There are two categories of extended control bar classes: control bar derivatives and frame window derivatives. Control bar classes include:
Control bar and control bar manager
Dialog bar, toolbar and toolbar manager
Status bar
MDI Alternatives and Enhancements. Objective Toolkit implements several MDI alternatives and enhancements. The Multiple Top-level Interface (MTI) and the Floating Document Interface (FDI) are alternatives to MDI. The Workbook Document Interface (WDI) and Gradient Caption class enhance MDI. The source code for all alternatives and enhancements is in the Src\Toolkit\MDI directory.
Objective Toolkit provides replacements for MFC’s frame window classes that add significant func- tionality. The Frame window classes include SECFrameWnd, SECMDIChildWnd, and SECMDIFrameWnd.
2 Toolbar Classes. The Stingray toolbar replacement for CToolBar supports the enhanced docking window features. It also gives you the ability to resize the toolbar when it is docked and maintain compatibility with our enhanced docking windows implementation. These classes also support drag-and-drop customization, large/small icon view modes, and an Microsoft Office look-and-feel.
Utility Classes. Objective Toolkit also provides classes that are not related to the user interface. For example:
SECRegistry provides a sophisticated interface to the registry.
SECRandom supports random number generation.
SECFileSystem provides an encapsulation of the run-time access to the file system.
SECCryptoFile is a CFile derivative that provides encryption.
SECCompressFile is a CFile derivative that provides compression.
The source code for all utility classes is in the Src\Toolkit\Utility subdirectory.
View Classes. The Objective Toolkit view classes are CView extensions that provide features such as advanced zooming and panning. The zooming feature lets the user zoom in and out of a view and automatically handles all mapping mode changes. Panning is a popular scrolling extension used in Windows applications like Delrina WinFax. The source code for all view classes is in the Src\Toolkit\Views subdirectory.
1.2.2 Full Source Code
The complete source code for Objective Toolkit is included with the product. The source code is indispensable for debugging, using, and inheriting from an MFC extension class. The source code is in the \Include\Toolkit and \Src\Toolkit directories. File names reflect the classes they contain.
1.2.3 Compatibility and Build Options
For maximum flexibility, you can use Objective Toolkit with the latest Microsoft Visual Studio com- pilers (see Section 1.3, “Supported Platforms.”). Moreover, you can use Objective Toolkit as a static library with MFC static, as a static library with MFC as a DLL, or as a DLL with MFC as a DLL. Objective Toolkit supports Unicode. Unicode and non-Unicode variants exist for all static and DLL builds.
Once the Objective Toolkit libraries are built, these configurations are transparent to you.
Chapter 1 Introduction to Objective Toolkit 3 1.3 Location of Samples
Stingray Studio ships the most basic and commonly used samples with the product itself. The less commonly used and more specialized samples have been removed from the product distribution, but are available from the Rogue Wave web site.
If you are looking for a sample and it does not appear under
1.4 Supported Platforms
For a list of supported operating systems and compilers, see http://www.roguewave.com/products/stingray.aspx, then click on the link “Supported Plat- forms” to download a PDF.
1.5 Getting Help
Several avenues of help are available to you when working with Objective Toolkit.
1.5.1 Documentation
Documentation is located in the Docs subdirectory of your Objective Toolkit directory. The follow- ing documents are available:
User's Guide - This manual. The User's Guide provides an introduction to Objective Toolkit and a foundation for using Objective Toolkit “out-of-the-box.” Several tutorials help new Objective Toolkit users learn how to create Objective Toolkit applications quickly. This manual assumes that you are familiar with Visual C++ and the Microsoft Foundation Classes (MFC). This document is available in two formats: HTML Help (otug.chm) and Portable Document Format (otug.pdf).
Reference Guide- The reference document (otref.chm) is a detailed description of the properties, methods, and events in Objective Toolkit.
ReadMe file - The latest information about the product, Toolkitreadme.htm located in the Readme directory under your Stingray installation directory.
For more information on the documentation, including all Stingray documentation, an index to the Help files, and document type conventions, see Section 1.4, “Product Documentation,” in the Sting- ray Studio Getting Started Guide.
4 1.5.2 Knowledge Base
The Rogue Wave Knowledge Base contains a large body of useful information created by the Sup- port Services team. This information is available to any user of the Rogue Wave Web site, and no login or registration is required. http://www.roguewave.com/support/knowledge-base.aspx.
1.5.3 Professional Services
The Rogue Wave Professional Services offers training and mentoring for all levels of project devel- opment, from analysis and design to implementation. For more information, see Section 1.5, “Professional Services,” in the Stingray Studio Getting Started Guide.
1.5.4 Technical Support
Technical support for Objective Toolkit products is provided through the Rogue Wave Web site. For more information on registering with the support system, and the type of support you may receive, see Section 1.6, “Technical Support,” in the Stingray Studio Getting Started Guide.
1.6 Licensing Restrictions
Please read the license agreement that was shipped with this package. You are bound by the licens- ing restrictions contained in that document. Do not use this product unless you can accept all the terms of the license agreement.
You can use all the files accompanying this product for development of an application. You can dis- tribute the Objective Toolkit Dynamic Link Libraries (DLLs) according to the terms of the license agreement.
Your applications can also statically link to Objective Toolkit, in which case you do not need to redistribute any Objective Toolkit files—except any required language configuration files.
Chapter 1 Introduction to Objective Toolkit 5 6 Chapter 2 Objective Toolkit Quick Start
2.1 Overview
The following sections describe how to build Objective Toolkit and setup your application to utilize its features.
2.2 Installation
Before continuing, ensure that Objective Toolkit has been properly installed on your system. If you have any questions about installation requirements, please refer to the Installation Guide.
2.3 Building Objective Toolkit
You can build Objective Toolkit in many different ways to support a variety of operating systems and VC++/MFC configurations. For example, you can build Objective Toolkit for any of the latest Visual Studio compilers. (For a full support matrix, go to the Stingray product page on the Rogue Wave web site, www.roguewave.com/products/stingray.aspx, and click on Supported Plat- forms.) In addition, your build configuration may specify any combination of build flags such as debug or release, Unicode or ANSI, static or DLL.
You can obtain prebuilt versions of the libraries by request to Rogue Wave technical support. Libraries are available for Windows XP and Vista with the currently supported compilers. We rec- ommend, however, that you build the libraries yourself. The prebuilt libraries are built with a particular instance of Visual Studio and the Windows operating system. Building the libraries yourself ensures that they are compatible with your version of the compiler and the operating sys- tem they are built on.
Chapter 2 Objective Toolkit Quick Start 7 A Build Configuration Wizard is included with Objective Toolkit (utils\ToolkitBuildWiz.exe). The Build Wizard is a powerful tool that allows you to build various versions of the Objective Tool- kit library with different configurations. For example, you can build a version of the library that only includes the features that pertain to your project. This is an effective technique for reducing the binary size of the resulting Objective Toolkit libraries and DLLs.
Objective Toolkit is distributed with build files for the default configuration that includes all the Toolkit features. You do not need to run the Build Wizard to build the default configuration.
The SRC subdirectory contains build files for every version of Visual Studio that Objective Toolkit supports. To build Objective Toolkit, open the appropriate build file. After you load it, examine the different build configurations that specify the settings such as debug or release, Unicode or ANSI, static linking or DLL, and more. You can choose a particular configuration and build only that library variant, or select the All configuration and build every variant of the Objective Toolkit library in one build session. To choose a build configuration, select an item from the Set Active Configuration combo box in Visual Studio or start a Batch Build and select several variants to be built at once.
2.3.1 Using the Build Wizard
The Build Configuration Wizard is a wizard dialog that allows you to select every feature you want to include in the resulting library. After you answer a few simple questions, the Build Wizard auto- matically generates a custom tailored makefile that you can build to create the Objective Toolkit library in the configuration you specified. You can customize the names of the libraries to avoid any potential name collisions or versioning problems.
You can generate multiple library configurations with the Build Wizard. For example, you could generate one with just a tree control and another with only the docking windows code. Several dif- ferent configurations can coexist on your hard disk simultaneously. The Wizard dialogs describe this procedure. Give the target libraries of different build configurations different target names to avoid name collisions.
The Objective Toolkit components are now built into two libraries: Stingray Foundation Library (SFL) and OT. If you want to create a set of libraries with a special configuration, you should run the Build Wizard for both libraries, specifying the same configuration name.
2.3.1.1 To build a custom configuration version of the library
1. Run the SFL Library Build Wizard.
2. On the second panel, specify the configuration name (for example, MyConfig). Use the Build Wizard to specify custom library names for the common library.
3. Run the Objective Toolkit library Build Wizard. After you enter the configuration name (for example, MyConfig), select the components you want to include in the build of the library, and then enter names for your custom library.
4. Rebuild the Objective Toolkit library to automatically build the Objective Toolkit and SFL libraries.
8 The Build Wizards automatically generate custom linking header files that you can include in your project. These header files are located in the include\toolkit\config directory for the Toolkit library and include\foundation\config directory for the SFL library. The Build Wizard created these files when you rebuilt the library. They have the same name as the library to which they link, with the added prefix sfl_ or ot_ .
To link to the custom configuration in your application, insert the following lines into stdafx, before you include toolkit\secall.h or any Objective Toolkit component headers.
#include "foundation\config\sfl_MyConfig.h" #include "toolkit\config\ot_MyConfig.h" #include "toolkit\secall.h"
If you are working with the default configuration, you do not need to include the xxx_Default.h header files.
2.3.2 DLL naming issues
When you build a custom configuration of Objective Toolkit, you must specify a unique DLL target name. When you build a subset of the Objective Toolkit features or make a change to the Objective Toolkit source or header files, the signature of the library changes. So, when you build a DLL that incorporates a subset of Objective Toolkit features or your own changes, you need to treat the tar- get DLL like a completely unique DLL. If you change the signature of Objective Toolkit and do not specify a new DLL target name, other applications that link to the Objective Toolkit DLL may fail.
2.3.3 Compiler Flags
The Objective Toolkit build files and header files use #ifdef’s on several compiler flags to define the configuration variants described above.
You can use the standard symbols, _DEBUG, _UNICODE, and _AFXDLL, to select support for debug- ging, Unicode characters, and linking to MFC as a DLL.
The flags in Table 1 are specific to Objective Toolkit.
Chapter 2 Objective Toolkit Quick Start 9 Table 1 – Objective Toolkit flags
Flag Definition
_SECDLL Links to the Objective Toolkit library as a DLL.
_SECNOAUTOLIB Prevents the Objective Toolkit autolink mechanism from working. If this is defined, you need to explicitly list the Objective Toolkit libraries you want to link to in your project's link settings.
_SECNOMSG Prevents the output of Objective Toolkit related messages when you build.
SEC_NO_TLB Objective Toolkit automatically includes its ScriptHost.tlb as resource 1 when the ActiveScript headers are included in an application. This can conflict with applications containing ActiveX components. Defining SEC_NO_TLB pre- vents this problem from occurring.
2.3.4 Build Target Naming Conventions
The library naming conventions are illustrated in Figure 1. Figure 1 – Build Configurations
10 2.3.5 Build Configuration Options
The following table shows the default library names for the various configurations, where
Library Objective MFC Unicode Build Type name Toolkit library configuration supported configuration
OT
OT
OT
OT
OT
OT
OT
OT
OT
OT
OT
OT
Objective Toolkit makefiles place .lib, .dll and .pdb files into the directory OT\lib\
2.3.6 To build the 32-bit or 64-bit libraries
1. Start Visual Studio.
2. Check the Visual Studio environment directory paths for both Win32 and x64 settings to ensure that the Include, Source, Library and Executable paths contain the appropriate Sting- ray Studio include, source, library and executable directory paths. Please refer to Section 2.6.3, “Stingray Studio Paths in Property Sheets,” in the Stingray Studio Getting Started Guide for pathing details.
3. Open the solution file appropriate to the compiler version you are using.
4. Choose the platform, i.e. Win32 or x64, and then choose the build configuration to build.
5. Start the build.
Intermediate files use approximately 250 Mb of space, and library files use approximately 80 Mb of space.
Chapter 2 Objective Toolkit Quick Start 11 2.3.7 Miscellaneous Build Issues
2.3.7.1 Using Multiple Library Configurations
Whenever you run the Build Wizard, it overwrites sflversion.h in the SFL (include\foundation) include directory or secver.h in the Objective Toolkit (include\toolkit) include directory with the names of the libraries. This information is used to link the libraries to your project automatically.
If you are maintaining more than one library configuration on your system, this can cause prob- lems. Your projects link to whatever configuration was last set up by the Build Wizard.
To avoid problems when switching library configurations, run the Build Wizard specifying the desired configuration for each of the Objective Toolkit libraries.
2.3.7.2 Make Files and Building Directly with nmake
When you build the Stingray libraries in Visual Studio, Visual Studio invokes make files that ship with the product. For information on these underlying make files, and how to build the libraries by invoking nmake on these files directly, see Section 2.2, “Building from the Command Line with nmake,” in the Stingray Studio Getting Started Guide.
This section also discusses the issue of building the libraries with 1-byte structure alignment rather than the default 8-byte structure alignment.
2.3.7.3 Components Requiring RTTI Support
Run-Time Type Information (RTTI) support is required for some components. When you run the Build Wizard, RTTI support must be enabled if you include:
Layout Manager
Advanced docking windows (ADW) components
Full Screen view components
Outlook bar
SECMultiDocTemplate and related code
Microsoft Agent
To learn more about this requirement, see our Knowledge Base at (kb.roguewave.com/kb/).
12 2.3.8 Building the Samples
Each sample project has a variety of build options to show you how to use the various build config- urations. All 32-bit and 64-bit samples build with the following targets:
Table 2 – Build Configurations for Samples
Build Configuration Description
WIN32 or x64 – Lib MFC Lib Objective Toolkit as a static library, MFC as a Debug static library, ANSI, Debug
WIN32 or x64 – Lib MFC Lib Objective Toolkit as a static library, MFC as a Release static library, ANSI, Release
WIN32 or x64 – Lib MFC DLL Objective Toolkit as a static library, MFC as a Debug DLL, ANSI, Debug
WIN32 or x64 – Lib MFC DLL Objective Toolkit as a static library, MFC as Release DLL, ANSI, Release
WIN32 or x64 – DLL MFC DLL Objective Toolkit as a DLL, MFC as a DLL, Debug ANSI, Debug
WIN32 or x64 – DLL MFC DLL Objective Toolkit as a DLL, MFC as a DLL, Release ANSI, Release
WIN32 or x64 – Lib MFC Lib Uni Objective Toolkit as a static library, MFC as a Debug static library, Unicode, Debug
WIN32 or x64 – Lib MFC Lib Uni Objective Toolkit as a static library, MFC as a Release static library, Unicode, Release
WIN32 or x64 – Lib MFC DLL Objective Toolkit as a static library, MFC as a Uni Debug DLL, Unicode, Debug
WIN32 or x64 – Lib MFC DLL Objective Toolkit as a static library, MFC as a Uni Release DLL, Unicode, Release
WIN32 or x64 – DLL MFC DLL Objective Toolkit as a DLL, MFC as a DLL, Uni- Uni Debug code, Debug
WIN32 or x64 – DLL MFC DLL Objective Toolkit as a DLL, MFC as a DLL, Uni- Uni Release code, Release
To build the samples, you need to build the appropriate Objective Toolkit library configuration first.
2.3.9 Automatic linking
If you check the Project Settings|C/C++ tab|Preprocessor Definitions for several target configu- rations, you can see how the compiler flags link to the appropriate Objective Toolkit library variant automatically.
Chapter 2 Objective Toolkit Quick Start 13 You indicate exactly which Objective Toolkit library you want to link by defining a combination of _DEBUG, _AFXDLL, _UNICODE, and _SECDLL in your project’s preprocessor definitions.
2.3.10 To incorporate Objective Toolkit into your application
After you build the libraries, you can start using Objective Toolkit classes in your own applications. Follow the steps below to add Objective Toolkit to an existing application.
1. Load your project into Visual Studio.
2. Add the following the line to the end of your stdafx.h header file. Because stdafx.h is normally included in all your source files, this makes the Objective Toolkit classes available throughout your project. You can optimize your application’s build speed by using the Objective Toolkit component-specific headers instead of secall.h.
#include “toolkit\secall.h”
If you are linking to a custom library configuration, include the custom headers before the secall.h include. For example:
#include "foundation\config\sfl_MyConfig.h" #include "toolkit\config\ot_MyConfig.h" #include “toolkit\secall.h”
Finally, add includes for these header files, common to all Stingray Studio products:
Add #include
The conditional platform information is displayed in the application's output window. The output information is helpful when developing and deploying across one or more platforms.
Add #include
This file facilitates the inclusion of manifest definitions for Windows Visual Styles.
3. Open the View|Resource Includes dialog and add the following line to the list of read- only symbol directives.
#include “toolkit\secres.h”
4. Add the next line to the list of compile-time directives.
#include “toolkit\secres.rc”
Add a combination of _DEBUG, _UNICODE, _AFXDLL, and _SECDLL to the Project Set- tings|C/C++ tab|Preprocessor Definitions. This automatically causes the correct variant of the Objective Toolkit library to be included in your project. _AFXDLL and _DEBUG may be defined automatically by other project settings.
If you have any problems using a specific class, refer to the online Objective Toolkit Class Reference. Each section of the Class Reference discusses one class or a group of related classes and includes an overview, step-by-step instructions, and important member functions. We also cite Objective Tool- kit samples that demonstrate the use and capabilities of the class.
14 For information on creating an application with our AppWizard, see Chapter 3, “The Objective Toolkit AppWizard.” For information on using component headers, see Section 2.6.1.
Chapter 2 Objective Toolkit Quick Start 15 2.4 Distributing Objective Toolkit Applications
Please read the license agreement that was shipped with this package. You are bound by the licens- ing restrictions contained in this document. Do not use this product unless you can accept all the terms of the license agreement.
You can use all the files accompanying this product for development of an application. You can dis- tribute the with Objective Toolkit Dynamic Link Libraries (DLLs) according to the terms of the license agreement.
Your applications can also statically link to Objective Toolkit, in which case you do not need to redistribute any Objective Toolkit files.
You can also distribute the MFC DLLS with your application. Look in the compiler's root directory where you installed Visual Studio (or a previous version of VC++).You should find a document named redist.txt. This document gives details about which MFC files need to be distributed with various configurations.
16 2.5 Basic Tutorial—MaskEdit Control
The CEdit control that MFC provides is often insufficient for data entry purposes. The application can only verify the value the user entered after it is fully typed. In addition, CEdit provides no abil- ity to break the edit field into sub-fields that indicate what text is expected. SECMaskEdit addresses these problems. SECMaskEdit is derived from CEdit and it adds member functions for specifying a mask.
This tutorial uses the built-in functionality of Objective Toolkit’s SECMaskEdit class to create a masked edit field for a telephone number.
Follow the steps below to create a simple dialog-based application using the AppWizard. An SECMaskEdit object, added as a member of the dialog, displays an entry field that is formatted for a telephone number. Along the way, the application is given access to all the Objective Toolkit classes.
1. From the File menu, choose New... (Name your project application MaskPhone.)
2. From the main wizard dialog, select MFC AppWizard (exe).
Chapter 2 Objective Toolkit Quick Start 17 3. Click the Dialog based radio button.
4. Click Finish. The MFC AppWizard finishes creating the project for you.
You must follow the two additional steps below if you are going to generate your own sample programs.
5. The next thing we need to do is make sure all of the resources in Objective Toolkit are avail- able to your project. Find the stdafx.h file for the project and add the following line:
#include
Make sure the stdafx.h file reads:
// stdafx.h : include file for standard system include files, // or project specific include files that are used // frequently, but // are changed infrequently
#if !defined(AFX_STDAFX_H__DC17B08B_39B3_11D1_8889_006097BFD99B__INCLUDED_) #define AFX_STDAFX_H__DC17B08B_39B3_11D1_8889_006097BFD99B__INCLUDED_
#if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000
#define VC_EXTRALEAN// Exclude rarely-used stuff from Windows headers
#include
// if linking to a custom library configuration // include the configuration headers #include "foundation\config\sfl_MyConfig.h" #include "toolkit\config\ot_MyConfig.h"
18 #include
//{{AFX_INSERT_LOCATION}} // Microsoft Visual Studio will insert additional // declarations immediately before the previous line.
#endif //!defined(AFX_STDAFX_H__DC17B08B_39B3_11D1_8889_006097BFD99B__INCLUDED_)
6. Click View | Resource Includes… and add the following line to the Read-Only symbol directives list box:
#include “toolkit\secres.h”
In the same dialog, add the following line to the compile-time directives list box:
#include “toolkit\secres.rc”
The list boxes should look like the following:
7. Click OK. A message box with a warning appears on the screen. The wording may vary depending on the version of Visual Studio, but the appearance of the warning is standard.
Chapter 2 Objective Toolkit Quick Start 19 Create the dialog box for the control. In the Resources view, open the Dialog folder. It holds IDD_MASKPHONE_DIALOG. Open it and remove the static text that is already there.
Replace the text with an Edit box from the Controls palette. Right-click the edit box and open the properties dialog. Name the edit box IDC_PHONE_NUMBER.
8. Add a member variable of SECMaskEdit to the dialog class. Open up the header file for MaskPhoneDlg and look up OnInitDialog(). Add the following line:
SECMaskEdit m_editPhone;
9. Open MaskPhoneDlg.cpp, look up OnInitDialog(), and the add the following code to it under the TODO comment.
// TODO: Add extra initialization here: m_editPhone.AttachEdit(IDC_PHONE_NUMBER, this); // attach the mask to the edit box m_editPhone.SetMask(_T(“(###)###-#### ext. ####”));
10. Build the project and see the final dialog.
20 2.6 Using Component Headers to Increase Application Build Performance
One factor that can significantly affect the build speed of your project is the size of the precompiled header generated for your project. The larger the precompiled header becomes, the slower each source file compiles. Every header file that is included in the precompiled header contributes to its size and increases the time it takes to compile your project.
The standard mechanism for including the Objective Toolkit headers into your project is to insert a single line into stdafx.h:
#include “toolkit\secall.h”
Although this makes integrating Objective Toolkit easy, it can also potentially pull every Objective Toolkit header file into your project. This can result in large precompiled headers and long compile times. Each and every source file included in your project is affected even if you only use a single control. Although this increase in build time may be tolerable in small projects, it is unwieldy for a larger project.
One solution is to limit the number of components built into the library with the Objective Toolkit Build Wizard; however, a better solution is to include a number of component-specific header files in place of secall.h. There is a component-specific header file for each component that you can select using the Build Wizard. You can use these headers individually or they can be combined as needed to include only the components that you require.
2.6.1 The Component Headers
The component-specific header files are listed below:
Table 3 – Component Specific Header Files
Component Header file
2D/3D tabbed windows toolkit\ot_tabwnd.h
Bitmapped dialog toolkit\ot_bitmapdlg.h
Browse edit control toolkit\ot_browedit.h
Button classes toolkit\ot_buttons.h
Calculator edit control toolkit\ot_calculator.h
Calendar control toolkit\ot_calendar.h
Color listbox control toolkit\ot_colorlistbox.h
Color well classes toolkit\ot_colorwell.h
Compressed file class toolkit\ot_compressfile.h
Currency edit control toolkit\ot_currency.h
Custom status bar toolkit\ot_statusbar.h
Chapter 2 Objective Toolkit Quick Start 21 Table 3 – Component Specific Header Files (Continued)
Component Header file
Customizable toolbar/menubar toolkit\ot_toolbar.h
Date/time edit control toolkit\ot_datetime.h
Design patterns framework toolkit\ot_patterns.h
DIB image support toolkit\ot_secdib.h
Docking windows toolkit\ot_dockingwindows.h
Drop edit control toolkit\ot_dropedit.h
Editable listbox control toolkit\ot_listboxedit.h
Encrypted file class toolkit\ot_encryptfile.h
Enhanced ComboBox toolkit\ot_combobox.h
File system class toolkit\ot_filesystem.h
Floating Document Interface toolkit\ot_fdi.h (FDI)
Full Screen View class toolkit\ot_fullscreenview.h
GIF image support toolkit\ot_secgif.h
Gradient caption classes toolkit\ot_gradientcaption.h
JPEG image support toolkit\ot_secjpeg.h
Keyboard shortcut classes toolkit\ot_keyshortcut.h
Marquee control toolkit\ot_marquee.h
Masked edit control toolkit\ot_maskedit.h
Multiple Top Level Interface toolkit\ot_mti.h (MTI)
PCX image support toolkit\ot_secpcx.h
Progress control toolkit\ot_progress.h
Random number class toolkit\ot_random.h
Registry class toolkit\ot_registry.h
Shortcut bar toolkit\ot_shortcutbar.h
Splash window classes toolkit\ot_splashwnd.h
Targa image support toolkit\ot_sectga.h
Thumbnail classes toolkit\ot_thumbnail.h
TIFF image support toolkit\ot_sectiff.h
Tray icon class toolkit\ot_trayicon.h
22 Table 3 – Component Specific Header Files (Continued)
Component Header file
Tip of the day class toolkit\ot_tipoftheday.h
Tree control toolkit\ot_treectrl.h
User tools menu class toolkit\ot_usertools.h
View classes (pan, zoom) toolkit\ot_views.h
Workbook Document Interface toolkit\ot_wdi.h (WDI)
Workspace manager toolkit\ot_workspacemgr.h
ActiveScript toolkit\ot_activescript.h
Advanced docking windows toolkit\ot_advdockingwindows.h
Docking views toolkit\ot_dockingviews.h
Layout manager toolkit\ot_layoutmgr.h
MVC architecture toolkit\ot_mvc.h
2.6.2 To use the component headers in your project
You can use the component headers in the same way that you use toolkit\secall.h.
1. Using Build Wizard, build the Objective Toolkit library with the required components.
If you are linking to Objective Toolkit as a static library, you do not need to build a special version of the library. You can improve the performance by using the component-specific headers and the default library with all components. If you are linking to Objective Toolkit as a DLL, carefully select the components you build into the library, as this will affect the size of the DLL that you ship.
2. Remove or comment out the line in stdafx.h that includes secall.h. For example:
//#include
Add one or more of the component headers to stdafx.h, depending on which components your application requires. For example:
#include
// alternative to above: if you want to include ALL // Objective Toolkit headers, uncomment the following line to use // the classic Objective Toolkit inclusion method (will increase // build time) //#include
Chapter 2 Objective Toolkit Quick Start 23 3. Build your project. If you experience build errors, there are two likely causes:
A required component header was not included.
The library was built with one of the required components missing.
If you are having problems using component headers, revert to using toolkit\secall.h.
24 Chapter 3 The Objective Toolkit AppWizard
3.1 Overview
The Objective Toolkit AppWizard enables developers to generate MFC projects with functional built-in Objective Toolkit options. The AppWizard includes every standard MFC AppWizard step that you need to create a ready-to-build program template in addition to the steps you need to enable the most popular features of Objective Toolkit. These features include:
Cool Look toolbar
Customizable toolbar
Menu Bar
Bitmap Menus
WorkBook interface
Workspace management (persistence)
Docking Windows (tree control, 2D and 3D tab windows, Shortcut Bar, or owner- draw).
Docking Views
Layout Manager
ActiveScript
Model View Controller Architecture
In addition, the resulting project automatically includes all the necessary Objective Toolkit header and resource files. The Objective Toolkit AppWizard is available for all supported versions of the Visual Studio compiler.
Based on the project type (SDI, MDI, or dialog), certain features may or may not be available. Run-Time Type Infor- mation (RTTI) is enabled for all projects generated by the AppWizard.
Figure 2 shows an example of an AppWizard-generated project with a docked shortcut bar and the workbook interface.
Chapter 3 The Objective Toolkit AppWizard 25 Figure 2 – Sample Application Generated Using AppWizard
26 3.2 Creating a Skeleton Application
To create a skeleton application using Objective Toolkit AppWizard:
1. In Visual Studio, click File | New, and then select the Projects tab. This opens a list of proj- ect types. The Objective Toolkit installation added a new project type called Objective Toolkit AppWizard to your Visual Studio environment. Select this project type and then complete the dialog.
Once you finish selecting options in the New Projects dialog, the OK button becomes active. Click this button to start the wizard. Figure 3 – Using the Objective Toolkit AppWizard
The first six panels of the AppWizard look like the standard panels for the Win32 Applica- tion AppWizard. The Objective Toolkit-specific portions of the AppWizard appear after you complete the Finished panel.
Chapter 3 The Objective Toolkit AppWizard 27 Figure 4 – Step 6 of the AppWizard
2. Instead of clicking Finish, click Next to view the remaining panels and choose options spe- cific to Objective Toolkit. Figure 5 – Choosing options specific to Objective Toolkit
28 3. In this step, you can link to the Objective Toolkit libraries as either a static library or as a DLL. By default, you link statically. Choosing the DLL option adds a #define _SECDLL statement to your stdafx.h before #include “secall.h”. Later, if you decide to link stati- cally, remove the #define _SECDLL statement.
Select Enable Toolbar Customization to add an SECCustomToolBar with the two-bar grip- per as your main toolbar.
By selecting Enable Toolbar Customization, you also enable the toolbar manager and cus- tomization dialog. A Tools | Customize menu item is added to your application automatically for easy access to customization features. For more information, see Chapter 6, “Customizable Toolbars.”
The Menu Bar option adds our dockable menu class, SECMenuBar. This class can be enabled independently of bitmap menus; however, you can also use them together or in a ReBar. Figure 6 – Dockable menu
You can enable the rebar control using the standard MFC steps.
4. The next step of the AppWizard brings in more Objective Toolkit features like the tabbed workbook interface and the workspace manager, which can save the positions of all the windows and toolbars in an application. You also have the option of adding a docking win- dow with a selection of child windows to place inside the docking window.
Chapter 3 The Objective Toolkit AppWizard 29 30 5. This step is only applicable to Objective Toolkit. In this step, you select an architecture and advanced features for your application. If you want to use Model View Controller with the standard MFC Document/View architecture, check Model View Controller. If you only want to support MVC, you can uncheck the Document View support box in step one of the standard MFC steps.
You can use docking views in combination with any other options to provide a convenient mechanism for docking CView derivatives contained in MDI child windows.
The Layout Manager is available in dialog-based applications to provide scaling and posi- tioning algorithms for controls in a dialog that are independent of screen resolution. By default, a scale algorithm is applied to the dialog.
ActiveScript is integrated in your application as a separate document type. Consequently, this option is only available if you chose an MDI project type.
6. Click Finish.
Chapter 3 The Objective Toolkit AppWizard 31 7. Click OK. The AppWizard closes. You can examine the new project in Visual Studio.
8. If you are using Visual Studio 2010 or later, please refer to Section 2.6.3, “Stingray Studio Paths in Property Sheets,” of the Stingray Studio Getting Started Guide to add property sheet(s) with Stingray Studio paths to the project.
9. Compile and run the application. The skeleton application can now be used as a template for further customization.
32 Chapter 4 Simple Controls
4.1 Overview
The simple controls in Objective Toolkit enable you to implement popular GUI controls quickly and easily.
4.2 Browse Edit Controls
A browse edit control is a Windows edit control that includes a browse button positioned immedi- ately to its right. A browse button is a push button with the label .... When the user presses the browse button, a modal dialog appears. Figure 7 – Example Browse Edit Control
The modal dialog contains values that the user can select to add to the edit field. After the user chooses a value from this dialog, the text appears in the edit field. If the user knows the value, he can type it directly in the edit field without referring to the modal dialog. The purpose of the browse button is to help the user find the value he wants to enter.
Chapter 4 Simple Controls 33 4.2.1 Browse Edit Classes
The class hierarchy for the browse edit controls is as follows: Figure 8 – Objective Toolkit Browse Edit Class Hierarchy
CEdit
SECBrowseEditBase
SECBrowseFileEdit
SECBrowseDirEdit
4.2.1.1 SECBrowseEditBase
SECBrowseEditBase is an abstract base class that provides the interface and some of the function- ality of a browse edit control.
4.2.1.2 SECBrowseFileEdit
The SECBrowseFileEdit class provides the functionality for a Filename Edit control. A filename edit is a browse edit that is suited for entering a filename. With a filename edit, the user can type in a filename directly or he can pick a filename from a dialog. When the user presses the browse but- ton, a modal file selection dialog appears.
After the user selects a filename from the dialog, the full filename is automatically entered into the edit field.
4.2.1.3 SECBrowseDirEdit
The SECBrowseDirEdit class provides the functionality for a Directory Edit control. A directory edit is a browse edit in which a user can enter a directory name. With a directory edit control, the user can type a directory name directly into an edit field or pick a directory from a dialog. When the user presses the browse button, a modal directory selection dialog appears.
34 Figure 9 – Browse Edit file dialog
After the user selects a directory from the dialog, its path is automatically entered into the edit field.
4.2.2 Using the Browse Edit Classes
You can use a browse edit class in a dialog or create one as a child of a window. The steps for creat- ing a browse edit control are the same whether you’re using SECBrowseFileEdit or SECBrowseDirEdit.
You can only use the SECBrowseFileEdit and SECBrowseDirEdit classes in your applications. SECBrowseEditBase is abstract and cannot be instantiated.
4.2.2.1 To incorporate the SECBrowseEdit classes into your code
1. Use AppStudio to create a dialog template. Drop the edit control on the dialog where you want to place the File or Directory Browse Edit.
2. Create a new dialog class and attach it to the dialog template you just created.
3. Add an SECBrowseFileEdit (or SECBrowseDirEdit) as a member variable to the dialog class you just created.
4. Override the OnInitDialog() member of the dialog class. In your override, call SECBrowseFileEdit::Initialize() or SECBrowseDirEdit::Initialize() and pass the window ID of the edit control you want to convert to a browse edit. The following code below is an example of the override:
Chapter 4 Simple Controls 35 BOOL MyDialog::OnInitDialog() { CDialog::OnInitDialog();
#ifndef WIN32 CenterWindow(); #endif
m_editFilename.Initialize(IDC_FILENAME, this); m_editPath.Initialize(IDC_PATH, this); .. }
4.2.3 Customizing the Browse Edit Control
You can create your own browse edit controls by deriving a class from SECBrowseEditBase and then overriding the OnBrowse() method. The SECBrowseEditBase base class creates and positions the text field and browse button for you.
Whenever the user presses the browse button, the OnBrowse() method is automatically called. Your derived class can define the response to a browse button press by overriding the OnBrowse() method and coding your response. For example, you can display one of the common file dialogs. SECBrowseFileEdit and SECBrowseDirEdit are examples of two classes that derive from SECBrowseEditBase. Refer to their implementations for examples of how to do this.
4.3 Browse Edit Sample
The Objective Toolkit toolmenu sample in the Samples\Toolkit\MFC\UIExt\toolmenu directory demonstrates the use of the file and directory browse edits in a dialog. This sample is not shipped with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
36 4.4 Button Controls
The Objective Toolkit button classes provide useful buttons that have more features and are easier to use than those provided by MFC. The buttons types available are as follows: Figure 10 – Bitmap Buttons
Figure 11 – Menu Buttons
Figure 12 – Colorwell Buttons
Chapter 4 Simple Controls 37 4.5 Button Class Hierarchy
The button class hierarchy is as follows: Figure 13 – Objective Toolkit Button Class Hierarchy
CButton
SECOwnerDrawButton
SECBitmapButton
SECMenuButton
SECWellButton
4.5.1 SECOwnerDrawButton
The SECOwnerDrawButton class is an abstract base class that simplifies creating an owner-draw button. To create an owner-draw button, provide a method to draw the face of the button and a focus rectangle on the face of the button. You do not need to consider the state of the button (up, down, disabled, etc.) or draw the borders around the edge of the button.
4.5.2 Using SECOwnerDrawButton
You can attach objects instantiated from SECOwnerDrawButton-derived classes to dialog resources, or you can create them dynamically.
4.5.2.1 To attach an SECOwnerDrawButton to a button resource in a dialog
1. Create a derived class from SECOwnerDrawButton. You must provide an implementation for the pure virtual methods DrawFocus() and DrawSpecific().
2. Create a button resource in the resource editor. The button resource must have the BS_OWNERDRAW style in its Properties dialog.
3. Instantiate an object from the SECOwnerDrawButton-derived class in your dialog. This object must be in scope when the dialog appears.
4. Attach the SECOwnerDrawButton-derived class to the dialog resource using the AttachButton() method.
38 4.5.2.2 To create SECOwnerDrawButtons without using a button dialog resource
1. Create a class derived from SECOwnerDrawButton. You must provide an implementation for the pure virtual methods DrawFocus() and DrawSpecific().
2. Create a unique control ID for the button. In Visual Studio, you can create a control ID in the Resource Includes dialog.
3. Instantiate an object of the SECOwnerDrawButton-derived class for each button you want to create.
4. Create the button using your SECOwnerDrawButton-derived by calling the Create() method.
4.5.3 Customizing SECOwnerDrawButton
The SECOwnerDrawButton class has overridable methods that allow you to customize the draw- ing of the button. Note that the DrawFocus() and DrawSpecific() are pure virtual methods that must be implemented before any derived class can be instantiated.
4.5.3.1 To extend the SECOwnerDrawButton class
DrawFocus(). Must be overridden to draw a focus rectangle on the face of the button.
DrawSpecific(). Must be overridden to draw the face of the button.
PreDrawButton(). Override this method to perform any initialization of the device context required before any drawing of the button is performed.
PostDrawButton(). Override this method to undo any initialization of the device context performed in PreDrawButton().
4.5.4 SECBitmapButton
The SECBitmapButton class encapsulates the behavior of a bitmap button, displaying a bitmap and an optional text caption on the face of the button.
4.5.5 Using SECBitmapButton
You can attach objects instantiated from the SECBitmapButton to dialog resources or create them dynamically.
4.5.5.1 To attach an SECBitmap Button to a dialog resource
1. Create a button resource in the resource editor. The button resource must have the BS_OWNERDRAW style set in its Properties dialog.
Chapter 4 Simple Controls 39 2. Instantiate an SECBitmapButton object in your dialog class. This object must be in scope when the dialog is displayed.
3. Attach the SECBitmapButton class to the dialog resource using the AttachButton() method.
4.5.5.2 To create SECBitmapButtons without using a button dialog resource
1. Create a unique control ID for each button you want. In Visual Studio, you can create a con- trol ID with the Resource Includes dialog in Visual Studio.
2. For each button you want to create, instantiate an SECBitmapButton object.
3. Create the button by calling the Create() method.
4.5.6 SECBitmapButton alignment
The placement of the bitmap and a caption (if present) is specified during initialization of the SECBitmapButton using either the AttachButton() or Create() method. There are five align- ment modes for the placement of the bitmap and the placement of the caption.
Table 4 – Alignment Mode Flags
Alignment mode flag Alignment of bitmap and caption
SECBitmapButton::Al_Left Bitmap on left, caption on right
SECBitmapButton::Al_Right Bitmap on right, caption on left
SECBitmapButton::Al_Top Bitmap on top, caption underneath
SECBitmapButton::Al_Bottom Bitmap underneath, caption on top
SECBitmapButton::Al_Center Bitmap in center of button, no caption.
4.5.7 SECMenuButton
The SECMenuButton class provides a simple button that displays a pop-up menu when you click it. The application can display this pop-up menu either to the right or below the button.
4.5.8 Using SECMenuButton
You can attach objects instantiated from the SECMenuButton class to dialog resources or create them dynamically.
40 4.5.8.1 To attach an SECMenuButton to a dialog resource
1. Create a button resource in the resource editor. The button resource must have the BS_OWNERDRAW style set in the button resource Properties.
2. Instantiate an SECMenuButton object in your dialog class. This object must be in scope when the dialog is displayed.
3. Attach the SECMenuButton class to the dialog resource using the AttachButton() method. Specify a menu handle and the placement of the menu through parameters, or call the SetMenu() and SetDirection() methods for altering the menu and its placement dynamically.
4.5.8.2 To create SECMenuButtons without using a button dialog resource
1. Create an unique control ID for each button you want. In Visual Studio, you can create a control ID in the Resource Includes dialog.
2. For each button you want to create, instantiate an SECMenuButton object.
3. Create the button by calling the Create() method. Specify a menu handle and the place- ment of the menu through parameters, or call the SetMenu() and SetDirection() methods for altering the menu and its placement dynamically.
4.5.9 SECMenuButton Menu Placement
You can specify the placement of the menu with respect to the button using direction flags, which are parameters to the AttachButton(), Create(), or SetDirection() methods. These flags are as follows.
Table 5 – Direction Flags
Direction flag Placement of menu
SECMenuButton::DT_Down Menu drops down from the button
SECMenuButton::DT_Right Menu appears to the right of the button
4.5.10 SECWellButton
The SECWellButton class includes a Color Selection button. The face of the button displays the currently selected color. When the user clicks the button, a color palette (or color well) appears below the button. The user can select a color by clicking it.
The SECWellButton class sends a CWN_COLOR_CHANGE message to its parent window when you select a new color.
If you are using AttachButton(), ensure that the original BS_OWNERDRAW button style is defined.
Chapter 4 Simple Controls 41 4.5.11 Using SECWellButton
You can attach objects instantiated from the SECWellButton class to dialog resources, or create them dynamically.
4.5.11.1To attach an SECWellButton to a dialog resource
1. Create a button resource in the resource editor. The button resource must have the BS_OWNERDRAW style set in the button resource Properties.
2. Instantiate an SECWellButton object in your dialog class. This object must be in scope when the dialog is displayed.
3. Attach the SECWellButton class to the button resource using the AttachButton() method.
4. Use the SetColor() and GetColor() methods to set and obtain the currently selected color in the control. You can also use the DDX_Color() function as part of a DoDataExchange() method.
4.5.11.2To create SECWellButtons without using a button dialog resource
1. Create a unique control ID for each button you need. In Visual Studio, you can create a con- trol ID in the Resource Includes dialog.
2. For each button you want to create, instantiate an SECWellButton object.
3. Create the button by calling the Create() method.
4. Use the SetColor() and GetColor() methods to set and obtain the currently selected color in the control. You can also use the DDX_Color() function as part of a DoDataExchange() method.
4.5.12 Customizing SECWellButton
The SECWellButton provides the following virtual methods so you can customize its behavior:
SetOtherButton(). Enable or disable the button that enables a user to select from more than the twenty system colors. When this button is clicked, a common Color Selection dialog is displayed.
SetPaletteRealization(). Enable or disable palette realization of the currently selected color before drawing.
SetPopup(). Enable a non-standard pop-up color palette (SECPopupColorWell).
GetColorDialogFlags(). Override to return the flags for displaying the common color selection dialog when the Other button is clicked. Refer to the Objective Toolkit Class Reference for more information on the SECWellButton::SetOtherButton() method.
42 4.6 Calculator Control
Objective Toolkit provides a calculator control that the user can use to perform basic arithmetic. You can use the calculator control independently or in association with a drop edit control. Figure 14 – Objective Toolkit Calculator Class Hierarchy
CWnd
SECCalculator
SECPopupCalculator
4.6.1 SECCalculator
The SECCalculator class implements a calculator edit control capable of decimal arithmetic and other standard operations. The calculator queries the current locale information for formatting the numerical output and determines the decimal character to display on the decimal button. Figure 15 – Example of SECCalculator
Chapter 4 Simple Controls 43 4.6.2 SECPopupCalculator
The SECPopupCalculator class creates a pop-up window for the calculator that is destroyed when- ever the < = > key is pressed. Figure 16 – Example using SECPopupCalculator with SECDropEdit
4.6.3 Using SECCalculator
After instantiating an SECCalculator object, the application can create the control dynamically by calling the Create() method. For example:
m_calc.Create(WS_CHILD|WS_VISIBLE|WS_BORDER| WS_TABSTOP, sz.cx, sz.cy, this, 200);
It is important that the SECCalculator object have sufficient scope so that it exists as long as the control exists.
To set and query the value currently displayed by the calculator, use the SetValue() and GetValue() methods.
You can control and query the number of decimal places displayed with the SetDecimalPlaces() and GetDecimalPlaces() methods.
You can reset the calculator control with the Reset() method.
4.6.4 Customizing SECCalculator
You can customize the behavior of the SECCalculator class with the following virtual methods:
CreateBtns(). Creates the calculator’s buttons.
CreatePanel(). Creates the calculator’s LCD panel.
HandleEvent(). Handles events related to the calculator’s operations (add, subtract, etc.).
LoadDecSeparator(). Override to change the decimal separator displayed.
44 4.6.5 Calculator Sample
The calc sample project (in Samples\Toolkit\MFC\Controls\calc) demonstrates the use of an SECCalculator control in a dialog. It demonstrates how to use a class derived from SECDropEdit that creates an SECPopupCalculator. This sample is not shipped with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 4 Simple Controls 45 4.7 Calendar Control
SECCalendar implements a standard calendar control for date entry and date representation. You can invoke methods to highlight and select days on the calendar. You can embed an SECCalendar instance into a dialog or implement it as a pop-up control through the derived class SECPopupCalendar. SECPopupCalendar allows the user to view the calendar control as a drop- down window, which saves screen space.
The calendar class hierarchy is as follows: Figure 17 – Objective Toolkit Calendar Class Hierarchy
CWnd
SECCalendar
SECPopupCalendar
Figure 18 – SECCalendar Display
4.7.1 To incorporate the SECCalendar class into your code
1. Create an instance of SECCalendar or SECPopupCalendar.
2. Call the SetPage() method to display the appropriate month for a given date. For 32-bit versions of Objective Toolkit, pass in either a COleDateTime reference or a CTime reference. For example:
46 COleDateTime date = COleDateTime::GetCurrentTime();
// bRedraw MUST be FALSE when presetting a page. m_theCalendar.SetPage(date, FALSE);
The CTime class encapsulates the run-time time_t data type. it represents absolute time val- ues only in the range January 1, 1970 to January 18, 2038, inclusive.
3. Call the SetBehaviorMode() and SetDrawMode() methods. For example:
long lBehaMode = SECBM_DEFAULT_DIALOG_BEHAVIOR; long lDrawMode = SECDM_DEFAULT_DIALOG_DRAW;
m_theCalendar.SetBehaviorMode(lBehaMode); m_theCalendar.SetDrawMode(lDrawMode);
You can override these methods to customize the behavior mode and drawing mode.
4. Call the Create() method. For example:
m_theCalendar.Create( WS_VISIBLE|WS_BORDER, rect, this, IDC_CALENDAR_FRAME );
If you are using SECPopupCalendar, WS_POPUP is a valid window style.
4.7.2 SECCalendar Key Methods
SetDrawMode(). Sets the drawing mode of the calendar with the flags specified in the following table.
Table 6 – Drawing Mode Flags for SECCalendar
Draw Flag Description
SECDM_FULL_MONTH_NAMES Uses full month names.
SECDM_FULL_DAY_NAMES Uses full day names.
SetBehaviorMode(). Sets the behavior mode of the calendar with the flags specified in the following table:
Table 7 – Behavior Mode Flags for SECCalendar
Behavior Flag Description
SECBM_AUTOSIZE_FONT Automatically scales the font to fit the current size of the control.
SECBM_AUTOSIZE_RECT Automatically scales the calendar’s bounding rectangle to fit the parent window.
SECBM_SINGLE_DATE Allows the user to select a single date.
SECBM_MONTH_BUTTONS Displays the buttons to scroll months.
Chapter 4 Simple Controls 47 Table 7 – Behavior Mode Flags for SECCalendar (Continued)
Behavior Flag Description
SECBM_YEAR_BUTTONS Displays the buttons to scroll years.
SECBM_AUTO_HIDE Hides the calendar automatically when the user is done.
SECBM_KEYBOARD_CONTROL Allows navigation of the calendar with the keyboard.
SECBM_MONTH_FROZEN Freezes the currently displayed month.
SetPage(). Sets the displayed calendar page based on the CTime or COleDateTime parameter passed in.
HighlightDate(). Sets the highlighted mode of the specified date. Multiple dates can be highlighted at one time.
SelectDate(). Selects the date based on the CTime or COleDateTime parameter passed in. The user can only select one date at any given time.
ToggleSelectDate(). Toggles the selected mode of the specified date.
ToggleHighlightDate(). Toggles the highlighted mode of the specified date. Multiple dates can be highlighted at one time.
AdvanceDay(), AdvanceWeek(), AdvanceMonth(), AdvanceYear(). Advances the calendar by the given amount.
RetreatDay(), RetreatWeek(), RetreatMonth(), RetreatYear(). Retreats the calendar by the given amount.
4.7.3 Customizing SECCalendar
Most of the SECCalendar operation methods (AdvanceDay(), AdvanceWeek(), AdvanceMonth(), and more) are virtual functions that you can override to add custom behavior to a derived class. In addition, you can override the InitColors() method to specify colors for the various parts of the calendar. The default implementation initializes the colors based on the current system colors.
4.7.4 SECCalendar Sample
The use of SECCalendar and SECPopupCalendar is demonstrated in the caltest sample in the Samples\Toolkit\MFC\Controls\calendar directory. This sample is not shipped with the prod- uct. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
48 4.8 Color Well Control
The Objective Toolkit Color Well classes provide a sophisticated Color Selection control. This con- trol displays the 20-system colors in a five by four grid. Figure 19 – Color Well Control
Figure 20 – Color Well Control with Other Button
The user can select a color by clicking a cell in the grid. The user can select from a wider range of colors by clicking the Other button. Figure 21 – Common Color Selection Dialog
The hierarchy diagram for the Objective Toolkit color well classes is as follows:
Chapter 4 Simple Controls 49 Figure 22 – Objective Toolkit Color Well Class Hierarchy
CWnd
SECColorWell
SECPopupColorWell
4.8.1 SECColorWell
The SECColorWell class is a CWnd derivative designed for embedding in a dialog window or a CFormView. The color well automatically sizes to fit its content, and it can have a 3D-raised border. SECColorWell also supports palette realization of the selected color. In other words, it maps entries from the current logical palette to the system palette.
The SECColorWell sends a CWN_COLOR_CHANGE message to its parent window when a new color is selected.
4.8.1.1 Using SECColorWell
To incorporate SECColorWell into your code:
1. Create the SECColorWell window using the Create() method. Remember to specify whether the control should have an Other button. If you want to embed the color well in a dialog, specify the initial x and y coordinates in dialog base units.
2. Set the initially selected color with the SetColor() method.
3. Enable or disable palette realization of the colors before drawing with the SetPaletteRealization() method.
4. Enable or disable the ability to select a color by passing the mouse over a cell with the SetMouseTracking() method.
5. Call GetColor() to obtain the currently selected color.
6. After you create the SECColorWell window, you can use the DDX_Color() function as part of a DoDataExchange() method.
50 4.8.1.2 Customizing SECColorWell
You can customize the SECColorWell class with the following virtual methods:
Table 8 – Virtual Methods for SECColorWell
Method Description
DrawCell() Override to customize the drawing of an unse- lected cell.
DrawSelectedCell() Override to customize the drawing of a selected cell.
SetGridSize() Override to change the size of the grid. Set the m_nCols and m_nRows member variables.
InitAdditionalColors() Override in conjunction with SetGridSize() to initialize any extra color cells defined in the grid.
HasFocusRectangle() Override to define whether the color well has a focus rectangle, an extra 1-pixel-wide border drawn around the edge of the window, when it has focus.
GetColorDialogFlags() Override to specify the flags with which the com- mon color selection dialog is opened when the Other button is clicked.
4.8.2 SECPopupColorWell
The SECPopupColorWell class works with the SECWellButton class. It provides a pop-up color selection window. After the application creates the window, it self-destructs when it loses focus or a color is selected.
When the user selects a new color or clicks the Other button, the SECWellButton sends CWN_COLOR_CHANGE and CWN_CUSTOM_COLOR messages to a specified window.
4.8.2.1 To incorporate SECPopupColorWell into your code
1. Create the pop-up color well using the Create() method.
2. Set the window to receive color change notifications using the SetNotifyWindow() method.
3. Set any other required options as you would for an SECColorWell window.
Chapter 4 Simple Controls 51 4.8.3 ColorWell Sample
The use of SECColorWell and SECPopupColorWell is demonstrated in the Objective Toolkit COLOR sample, located at Samples\Toolkit\MFC\Controls\colrwell. This sample is not shipped with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
52 4.9 Currency Edit Control
The Objective Toolkit currency edit control classes provide a specialized edit control for the display and entry of currency data. The control includes a bitmap button for dropping down a calculator. Figure 23 – Objective Toolkit’s Currency Edit Class Hierarchy CWnd
SECDropEdit
SECCurrencyEdit
4.9.1 SECDropEdit
The SECDropEdit class adds a combo-like drop-down button to an edit control.
SECCurrencyEdit uses the special SECDropEdit capabilities to display a bitmap button that acti- vates a calculator to help in the data entry.
4.9.2 SECCurrencyEdit
SECCurrencyEdit provides an extensible class for entering and displaying custom-formatted cur- rency data. In addition, it includes a context menu and an optional bitmap button.
The methods of the Format class, a helper class, provide a comprehensive set of custom formatting options. If you need implement behavior that is not addressed by Format’s methods, you can cus- tomize the input data parsing and output display formatting by descending new classes from SECCurrencyEdit::Format and SECCurrencyEdit.
4.9.3 Using SECCurrencyEdit
To attach an SECBitmap Button to a dialog resource:
1. Add an edit control to your dialog using the resource editor.
2. Instantiate an SECCurrencyEdit object in your dialog class. This object must be in scope when the dialog is displayed.
3. In OnInitDialog(), replace the edit control with your SECCurrencyEdit object by calling the Initialize() method.
4. Create and configure an SECCurrencyEdit::Format object to specify formatting options. Call SetFormat() to start using the new formatting information.
Use GetValue() and SetValue() to obtain and recover the current value in the control. You can also use the DDX_Currency() method in your DoDataExchange() function.
Call SetBitmap(IDB_CALC) to display the calculator drop-down button.
Chapter 4 Simple Controls 53 4.9.4 SECCurrencyEdit::Format
Format is a nested helper class that provides the core currency formatting and parsing methods used by an SECCurrencyEdit control. As the following list of methods suggests, the Format class provides extensive control over the appearance of the currency data.
void EnableLeadingZero(BOOL b);
void EnableDecimalSeparatorLine(BOOL b);
void SetMonetarySymbol(LPCTSTR p);
void SetThousandSeparator(TCHAR c);
void EnableLeadingThousSeparator (BOOL b);
void SetDecimalSeparator(TCHAR c);
BOOL SetGrouping(LPCTSTR x);
BOOL SetPaddingCharacter(TCHAR c);
void SetPositiveFormat(int i);
void SetNegativeFormat(int i);
void SetDecimalDigits(int i);
void SetFractionalDigits(int i);
void SetBackgroundColor(COLORREF cr);
void SetNegativeColor(COLORREF cr);
void SetPositiveColor(COLORREF cr);
void SetDecimalSeparatorLineColor(COLORREF cr);
Consider the following facts before you use the currency display options:
Setting the thousands separator to the null character (‘\0’) prevents its use.
With EnableLeadingThousSeparator, the thousands separator will present ‘5555555’ as ‘$ , 5,555,555.00’ as opposed to ‘$ 5,555,555.00’.
When you set decimal digits to negative one (-1) the application uses every digit that is necessary to display the number. If the number of decimal digits is greater than is required, the output is padded with the padding character.
You can use the values in the table below with the SetNegativeFormat() and SetPositiveFormat() methods. These values are taken directly from Microsoft’s documentation regarding the international section of WIN.INI.
Negative Format Positive Format
0 ($1) 0 $1
1-$111$
2$-12$ 1
54 Negative Format Positive Format
3 $1- 3 1 $
4 (1$)
5-1$
61-$
71$-
8 -1 $
9-$ 1
10 $ 1-
The ParseValue() and FormatValue() methods convert between a numeric and a string represen- tation. If you need to use a format that is not supported by the basic Format class, derive your own Format class and override those methods. Then, derive your own version of SECCurrencyEdit and override its CreateFormatObject() method to provide an object of your descendant class.
For example, the following code:
SECCurrencyEdit m_Edit; // fmt(TRUE) will load the default system settings. SECCurrencyEdit::Format fmt(FALSE); fmt.EnableLeadingZero(TRUE); fmt.EnableDecimalSeparatorLine(FALSE); fmt.SetMonetarySymbol(_T("$")); fmt.SetThousandSeparator(_T(',')); fmt.SetDecimalSeparator(_T('.')); fmt.SetGrouping(_T("3;0")); // 3 digits per group repeated. fmt.SetPaddingCharacter(_T(' ')); fmt.SetPositiveFormat(0); fmt.SetNegativeFormat(0); fmt.SetDecimalDigits(10); fmt.SetFractionalDigits(2); fmt.SetNegativeColor(RGB(255,0,0)); fmt.SetPositiveColor(RGB(0,0,255)); m_Edit.SetFormat(fmt); will present "5555555" as "$ , 5,555,555.00" in blue color; and "-5555555" as "($ , 5,555,555.00)" in red color.
4.9.5 SECCurrencyEdit Messages
The SECCurrencyEdit class supports some of the WM_* windows messages and EM_* edit control messages.
Chapter 4 Simple Controls 55 The supported messages are as follows:
Table 9 – Windows Messages Supported by SECCurrencyEdit
Windows Message Description
WM_COPY Copies the current selection to the clipboard.
WM_CUT Deletes or cuts the current selection, if any, in the con- trol and then copies the deleted text to the clipboard.
WM_GETFONT Retrieves the font with which the control is currently drawing its text.
WM_PASTE Copies the current content on the clipboard to the control.
WM_SETFONT Specifies the font that the control uses when drawing text.
WM_SETREDRAW Allows changes in the control to be redrawn or prevents changes in the control from being redrawn.
WM_SETTEXT Sets the text of the control.
WM_UNDO Undoes the last operation.
Table 10 – Edit Control Messages Supported by SECCurrencyEdit
Edit Control Message Description
EM_CANUNDO Determines whether the user can undo an operation.
EM_EMPTYUNDOBUFFER Resets the undo flag of the control.
EM_GETSEL Gets the starting and ending character positions of the current selection in the control.
EM_SETREADONLY Sets or removes the read-only style (ES_READONLY) of the control.
EM_SETSEL Selects a range of characters in the control.
EM_UNDO Undoes the last edit control operation.
4.9.6 SECCurrencyEdit Sample
The use of SECCurrencyEdit and its supporting classes is demonstrated in the Objective Tool- kitcurrency sample in the Samples\Toolkit\MFC\Controls\currency directory. This sample is not shipped with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
56 4.10 Date/Time Edit Control
The date/time edit control implements an edit field that allows users to edit date information in various display formats using either keyboard or mouse with optional spin buttons. The date is internally represented with a COleDateTime object, limiting it to 32-bit environments.
Some features of the date time control include:
Default and customizable display formats
Null date entry mode
Fast entry mode (automatic cursor advancement as data is entered)
Minimum/maximum range restriction
Spinner buttons
Popup calendar
Y2K compliance Figure 24 – Example Date Time Control with Default Display Formats
Figure 25 – Example Date Time Control with a Custom Display Format
The SECDateTimeCtrl class implements the date/time control. The entry field is divided into a number of subfields, depending on the specified format. Each subfield or component is controlled by a gadget class specialized for the input and display of that particular subfield. Each gadget class is based on SECDTGadget. Figure 26 – The Date/time Control Class Hierarchy
CWnd CObject
SECDateTimeCtrl SECDTGadget
Chapter 4 Simple Controls 57 4.10.1 SECDateTimeCtrl
SECDateTimeCtrl is a date/time editing control class. SECDateTimeCtrl manages several gadget objects to display the data in a specified format.
4.10.1.1SECDateTimeCtrl styles
You can set the following extended styles when the control is:
Created.
Attached to an edit control in a dialog resource using AttachDateTimeCtrl().
You can set the styles with the Create() or CreateEx() methods. The Y2K styles determine which century is added to a two-digit year.
Table 11 – Extended Styles for SECDateTimeCtrl
SEC_DTS_CALENDAR Adds calendar drop-down button.
SEC_DTS_UPDOWN Adds spinner control.
SEC_DTS_Y2K_NOFIX Ignores Y2K fix (for backward compatibility). The current century is used to expand two-digit years.If not defined, the century is chosen so that the resulting date is within 50 years of either the current date or the date previously stored in the control, depending on SEC_DTS_Y2K_CONTEXT.
SEC_DTS_Y2K_CONTEXT If SEC_DTS_Y2K_NOFIX is not defined, the cen- tury is based on the date previously stored in the control.
4.10.1.2SECDateTimeCtrl messages
SECDateTimeCtrl only supports the following edit control messages.
SECDTN_CHANGED or EN_CHANGE
SECDTN_KILLFOCUS or EN_KILLFOCUS
SECDTN_SETFOCUS or EN_SETFOCUS
4.10.2 SECDTGadget
SECDTGadget is an abstract base class that handles the input and display of data in the subfields of a date/time control. SECDateTimeCtrl uses several subclasses of SECDTGadget including:
SECDTStaticGadget. Implements a non-editable text gadget.
SECDTNumericGadget. Implements an editable numeric gadget.
58 SECDTListGadget. Implements a text gadget with a defined list of possible strings.
SECDTButtonGadget. Implements a simple push button gadget.
SECDTSpinGadget. Implements a spin button gadget.
4.10.3 Date Formats
SECDataTimeCtrl’s SetFormat() method specifies how the date or time data is displayed. The for- mat determines which subfields or gadgets are shown. Several predefined format types are available. In addition, you can specify custom formats using codes in a user-defined string.
4.10.3.1Predefined Format Types
The table below lists the format types that the application can pass as a parameter to SetFormat(). To specify a custom format, the user-defined string is passed to SetFormat(); don’t pass SECDateTimeCtrl::Custom.
Table 12 – Supported Format Types for SetFormat()
Format type Description Example
SECDateTimeCtrl::Time Locale time format 11:54
SECDateTimeCtrl::ShortDate Locale short date format 7/21/98
SECDateTimeCtrl::LongDate Locale long date format Tuesday July 21, 1998
SECDateTimeCtrl::Custom A user supplied date/time July 21, 1998 format string (Tuesday)
4.10.3.2Format Strings
You can use the codes in the following table to build a custom format string.
Table 13 – Format Strings Supported by SECDateTimeCtrl
Format string Description
h Hours, 12 hour format, no leading zero
hh Hours, 12-hour format with leading zero
H Hours, 24-hour format, no leading zero
HH Hours, 24-hour format with leading zero
m Minutes, no leading zero
mm Minutes with leading zero
s Seconds, no leading zero
Chapter 4 Simple Controls 59 Table 13 – Format Strings Supported by SECDateTimeCtrl (Continued)
Format string Description
ss Seconds with leading zero
t Abbreviated AM/PM designator
tt Full AM/PM designator
d Numeric day
dd Numeric day with leading zero
ddd Abbreviated day name
dddd Full day name
MMonth
MM Month with leading zero
MMM Abbreviated month
MMMM Full month name
y Year without century
yy Year with leading zero, without century
yyyy Year including century
gg Era (ignored)
‘text' Quoted text passed straight through
4.10.4 Null Data Entry Mode
SECDateTimeCtrl supports a null date entry mode. This mode allows you to enter date time infor- mation in an empty control. You can specify a character to fill the fields of the control so that the user can see them. The following figure is an example date time control that has been put into null date entry mode. Figure 27 – Example Date Time Controls in Null Data Entry Mode
The user can now begin entering data. The control remains in null entry mode until all of the required fields are completed.
60 Figure 28 – Using Date Time Controls in Null Data Entry Mode
When not in null date entry mode, GetDateTime() always returns a COleDateTime object contain- ing the currently displayed date/time. When the application is in null date entry mode, GetDateTime() returns one of the following:
A COleDateTime object with a status of COleDateTime::null if the date is incomplete.
A COleDateTime object with a status of COleDateTime::invalid if the date is complete, but invalid (out of range).
A COleDateTime object containing the entered date/time.
4.10.5 Using SECDateTimeCtrl
The following sections give tips on using the SECDateTimeCtrl class.
To use the date/time control in a dialog:
1. Create an edit control on a dialog resource in the resource editor.
2. Add a data member to the dialog class for the date time control. For example:
SECDateTimeCtrl m_dateCtrl;
3. In the OnInitDialog() method of the dialog, set the display format for the date time object with the SetFormat() method. For example:
m_dateCtrl.SetFormat(SECDateTimeCtrl::Time);
4. After setting the display format, attach the resource edit control to the date time object with the AttachDateTimeCtrl() method. For example:
VERIFY(m_dateCtrl.AttachDateTimeCtrl(IDC_TIME, this, SEC_DTS_UPDOWN));
To set the date or time for the control:
Call the SetDateTime(), SetDate(), or SetTime() methods. For example: m_dateCtrl.SetDateTime(minDate);
To change a date/time control to the null date entry mode:
Call the SetNull() method. This method accepts a character that is used to blank out the control. For example:
m_dateCtrl.SetNull('_');
Chapter 4 Simple Controls 61 To make the control always remain in the null date entry mode:
m_dateCtrl.SetNull('_', TRUE);
To clear the control using the delete key:
1. Derive a class from SECDateTimeCtrl.
2. Override the OnKeyDown() method. In this override, test for the VK_DELETE key, and if detected, call the SetNull() method. For example:
void CMyDateTimeCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: Add your message handler code here and/or call default SECDateTimeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
if (VK_DELETE == nChar) { SetNull('_'); } }
To set focus back to the first gadget of the control:
1. Derive a class from SECDateTimeCtrl.
2. Create a method, or in a method override, use the following code to locate the first gadget index:
// Find first gadget int nGadget; for(nGadget = m_nFixed; nGadget < m_gadgets.GetSize() && !(m_gadgets[nGadget]->GetStyle() & SECDTGadget::WantFocus); nGadget++);
3. When you locate the first gadget index, call the Enable() method on the gadget, and then call the BringIntoView() method. For example:
if(nGadget >= m_nFixed && nGadget < m_gadgets.GetSize()) { m_gadgets[m_nCurGadget = nGadget]->Enable(TRUE); BringIntoView(m_nCurGadget); }
To change the color of the text in the control:
1. In the parent window, override OnCtlColor() and set the text and background colors using the SetBkColor() and SetTextColor() methods. For example:
HBRUSH CDatetimeDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CPropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
if (pWnd-> IsKindOf(RUNTIME_CLASS(SECDateTimeCtrl)) && nCtlColor == CTLCOLOR_EDIT)
62 { //pDC->SetBkMode(OPAQUE); pDC->SetBkColor(RGB(75,75,255)); pDC->SetTextColor(RGB(255,255,0)); } // for all other windows, use the default brush from the // base class else hbr = CPropertyPage::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr; }
4.10.6 Date/Time Edit Control Sample
See the datetime sample in the Samples\Toolkit\MFC\Controls\datetime directory for a demonstration of how to use the SECDateTimeCtrl classes. This sample is not shipped with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 4 Simple Controls 63 4.11 List Box Edit Control
An editable list box is a Windows list box that contains items that the user can modify. For example, the user can modify the order of the list box items, create and delete items, and edit the content of individual items. The editable list box is similar to Visual Studio’s Include and Library path editors, which is accessible by selecting Options from the Tools menu. Figure 29 – Objective Toolkit Editable Listbox Class Hierarchy
CWnd
SECListBoxEditor
SECListBoxFileEditor
SECListBoxDirEditor
There are two ways to edit a list box item. You can either edit in-place by selecting the text of the item and typing or, if the class supports browsing, you can browse for a value by pressing the browse button to the right of the item. A browse button is a push button labeled with ellipses (...), which is only visible after the user double-clicks an item. When the browse button is pressed, a dia- log appears to allow the user to choose from a list or tree of possible values. After the user selects a new value and closes the dialog, the selected item is automatically replaced.
To support the creation, deletion, and reordering of list box items, SECListBoxEditor adds several child controls, known as command buttons, above the list box. Figure 30 – Editable List Box Command Buttons
The command buttons and their actions are as follows:
Table 14 – Command Buttons for SECListBoxEditor
Click the: To:
New Button Create a new list box item at the end of the list.
Delete Button Remove the selected list box item.
Move-Up Button Move up selected list box item one place.
Move-Down Button Move down selected list box item one place.
64 4.11.1 SECListBoxEditor
The SECListBoxEditor class implements an editable list box that supports item creation, deletion, reordering, and in-place text editing. Figure 31 – Example SECListBoxEditor
The SECListBoxEditor does not support browsing. If you need to support browsing, derive a class from SECListBoxEditor and override its OnBrowse() method. See Section 4.11.6 later in this chap- ter for more information.
4.11.2 SECListBoxFileEditor
The SECListBoxFileEditor class is an editable list box that is specialized for entering a list of filenames.
An SECListBoxFileEditor object allows users to enter a filename by typing it or by selecting it from a file selection dialog. SECListBoxFileEditor inherits most of its functionality from SECListBoxEditor. In fact, its only method is an override of OnBrowse(), which launches a file selection dialog when the user presses a browse button.
4.11.3 SECListBoxDirEditor
The SECListBoxDirEditor class is an editable list box that is specialized for entering a list of directories. Figure 32 – Example SECListBoxDirEditor
Chapter 4 Simple Controls 65 An SECListBoxDirEditor object allows you to enter a directory name by typing it or by selecting it from a directory selection dialog. SECListBoxDirEditor inherits most of its functionality from SECListBoxEditor. In fact, its only method is an override of OnBrowse(), which launches a direc- tory selection dialog when a browse button is pressed.
4.11.4 Using the List Box Edit Classes
The SECListBoxEditor-based classes are intended to replace existing list box controls in a parent window. Typically, the parent window is a dialog box, but the parent can be any CWnd with a list box control as a child. The steps for creating a list box edit control are the same whether you are using SECListBoxEditor, SECListBoxFileEditor, or SECListBoxDirEditor.
To incorporate an editable list box into a dialog window:
1. Use the resource editor to create a dialog template. Drop a list box control on the dialog.
2. Create a new dialog class and attach it to the dialog template created in the last step.
3. Add a member variable of type SECListBoxEditor to the class created in the last step.
4. Override the OnInitDialog() member of the dialog you created earlier. In your override, call SECListBoxEditor::Initialize() and pass the window ID of the list box control you want to convert to an editable list box. For example:
BOOL MyDialogBox::OnInitDialog() { CDialog::OnInitDialog();
m_LBEditor.Initialize(this, IDC_LIST); m_LBEditor.SetWindowText("My Editable List Box:"); .. }
After the control is initialized, use the GetListBoxPtr() method to obtain a pointer to the CListBox-based helper object for manipulating and querying the list box control.
To incorporate an editable list box into an arbitrary CWnd:
1. Construct a CListBox object and then create the control in the parent window with the Create() method, assigning it a unique control ID.
2. After the list box control is created, construct an SECListBoxEditor object and call the Initialize() method, using the control ID you just created.
It is important that both the CListBox and SECListBoxEditor objects have sufficient scope to exist while the control lives in the parent window.
4.11.5 Customizing the List Box Edit Classes
The command buttons are optional. A style flag passed into the initialization of the editable list box controls their creation. These style flags allow you to select editing features for the list box.
66 The style flags and their definitions are as follows.
Table 15 – Style Flags for the List Box Edit Classes
Style Flag Definition
LBE_BROWSE Editable list box has a browse button for each item.
LBE_AUTOEDIT Alphanumeric key starts in-place edit of selected item.
LBE_BUTTONS Enable the command buttons. The presence of the individual buttons is determined by the next four styles.
LBE_NEWBUTTON Displays new pushbutton.
LBE_DELBUTTON Display delete pushbutton.
LBE_UPBUTTON Display up pushbutton.
LBE_DOWNBUTTON Display Down pushbutton.
LBE_TOOLTIPS Supply tool tips for the command buttons.
LBE_SHORTCUTS Allow keyboard shortcuts for New, Delete, Move, etc.
LBE_DRAGNDROP Allow items to be drag-and-drop to and from the list.
LBE_NOTRAILBLANK Does not add the trailing blank item.
LBE_DEFAULT Combination of all of the preceding style flags.
Use these style flags with the SECListBoxEditor::Initialize() method by passing a style flag to its third parameter. Note that the styles for displaying the individual command buttons (LBE_NEWBUTTON, etc.) must be combined with LBE_BUTTONS.
4.11.6 Extending the Editable List Box Classes
The SECListBoxEditor and SECListBoxEditor-derived classes have a number of virtual methods that you can override to modify the standard behaviors. Some of the virtual callbacks provided by these classes are as follows:
Table 16 – Virtual Callbacks for Edit List Box Classes
OnEditingJustStarted() Called when editing has started.
OnEditingStopped() Called when editing has stopped.
OnItemRenamed() Called after an item has been renamed.
OnItemAdded() Called after an item has been added.
Chapter 4 Simple Controls 67 Table 16 – Virtual Callbacks for Edit List Box Classes (Continued)
OnItemMoved() Called after an item has been moved.
OnItemDelete() Called before an item is deleted.
The SECListBoxEditor class implements an editable list box into which the user can enter arbitrary text. It does not support browsing. To support browsing, the control must understand the nature of the text contained in the list box. This is why the SECListBoxFileEditor and SECListBoxDirEditor classes exist. These classes inherit the functionality of an editable list box from SECListBoxEditor and add the ability to browse for a file or directory name. If you need to create an editable list box that supports browsing, derive a class from SECListBoxEditor and override its OnBrowse() method.
Typically, an overridden OnBrowse() method opens an application-specific modal dialog, accepts the user’s choice and writes the new value back to the selected list box item. Refer to the implemen- tations of OnBrowse() in SECListBoxDirEditor and SECListBoxFileEditor for examples of how to do this.
4.11.7 Editable List Box Sample
The Objective Toolkit LBEdit sample in the Samples\Toolkit\MFC\Controls\LBEdit directory shows how to use SECListBoxEditor and SECListBoxDirEditor in a dialog. This sample is not shipped with the product. For information on how to obtain this sample, see Section 3.6.1, “Loca- tion of Sample Code,” in the Stingray Studio Getting Started Guide.
68 4.12 Marquee Control
The SECMarquee implements a marquee control that scrolls text across its window. You can config- ure the fonts, colors, scrolling speed, and wrapping mode. In addition, you can easily change them at run time. Because it is CWnd-derived, you can embed SECMarquee in a view or dialog like any other control. Figure 33 – SECMarquee Window Embedded in an SECStatusBar
Figure 34 – Objective Toolkit Marquee Class Hierarchy
CStatic
SECMarquee
4.12.1 Using SECMarquee
You can use objects instantiated from SECMarquee anywhere a CStatic can be used. You can attach the object to an existing CStatic control via the AttachStatic() method or create it dynamically via the Create() method.
To attach an SECMarquee instance to an existing CStatic instance:
1. Call the AttachStatic() method with the control ID of the static control to attach the SECMarquee instance. For example:
m_wndMarquee.AttachStatic(IDC_MARQUEE_STATIC,this);
To create an SECMarquee instance dynamically:
1. Create a unique control ID for the control. In Visual Studio, you can create a control ID in the Resource Includes dialog.
2. Call the Create() method. For example:
Rect rect(0,0,100,50); // initial rectangle m_wndMarquee.Create(rect,this,strMarqueeText);
To start and stop the SECMarquee:
The Scroll() method controls the scrolling of the marquee.
Chapter 4 Simple Controls 69 4.12.2 Customizing SECMarquee
Table 17 lists the five methods that allow you to customize the text, the text font, scrolling speed, foreground/background colors, and wrapping mode at run time.
Table 17 – Customization Methods for SECMarquee
Method Description
SetScrollDelay() Sets scrolling delay.
SetTextWrap() Sets text wrapping mode.
SetColors() Sets foreground and background colors.
SetWindowText() Sets/resets marquee message text.
SetFont() Set the marquee font.
For more information about these methods, see the Objective Toolkit Class Reference.
To modify the SECMarquee behaviors:
Nearly all the public and protected methods of SECMarquee are virtual so you can override them. Some of the virtual callbacks provided by this class are as follows:
Table 18 – Virtual Callbacks for SECMarquee
Method Behavior
OnScrollStart() Called when a new message is about to start scrolling.
OnScrollComplete() Called when an existing message is about to finish.
OnInitMarquee() Called when the marquee is initializing.
OnScrollMarquee() Called when the marquee is scrolling one frame.
Some of the methods that you can override to alter the appearance of the SECMarquee class include:
Table 19 – Methods to alter the appearance of SECMarquee
Method Behavior
Draw3Dborder() Draws a 3D border around the marquee control.
DoPaint() Paints the marquee control.
70 4.12.3 Marquee Sample
The statbar sample in the Samples\Toolkit\MFC\UIExt\statbar directory demonstrates how to the use the marquee control in an SECStatusBar. This sample is not shipped with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 4 Simple Controls 71 4.13 Masked Edit Control
The masked edit control implements an edit field that filters characters as they are typed. One of the primary limitations of Dynamic Data Validation (DDV) is that the user must type all the data and dismiss the dialog before the errors in input are found. The masked edit control in Objective Toolkit provides a solution to this problem by giving the user immediate feedback if an invalid character is typed.
The class hierarchy is as follows: Figure 35 – Masked Edit Class Hierarchy
CWnd
CEdit
SECMaskEdit
4.13.1 SECMaskEdit
SECMaskEdit provides a subclassed CEdit that you can use to specify the format and restrictions for entered data. For example, if you wanted a user to enter a telephone number, you would set the mask to (###) ###-####. SECMaskEdit would restrict cursor movement and data input to the location of the pound signs (#). Figure 36 – Example SECMaskEdit Control
SECMaskEdit supports cut, copy, paste, and clear operations in addition to the insert mode, which the user can toggle on and off by pressing the VK_INSERT key.
4.13.2 Using SECMaskEdit
SECMaskEdit attaches to an existing CEdit control and lets you add formatted input capabilities to it.
To incorporate an SECMaskEdit object into your code:
Attach an SECMaskEdit object to an existing CEdit using the AttachEdit() method.
To set a mask that defines the format for the data the user enters:
Construct a string containing the special mask codes and pass it to the control with the SetMask() method. For more information, see Section 4.13.3.
72 To retrieve the data from the masked edit control:
Call GetData() to retrieve the data without the mask or GetRawData() to retrieve the entire con- tents of the SECMaskEdit.
To use DDX (dynamic data exchange) with an SECMaskEdit:
Use the DDX_Mask() function instead of DDX_Control() function in your dialog’s DoDataExchange() method.
4.13.3 Creating a Mask to Use with SECMaskEdit
Mask strings consist of mask characters and literals. Literals are characters that appear unchanged in the mask. Mask characters specify a spot in the mask that accepts certain characters. The valid mask characters are as follows:
Table 20 – Mask Characters for SECMaskEdit
Mask Character Input allowed for that field
# Numeric data (0-9)
A Alpha-numeric data (0-9 and a-Z)
& Any ASCII character
? Alphabetic data (a-Z)
U Accepts a-Z, forces to A-Z (uppercase)
L Accepts a-Z, forces to a-z (lowercase)
\ Escape character. Use this character if you want the application to interpret one of the preceding character literally (in other words, shown in the mask).
The ES_LOWERCASE and ES_UPPERCASE styles have precedence over the ‘U’ and ‘L’ masks.
Here are some of more popular masks:
Table 21 – Popular Masks for SECMaskEdit
Description Mask Example
Date ##/##/## 12/24/98
Time ##:## UU 12:35 AM
Soc. Sec. Number ###-##-#### 148-92-1532
Phone (###) ###-#### [####] (919) 933-0867 [7]
Zip code + 4 #####-#### 27858-1203
First Name ???????????????? Bartholomew
Chapter 4 Simple Controls 73 At run time, a prompt character replaces the mask characters. By default, the prompt character is a space. You can change the prompt character via the SetPromptChar() method, e.g., in the case that the space is used as a valid input character.
In this version of SECMaskEdit, validation is not performed on the various types of data. For example, 12/35/95 is invalid for a US date format, but would fit the requirements of the mask. It is the SECMaskEdit user’s task to detect that 12/35/95 is an invalid date in such a circumstance.
4.13.4 Mask Edit Sample
The Objective Toolkit masktest sample in the Samples\Toolkit\MFC\Controls\masktest direc- tory demonstrates the creation and capabilities of SECMaskEdit, including DDX (dynamic data exchange). This sample is not shipped with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
74 4.14 Extended Progress Control
Derived from MFC's CProgressCtrl, SECProgressCtrl offers several enhancements to the existing progress control, including
Smooth fill with percentages.
Multidirectional progressions (left to right, right to left, bottom to top, or top to bottom).
Fully configurable foreground and background coloring.
Custom status text with configurable fonts.
The progress control also offers powerful virtual hooks for you to provide your own customiza- tions easily.
In addition, SECProgressCtrl supports the automatic advancing of the progress status in response to timer events. Refer to StepOnTimer() in the Objective Toolkit Class Reference for more information. Figure 37 – Example Progress Control
The class hierarchy for the progress control is as follows: Figure 38 – Objective Toolkit SECProgressCtrl Class Hierarchy
CProgressCtrl
SECProgressCtrl
4.14.1 Using SECProgressCtrl
You can use objects instantiated from SECProgressCtrl anywhere you can use CProgressCtrl. You can attach an SECProgressCtrl object to an existing CProgressCtrl control via the AttachProgress() method or you can create the control dynamically via the Create() method.
To attach an SECProgressCtrl instance to an progress control resource:
Call the AttachProgress() method with the control ID of the progress control you want to attach.
m_wndProgress.AttachProgress(IDC_PROGRESS,this);
To create an SECProgressCtrl instance dynamically:
1. Create a unique control ID for the control. In Visual Studio, you can create a control ID in the Resource Includes dialog.
2. Call the Create() method.
CRect rect(0,0,100,50); // initial rectangle m_wndProgress.Create(WS_CHILD|WS_VISIBLE,rect, this,IDC_PROGRESS1);
Chapter 4 Simple Controls 75 4.14.2 Customizing SECProgressCtrl
You can use the following extended styles to customize the progress control.
Table 22 – Extended Styles for SECProgressCtrl
Extended style flag Description
SEC_EX_PROGRESS_VERT Bar progresses vertically
SEC_EX_PROGRESS_RIGHT_TO_LEFT If horizontal, bar progresses right to left
SEC_EX_PROGRESS_TOP_TO_BOTTOM If vertical, bar progresses top to bottom
SEC_EX_PROGRESS_SHOWPERCENT Show text percentages on bar
SEC_EX_PROGRESS_SHOWTEXT Show text on bar
SEC_EX_PROGRESS_TEXT_ALIGN_LEFT If text shown, align text left
SEC_EX_PROGRESS_TEXT_ALIGN_RIGHT If text shown, align text right
SEC_EX_PROGRESS_TEXT_ALIGN_CENTER If text shown, center the text
SEC_EX_PROGRESS_ COMMCTRL32 Has look and feel of CProgressCtrl
SEC_EX_PROGRESS_DEFAULTS SEC_EX_PROGRESS_SHOWPERCENT |SEC_EX_PROGRESS_TEXT_ALIGN _CENTER
You can specify these styles as parameters to the Create() and SetExStyle() methods. By default, the progress bar is horizontal and progresses left to right with centered percentages. You can use the preceding flags to modify the default behavior. In addition, the application can config- ure the font, foreground, and background color at run time.
4.14.3 Extending SECProgressCtrl
Almost every method in SECProgressCtrl is virtual so you can override them. Some of the virtual callbacks provided by this class include:
Table 23 – Virtual Callbacks in SECProgressCtrl
Method Description
OnDisplayStr() Override to alter a progress string before display.
OnPaintBarFill() Paint the filled portion of the progress bar.
OnPaintBarEmpty() Paint the empty portion of the progress bar.
OnPaintBarText() Paint the progress text, if any.
76 4.15 Enhanced ComboBox with AutoComplete
The SECComboBoxEx class extends MFC’s CComboBoxEx class by providing a type ahead or auto- complete feature. The Address combobox in MS Internet Explorer provides the same functionality. As the user types, the control searches through its list of entries for a match. If the control finds a match to the partial entry, it substitutes the text in the edit control with first matching entry and highlights the characters to the right the caret. Figure 39 – Example Enhanced Combobox Control
The autocomplete feature also skips ahead when the user types in an entry that includes a regularly repeating delimiter strings sequence, such as the “.” in an IP address or the slash character (/) in an URL.
When the user presses the delimiter key once, the entry appears as follows: Figure 40 – Example Entry with Repeating Delimiters
When the user presses the delimiter key twice, the entry appears as follows:
When the user presses the delimiter key three times, the entry appears as follows:
The user can always click the button to the right to drop down the list of items as well.
4.15.1 The Enhanced ComboBox Class
The SECComboBoxEx class inherits directly from CComboBoxEx. Figure 41 – Enhanced Combobox Class Hierarchy
CComboBoxEx
SECComboBoxEx
4.15.2 Using SECComboBoxEx
The following procedures describe how to use an enhanced combo box in your application.
To add SECComboBoxEx to a window:
Use the CComboBox::Create() method. For example:
Chapter 4 Simple Controls 77 m_combo.Create(WS_CHILD | WS_VISIBLE | CBS_DROPDOWN, CRect(10,10,350,100), this, ID_COMBOBOX);
To add string items to the combo box:
Use the CComboBox::InsertItem() method. For example:
COMBOBOXEXITEM comboItem; memset(&comboItem, 0, sizeof(comboItem));
comboItem.mask = CBEIF_TEXT; comboItem.iItem = 0; comboItem.pszText = _T("
m_combo.InsertItem(&comboItem);
where
To set the case sensitivity for the autocomplete feature:
Call the CComboBox::SetCaseSensitive() method.
m_combo.SetCaseSensitive(FALSE);
The preceding call ensures that the autocomplete feature does not consider the case of the charac- ters when it searches for a matching entry in the list.
To allow users to skip repeating delimiters:
Use the CComboBox::SetDelimiterKey() and SetDelimiterString() methods. For example, if the combobox contains long directory entries delimited by two backslashes, you can let the user skip the next delimiter by pressing the
m_combo.SetDelimiterKey(VK_TAB); m_combo.SetDelimiterString(_T("\\"));
78 Chapter 5 Look and Feel Styles
5.1 Overview
Objective Toolkit, along with the SFLEx libraries, provide developers with components that simu- late Visual Studio application styles or themes, such as APPSTYLE_OFFICE_*, where * denotes XP, BLUE, BLACK, SILVER, AQUA or 2003. Other application styles include APPSTYLE_WIN_2000, APPSTYLE_WIN_XP, APPSTYLE_VS_2005, APPSTYLE_VS_2008, and APPSTYLE_WIN_7.
You cannot dynamically switch between look-and-feel styles without some noticeable drawing side effects with tool- bar buttons.
Stingray Studio now has a generalized mechanism for enabling supported look and feel styles. See Section 5.2 for a description of this mechanism. The previous mechanisms described in Section 5.3 and Section 5.4 still work.
Chapter 5 Look and Feel Styles 79 5.2 Microsoft Vista Classic Style
The Vista Classic style feature allows your applications to take on a look and fill similar to Win- dows Vista Classic. This visual style is theme-enabled, and requires Windows Vista.
The Vista Classic look and feel is enabled for Objective Toolkit and Objective Grid controls. MFC- derived and Stingray custom controls now have the Vista Classic look and feel.
Applications and samples enable a particular drawing style with the function call RWSetVisualStyle(). Using this function requires inclusion of the header file RWUXTheme.h, which is found in the
RWSetVisualStyle(RW_VISUALSTYLE_VISTACLASSIC);
The following themes are available through this call:
RW_VISUALSTYLE_WINDOWSCLASSIC
RW_VISUALSTYLE_DOTNET
RW_VISUALSTYLE_OFFICE2003
RW_VISUALSTYLE_VISTACLASSIC.
80 5.3 Visual Studio .NET/Office XP Style
The following are examples of the styles of Visual Studio.NET/Office XP components that Objec- tive Toolkit offers: Figure 42 – Toolbar in Normal Mode
Figure 43 – Toolbar in Mouse Hover Mode
Figure 44 – Toolbar in Pressed Mode
Figure 45 – Toolbar in Checked Mode
Figure 46 – Menu bar in Normal Mode
Figure 47 – Menu bar in Mouse Hover Mode
Figure 48 – Menu bar with Open Submenu and Selected Item
Chapter 5 Look and Feel Styles 81 5.3.1 Enabling .NET/Office XP Styles
To enable Visual Studio.NET style toolbars and menu bars, call theBOOL RWSetDotNetStyle(BOOL bEnable=true) function from your application. This function belongs to the global namespace and can be found in Includes\Toolkit\TMenuFrm.h. The suggested place to call this function is from the InitApplication method of your CWinApp-derived class. Note that this call must be made before the creation of the Mainframe.
To view sample code showing how to enable Visual Studio.NET/Office XP styles, see the CVizApp::InitInstance function implementation in VIZ.cpp, VIZ sample:
RWSetDotNetStyle(TRUE);
The VIZ sample demonstrates this feature, and can be found in the Samples\Toolkit\MFC\Docking directory.
To fully enable the .NET style, use the Stingray Studio toolbars and menu bars. You will also need to enable ‘Cool’ look for the toolbar. For more information on ‘Cool’ look, please see Section 6.2, “The Customizable Toolbar Classes.”
82 5.4 Microsoft Office 2003 Style
The Office 2003 style feature allows your applications to take on a similar look and feel to the Mic- rosoft Office 2003 suite of products. This visual style is theme-enabled, meaning that colors will change depending on the current Windows XP theme you have enabled. (Windows XP required.)
The following are examples of the styles of Microsoft Office 2003 components that Objective Toolkit offers: Figure 49 – Gradient-shaded and rounded toolbars with grippers
Figure 50 – Hot toolbar buttons
Figure 51 – Hot pressed toolbar buttons
Figure 52 – Large toolbars
Figure 53 – Vertically docked toolbars
Figure 54 – Menus with grippers and hot menu buttons
Chapter 5 Look and Feel Styles 83 Figure 55 – Gradient-shaded menus with hot items
Figure 56 – Checks with hot and hot pressed states
Figure 57 – Expanded menus
Figure 58 – Gradient-shaded control bar with grippers
Figure 59 – Control bars with embedded controls
84 Figure 60 – Themed shortcut bars
Figure 61 – Gradient-shaded workbook/worksheet window tabs
Figure 62 – Gradient-shaded 3D tab controls
Figure 63 – Triple-nested tabs on bottom
Chapter 5 Look and Feel Styles 85 Figure 64 – Tabs on left with double-nested tabs on bottom
Figure 65 – Tabs on top with double-nested tabs on bottom
86 Figure 66 – Tabs on right with double-nested tabs on bottom
Figure 67 – Themed status bars
Figure 68 – Objective Toolkit’s Viz sample
Chapter 5 Look and Feel Styles 87 5.4.1 Enabling Office 2003 Styles
To enable Microsoft Office 2003 styles, add RWSetOfc2003Style (TRUE); in your main applica- tion class’s InitInstance(). You must also include toolkit\ot_toolbar.h in your application’s stdafx.h file to pick up the classes involved with this look-and-feel style. Theme colors will auto- matically update when you change the system theme via the OnSysColorsChange() call. Do not use this look-and-feel style in conjunction with the .NET/XP style, described in Section 5.3, “Visual Studio .NET/Office XP Style.” You can either remove any previous RWSetDotNetStyle() or set it to FALSE.
For toolbars and menus to use this style, you must create Stingray toolbars and menus. Controls that you create should have their corresponding flat style and grippers enabled. Cool Look should also be enabled.
For classes derived from SECControlBar, if you have overridden OnEraseBkgnd(), you must return SECControlBar::OnEraseBkgnd(pDC); at the end of your routine in order to have the background draw themed.
88 Chapter 6 Customizable Toolbars
6.1 Overview
The customizable toolbar classes extend traditional toolbars by allowing the user to drag-and-drop toolbar buttons onto custom toolbar configurations. These classes also implement the cool toolbar look-and-feel found in Microsoft’s Visual Studio. Figure 69 – Example of Customizable Toolbars with the Cool Look
The toolbar classes also provide dialogs that you can use to customize toolbars dynamically. Some- times the toolbars on the desktop do not contain every button available. An end-user can use these dynamic dialogs to move buttons on and off the toolbars via drag-and-drop.
Chapter 6 Customizable Toolbars 89 Figure 70 – Example Toolbar Customization Property Sheet
90 6.2 The Customizable Toolbar Classes
The hierarchies of the customizable toolbar classes are as follows: Figure 71 – Customizable Toolbar Class Hierarchies
CControlBar CObject
SECControlBar SECControlBarManager
SECCustomToolBar SECToolBarManager
SECToolBarsBase CPropertyPage
CDialog SECToolBarCmdPage
SECToolBarsDlg SECWndBtn
CPropertySheet CComboBox
SECToolBarSheet SECComboBtn
SECToolBarsPage SECStdBtn
SECTwoPartBtn
6.2.1 SECCustomToolBar
SECCustomToolBar lets you create a custom toolbar to which you can assign a specialized set of buttons. You can add or remove buttons from your toolbar via the Customize dialog. You can also drag-and-drop toolbar buttons by pressing the
In the Toolbar dialog, you can choose from large or small buttons, enable or disable tool-tips, and select the standard appearance or the new cool look. Once a button is selected, you can drag it to any toolbar. You can also drag-and-drop buttons among toolbars.
When you are dragging a toolbar, you can press the
Chapter 6 Customizable Toolbars 91 Because SECCustomToolBar inherits from SECControlBar, it includes support for sizing while docked, automatic stretching when resized, and a default context menu with facilities for adding and removing menu items. Although you can use SECCustomToolBar as a replacement for CToolBar, it works best when used in conjunction with SECToolBarManager.
6.2.2 SECToolBarManager
The SECToolBarManager class manages customizable toolbars and the state of an application’s main frame during customize mode, as invoked by SECToolBarsDlg, SECToolBarsPage, and SECToolBarCmdPage. This mode allows the user to create custom toolbars with buttons that are specific to a certain task.
In particular, SECToolBarManager performs the following functions:
Administrates all SECCustomToolBar objects.
Creates/Destroys toolbars.
Loads and maintains toolbar bitmap(s).
Provides utility access to all toolbars.
Provides a framework for the persistent state from the SECControlBarManager base class (introduced in Section 8.7.3).
Because customizable toolbars are derived from SECControlBar, you cannot attach an SECCustomToolbar to an existing CToolBar/SECToolBar. Instead, you must utilize the toolbar manager (SECToolBarManager) to create and maintain the bars.
6.2.3 SECToolBarsBase
SECToolBarsBase provides the common code base for SECToolBarsDlg and SECToolBarsPage, which provide a user interface for listing and manipulating all of the toolbars. In the toolbar dialog, the user can choose from large or small buttons, enable or disable tooltips, and select a look for the application. SECToolBarsBase is a protected class. Because its constructor is hidden, this class can- not be instantiated directly.
6.2.4 SECToolBarsDlg
SECToolBarsDlg displays a list of toolbars and allows the user to manipulate these toolbars. SECToolBarsDlg implements the Customize dialog, which you can use to create a customized tool- bar with buttons designed to perform particular tasks. On the toolbar dialog, you can choose from large or small buttons, enable or disable tooltips, and select a look for the toolbars.
92 6.2.5 SECNewToolBar
SECNewToolBar constructs the New Toolbar dialog. This dialog is invoked from within the Cus- tomize dialog, which you can use to create a toolbar comprised of buttons designed to perform a particular task. Typically, SECToolBarsDlg and SECToolBarsPage use SECNewToolBar to lay the foundation for the Customize and New Toolbar dialogs. This class also prompts you to enter the title of the new toolbar.
6.2.6 SECToolBarsPage
SECToolBarsPage constructs a toolbar property page for the Customize dialog implemented by SECToolBarsDlg. This dialog displays a list of toolbars that you can manipulate. In the Toolbar dialog, you choose from large or small buttons, enable or disable tooltips, and select a look for your toolbars.
6.2.7 SECToolBarCmdPage
The SECToolBarCmdPage class presents you with all the available toolbar buttons. You can drag these buttons onto an existing toolbar or create a new toolbar from them. You can only use SECToolBarCmdPage in an SECToolBarSheet. Do not try to use it directly in a CPropertySheet. Use the DefineBtnGroup() function to define at least one button group. SECToolBarCmdPage must be used in conjunction with a toolbar manager.
6.2.8 SECToolBarSheet
The SECToolBarSheet class constructs a property sheet that you can use with the toolbar button templates created by the SECToolBarCmdPage and SECToolBarsPage. SECToolBarSheet supports the Customize dialog, which you can use to create a toolbar comprised of buttons designed to per- form a particular task. This dialog displays a list of toolbars that can be manipulated. In the Toolbar dialog, you choose from large or small buttons, enable or disable tooltips, and select a look for your toolbars.
Chapter 6 Customizable Toolbars 93 6.3 The Toolbar Button Classes
Objective Toolkit includes a variety of classes that allow you to add different types of buttons to customizable toolbars. The following figure is of some of these button types. Figure 72 – Example Customizable Toolbar Button Types
The button classes do not derive from CWnd or CObject. SECStdBtn is the base class for all cus- tomizable toolbar buttons. The reason the buttons are not CWnd-derived is to restrict the use of Windows resources. Multiple concurrently running applications with multiple customizable tool- bars per application and multiple buttons per toolbar require considerable system resources. Our mechanism allows you to add CWnd-derived controls that can be added to the toolbars on an as- needed basis. See Section 6.3.5, “SECWndBtn,”and Section 6.7, “Creating New Button Types,”for more information. Figure 73 – Hierarchies of the Toolbar Button Classes
SECStdBtn
SECStdMenuBtn CComboBox
SECTwoPartBtn
SECTBTextBtn
SECWndBtn
SECComboBtn
6.3.1 SECStdBtn
The SECStdBtn encapsulates a single toolbar button. The SECCustomToolBar class uses it. SECStdBtn includes various operations for drawing buttons on a toolbar.
Typically, the SECStdBtn member functions are called from the Customize dialog. For more infor- mation, see Section 6.2.4. You can use this dialog to create a toolbar comprised of buttons designed to perform a particular task. If the default styles offered in the Customize dialog do not match your requirements, you can invoke the New Toolbar.
94 The New Toolbar dialog allows the user to create a new toolbar with a unique set of buttons.Use STD_BUTTON in your button map to create buttons of this type.
6.3.2 SECStdMenuBtn
This class encapsulates a bitmap toolbar button that does not execute a command. Instead, it dis- plays a drop-down menu that behaves like a context menu. This menu must be part of your application’s menu resources. If you create a separate menu resource for the button to use and you want to support bitmap menus, include this menu in your call to SECToolBarManager::SetMenuInfo().
Use the STD_MENU_BUTTON macro in your button map to create buttons of this type.
6.3.3 SECTwoPartBtn
The SECTwoPartBtn class constructs a button that splits its functionality into two parts. The two parts of the button are independent. The Undo/Redo buttons in Visual Studio and MS Word are examples of two part buttons. The left side is a button. The right side part can perform actions such as displaying a drop-down list.
When the toolbar containing the button is vertically docked, only the left side of the button is displayed.
Use the TWOPART_BUTTON in your button map to create buttons of this type.
6.3.4 SECTBTextBtn
SECTBTextBtn is a specialized class that allows you to display text in toolbar buttons when large buttons are displayed.
Use the TEXT_BUTTON or TEXT_BUTTON_EX macro in your button map to create buttons of this type.
6.3.5 SECWndBtn
The SECWndBtn class bridges the logic between a CWnd control and SECStdBtn. By multiply inheriting from a CWnd control and SECWndBtn, you can create new CWnd-derived button types. For more information, refer to Section 6.7, “Creating New Button Types.”
Chapter 6 Customizable Toolbars 95 6.3.6 SECComboBtn
The SECComboBtn class constructs a button that can function like a combo box that combines a list box and an edit control. It derives multiply from CComboBox and SECWndBtn. This inheritance gives it the functionality of a CComboBox and allows it to be embedded within an SECCustomToolBar.
When embedded in a vertically docked toolbar, the combo box is replaced with a simple button.
Use the COMBO_BUTTON macro in your button map to create buttons of this type.
6.4 Comparing SECToolbar to SECCustomToolBar
The SECCustomToolbar class is not a drop-in replacement for the CToolbar or SECToolbar classes.
96 6.5 Toolbar Button Map
The toolbar manager for the customizable toolbar also allows you to register a button map. A button map lets you map specific button command IDs to non-standard toolbar buttons such as text but- tons, combo box buttons, and two part buttons. You don’t need to include a button map if you only need traditional bitmap-only buttons.
The button map supports the following features:
Allows customization of buttons on a per-command basis (recall button instances can be cloned).
Sets the button style.
Sets the button class.
Sets button class specific parameters.
Is linked in via the toolbar manager.
The button map is placed in the implementation file of your frame class, similar to the way a win- dow message map is added.
The following lines of code are an example of a button map.
BEGIN_BUTTON_MAP(btnMap) STD_BUTTON(ID_CHECKED, TBBS_CHECKBOX) STD_BUTTON(ID_DISABLE, TBBS_CHECKBOX) STD_BUTTON(ID_INDETERMINATE, TBBS_INDETERMINATE) TWOPART_BUTTON(ID_UNDO, ID_DROPARROW, TBBS_CHECKBOX, 0) TWOPART_BUTTON(ID_REDO, ID_DROPARROW, 0, ID_REDO) COMBO_BUTTON(ID_FIND, IDC_COMBO_FIND, 0, CBS_DROPDOWN, 150, 40, 150) END_BUTTON_MAP()
Once you define a button map, it is given to the toolbar manager. For more information, see Section 6.9.7.
6.5.1 STD_BUTTON
The STD_BUTTON macro extends the standard customizable toolbar bitmap only button by intro- ducing a style parameter. The syntax is as follows:
STD_BUTTON(ButtonID, Style)
Table 24 – STD_Button Macro Parameters
Macro parameter Description
ButtonID Command ID for the button.
Style Window style (WS_*)
Chapter 6 Customizable Toolbars 97 6.5.2 STD_MENU_BUTTON
The STD_MENU_BUTTON macro extends the standard customizable toolbar by creating a bitmap tool- bar button that drops down a menu instead of executing a command.
STD_MENU_BUTTON(ButtonID, style, MenuResID, SubMenuIdx, TPMAlign)
Table 25 – STD_MENU_BUTTON Macro Parameters
Macro Description Parameter
ButtonID The command ID for the button. This command is not actually exe- cuted when the button is pressed.
style The button’s window style. This parameter is usually zero.
MenuResID The resource ID for the menu resource for the drop-down menu.
SubMenuIdx Zero-based index for the popup menu’s location in the menu resource—usually zero if creating a separate menu resource.
TPMAlign Alignment of the menu when dropped with respect to the toolbar button. Can be either TPM_LEFTALIGN, TPM_CENTERALIGN, or TPM_RIGHTALIGN.
6.5.3 TEXT_BUTTON
The TEXT_BUTTON macro implements a customizable toolbar button with text. The macro syntax is shown below.
TEXT_BUTTON(ButtonID, textResourceID)
Macro parameter Description
ButtonID Command ID for the button.
TextResourceID Resource ID of the text string (or 0 to load based on the button ID).
98 6.5.4 TEXT_BUTTON_EX
The TEXT_BUTTON_EX macro is similar to TEXT_BUTTON (it implements a customizable toolbar but- ton with text) except it also introduces a style parameter. The syntax is as follows:
TEXT_BUTTON_EX(ButtonID, TextResourceID, Style)
Macro parameter Description
ButtonID Command ID for the button.
TextResourceID Resource ID for the text string (or 0 to load based on the button ID).
Style Window style (WS_*)
6.5.5 TWOPART_BUTTON
The TWOPART_BUTTON macro implements a customizable toolbar button that is divided into two bitmaps. It can issue two separate command IDs (for example, an Undo-Redo button). The syntax for this macro is as follows:
TWOPART_BUTTON(ButtonID, ButtonID2, Style, DispatchID)
Macro parameter Description
ButtonID Obtains the bitmap resource and command ID for the left side of the button.
ButtonID2 Obtains the bitmap resource for the right side of the button.
Style Window style (WS_*).
DispatchID The command ID for the right side of the button.
6.5.6 COMBO_BUTTON
The COMBO_BUTTON macro implements a customizable toolbar button from which you can drop down a combo box. The syntax is as follows:
COMBO_BUTTON(ButtonID, ComboID, Style, ComboStyle, ComboDefWidth, ComboMinWidth, ComboHeight)
Macro parameter Description
ButtonID Command ID for the button.
ComboID Command ID for the combo button.
Style Window style (WS_*).
Chapter 6 Customizable Toolbars 99 ComboStyle Combo style (CBS_*). Not all combo styles are supported.
ComboDefWidth Default width of combo button.
ComboMinWidth Minimum width of combo button.
ComboHeight Height of combo button.
6.6 Toolbar Button Styles
The style flags for toolbar buttons are stored in SECStdBtn::m_nStyle. In addition, you can clone and create buttons through the user interface. Applying a style to a specific button is difficult because you need to use a style template.
6.6.1 Button style macros
You can use the following button style macros as parameters in the button map. They can be logi- cally OR’ed with the button state macros.
Button style macro Equivalent to Description
TBBS_BUTTON TBSTYLE_BUTTON Standard button
TBBS_SEPARATOR TBSTYLE_SEP Separator
TBBS_CHECKBOX TBSTYLE_CHECK Auto check button
TBBS_GROUP TBSTYLE_GROUP Marks the start of a group.
TBBS_CHECKGROUP TBBS_GROUP | Marks the start of a group of check buttons. TBBS_CHECKBOX
6.6.2 Button State Macros
You can use the following button state macros as style parameters with the button map macros. You can logically OR’ed them with the button style macros.
Button state macro Equivalent to Description
TBBS_CHECKED TBSTATE_CHECKED Button is checked/down.
TBBS_PRESSED TBSTATE_PRESSED Button is being depressed.
TBBS_DISABLED TBSTATE_ENABLED Button is disabled.
TBBS_INDETERMINATE TBSTATE_INDETERMINATE Third state
100 TBBS_HIDDEN TBSTATE_HIDDEN Button is hidden.
TBBS_WRAPPED TBSTATE_WRAP Button is wrapped at this point.
6.7 Creating New Button Types
You can create new button types; however, the process can be tedious and does not support the cool or flat look. First you need to derive a class from SECWndBtn and the CWnd (SECComboBtn). Then you need to propagate CWnd events across the SECWndBtn bridge.
Chapter 6 Customizable Toolbars 101 6.8 Customization Dialogs
You can use customization dialogs to display a hidden toolbar. They have a lightweight interface and can easily be overridden to remove various buttons and checkboxes. Figure 74 – Example Toolbars Dialog
Figure 75 – Example Toolbars Property Page
102 Figure 76 – Example Toolbars Command Property Page
6.8.1 Creating SECCustomToolBars—Arguments and Cautions
The toolbar ID defaults to AFX_IDW_TOOLBAR +0 so that two toolbars can take the default in deftoolbar. When you’re creating a toolbar, you cannot use +2, +3, or +4 or go over +20.
6.8.2 The Effect of Modifying Toolbars on Persistence
If the buttons on a toolbar are modified at run time (for example, by dynamically creating a button) persistence may fail.
Chapter 6 Customizable Toolbars 103 6.9 Using the Customizable Toolbar Classes
The following sections describe how to use customizable tooltips in your applications.
6.9.1 To incorporate customizable toolbars into your application
1. Generate a skeletal application with toolbars using AppWizard.
If you create a Do this
MDI application Replace CMDIFrameWnd with SECMDIFrameWnd. Replace CMDIChildWnd with SECMDIChildWnd.
SDI application Replace CFrameWnd with SECFrameWnd.
2. Replace CToolBar or SECToolbar with SECCustomToolBar. ReplaceCStatusBar with SECStatusBar.
3. Use the Microsoft Visual Studio toolbar resource editor to create a composite bitmap of all the toolbar buttons you want to use with any of the customizable toolbars as one resource. Do NOT put any button separators inside this toolbar resource. Specify every button com- mand ID you want to associate with a bitmap in the resource editor.
4. You can also create a copy of the previous resource and set a larger pixel height/width and redraw any bitmap images as you see fit. This is your large buttons resource. It is important that you maintain a 1-1 button ID mapping to the resource you created earlier. This is essen- tially a different view of the same data.
5. In your CMainFrame constructor, create the SECToolBarManager object. Use the existing m_pControlBarManager member from the frame’s base class. For example:
m_pControlBarManager = new SECToolBarManager(this);
6. In CMainFrame::OnCreate(), issue a call to LoadToolBarResource to load the resource(s) created earlier. If you're only using one resource, use the same resource ID twice. For example,
// large and small resources pToolBarMgr-> LoadToolBarResource(MAKEINTRESOURCE(IDR_MAINFRAME), MAKEINTRESOURCE(IDR_MAINFRAME_LG)));
104 // OR small resources only (identical views) pToolBarMgr-> LoadToolBarResource(MAKEINTRESOURCE(IDR_MAINFRAME), MAKEINTRESOURCE(IDR_MAINFRAME)));
m_pControlBarManager is declared as type SECControlBarManager so you must typecast to SECToolBarManager to access the specific member function mentioned above. For example,
SECToolBarManager* pToolBarMgr= (SECToolBarManager *)m_pControlBarManager;
7. Create a button group. For example:
static UINT BASED_CODE fileButtons[] = { ID_FILE_NEW, ID_FILE_OPEN, ID_FILE_SAVE, ID_FILE_SAVEALL, };
See Section 6.9.4, “To implement button groups,”for more information.
8. In CMainFrame::OnCreate(), define default toolbar resources via the DefineDefaultToolBar() method. For example,
pToolBarManager->DefineDefaultToolBar(AFX_IDW_TOOLBAR, _T("File"),NUMELEMENTS(fileButtons),fileButtons, CBRS_ALIGN_ANY,AFX_IDW_DOCKBAR_TOP);
Toolbar IDs AFX_IDW_TOOLBAR+1,+2,+3 are reserved by other MFC components, includ- ing the status bar, and cannot be used in this call. However, you can use +0, +4 and higher.
9. If you do not plan to load toolbar states from persistent storage, call the toolbar manager’s SetDefaultDockState() method to pre-load the default toolbars in your application. For example:
pToolBarMgr->SetDefaultDockState();
See Section 6.9.7, “To use the button map,” Section 6.9.22, “To save and restore customizable toolbars,” and “Section 6.9.17, “To implement the toolbar customization dialog.”
6.9.2 To implement toolbars with the flat cool look with a toolbar manager
In the OnCreate() method of your main frame class, call the EnableCoolLook() method of the toolbar manager. For example:
// the boring old toolbars won't cut it, let's see something cool! pToolBarMgr->EnableCoolLook(TRUE);
Chapter 6 Customizable Toolbars 105 6.9.3 To implement toolbars with the flat cool look without a toolbar manager
1. Generate a skeletal application with toolbars.
If you create a Do this
MDI application Replace CMDIFrameWnd with SECMDIFrameWnd. Replace CMDIChildWnd with SECMDIChildWnd.
SDI application Replace CFrameWnd with SECFrameWnd.
2. Replace CToolBar or SECToolbar with SECCustomToolBar and CStatusBar with SECStatusBar.
3. Change the toolbar create syntax to that of the SECCustomToolBar create overload and spe- cific the cool extended styles. For example:
if(!m_wndToolBar.CreateEx(CBRS_EX_COOLBORDERS|CBRS_EX_GRIPPER,this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) {
TRACE0("Failed to create toolbar\n"); return -1; // fail to create }
6.9.4 To implement button groups
1. Create the button group as a static array using the button control IDs defined with the asso- ciated bitmap resource in the Resource Editor. For example:
static UINT BASED_CODE fileButtons[] = { ID_FILE_NEW, ID_FILE_OPEN, ID_FILE_SAVE, ID_FILE_SAVEALL, };
2. In CMainFrame::OnCreate(), define the default toolbar using the DefineDefaultToolBar() method. For example:
SECToolBarManager* pToolBarMgr= (SECToolBarManager *)m_pControlBarManager; pToolBarManager-> DefineDefaultToolBar(AFX_IDW_TOOLBAR, _T("File"),NUMELEMENTS(fileButtons),fileButtons, CBRS_ALIGN_ANY,AFX_IDW_DOCKBAR_TOP);
Toolbar Ids AFX_IDW_TOOLBAR+1,+2,+3 are reserved by other MFC components, including the status bar and cannot be used in this call. However, you can use +0, +4 and higher.
106 6.9.5 To use multiple toolbar bitmap resources with the toolbar manager
Use the SECToolBarManager::AddToolBarResource() method in conjunction with LoadToolBarResource(). For example:
// Use the following calls for multiple bitmaps // (to surpass the 2048 pixel width limit on toolbar bitmaps) pToolbarManager->AddToolBarResource( MAKEINTRESOURCE(IDR_MAINFRAME1), MAKEINTRESOURCE(IDR_MAINFRAMELARGE1)); pToolbarManager->AddToolBarResource( MAKEINTRESOURCE(IDR_MAINFRAME2), MAKEINTRESOURCE(IDR_MAINFRAMELARGE2)); VERIFY(pMgr->LoadToolBarResource());
6.9.6 To find a button on a customizable toolbar
1. Obtain a pointer to the customizable toolbar. See Section 6.9.15, “To obtain a pointer to a specific customizable toolbar,” for more information.
2. For each customizable toolbar, use the GetBtnCount() method and the m_btns data mem- ber to access the button data.
If your application contains the Customize dialog, you may have more than one copy of that button in existence.
For example:
// Get pointer to custom toolbar using the preceding // procedure… int nButtons=pBar->GetBtnCount();
for(int nIndex=0;nIndex
}
6.9.7 To use the button map
The button map maps specific button command IDs to non-standard toolbar buttons.
1. Create a customizable toolbar that uses a toolbar manager. See Section 6.9.1 for more information.
2. Create a button map in your frame class implementation file. For example:
BEGIN_BUTTON_MAP(btnMap) STD_BUTTON(ID_CHECKED, TBBS_CHECKBOX) STD_BUTTON(ID_DISABLE, TBBS_CHECKBOX)
Chapter 6 Customizable Toolbars 107 STD_BUTTON(ID_INDETERMINATE, TBBS_INDETERMINATE) TWOPART_BUTTON(ID_UNDO, ID_DROPARROW, \ TBBS_CHECKBOX, 0) TWOPART_BUTTON(ID_REDO, ID_DROPARROW, 0, \ ID_REDO) COMBO_BUTTON(ID_FIND, IDC_COMBO_FIND, 0, \ CBS_DROPDOWN, 150, 40, 150) END_BUTTON_MAP()
3. In the frame’s OnCreate() method, provide a reference to the button map using the toolbar manager’s SetButtonMap() method. For example,
pMgr->SetButtonMap(btnMap);
6.9.8 To implement a text button
1. Create a customizable toolbar that uses a toolbar manager. See Section 6.9.1, “To incorporate customizable toolbars into your application,” for more information.
2. Create a button map with a TEXT_BUTTON macro entry in your frame class implementation file. For example:
BEGIN_BUTTON_MAP(btnMap) TEXT_BUTTON(ID_TEXTBTN, IDS_BUTTONTEXT) END_BUTTON_MAP()
3. In the frame’s OnCreate() method, provide a reference to the button map using the toolbar manager’s SetButtonMap() method. For example:
pMgr->SetButtonMap(btnMap);
6.9.9 To implement a text button with styles
1. Create a customizable toolbar that uses a toolbar manager. See Section 6.9.1, “To incorporate customizable toolbars into your application,” for more information.
2. Create a button map with a TEXT_BUTTON_EX macro entry in your frame class implementa- tion file. For example:
BEGIN_BUTTON_MAP(btnMap) TEXT_BUTTON_EX(ID_TEXTBTN, IDS_BUTTONTEXT, \ TBBS_CHECKBOX) END_BUTTON_MAP()
3. In the frame’s OnCreate() method, provide a reference to the button map using the toolbar manager’s SetButtonMap() method. For example:
pMgr->SetButtonMap(btnMap);
108 6.9.10 To implement a combo button
1. Create a customizable toolbar that uses a toolbar manager. See Section 6.9.1 for more information.
2. Create a button map with a COMBO_BUTTON macro entry in your frame class implementation file. For example:
BEGIN_BUTTON_MAP(btnMap) COMBO_BUTTON(ID_FIND, IDC_COMBO_FIND, 0, CBS_DROPDOWN, 150, 40, 150) END_BUTTON_MAP()
3. In the frame’s OnCreate() method, provide a reference to the button map using the toolbar manager’s SetButtonMap() method. For example:
pMgr->SetButtonMap(btnMap);
6.9.11 To implement a twopart button
1. Create a customizable toolbar that uses a toolbar manager. See Section 6.9.1, “To incorporate customizable toolbars into your application,” for more information.
2. Create a button map with a TWOPART_BUTTON macro entry in your frame class implementa- tion file. For example:
BEGIN_BUTTON_MAP(btnMap) TWOPART_BUTTON(ID_UNDO, ID_DROPARROW, \ TBBS_CHECKBOX, 0) END_BUTTON_MAP()
3. In the frame’s OnCreate() method, provide a reference to the button map using the SetButtonMap() method. For example:
pMgr->SetButtonMap(btnMap);
6.9.12 To implement a bitmap button using styles
1. Create a customizable toolbar that uses a toolbar manager. See Section 6.9.1, “To incorporate customizable toolbars into your application,” for more information.
2. Create a button map with a STD_BUTTON macro entry in your frame class implementation file. For example:
BEGIN_BUTTON_MAP(btnMap) STD_BUTTON(ID_DISABLE, TBBS_CHECKBOX) END_BUTTON_MAP()
3. In the frame’s OnCreate() method, provide a reference to the button map using the SetButtonMap() method. For example:
pMgr->SetButtonMap(btnMap);
Chapter 6 Customizable Toolbars 109 6.9.13 To make a customizable toolbar dockable
When you define toolbars with the toolbar manager, specify the docking behavior as parameters in the DefineDefaultToolbar() method. For example:
pToolBarManager-> DefineDefaultToolBar(AFX_IDW_TOOLBAR, _T("File"),NUMELEMENTS(fileButtons),fileButtons, CBRS_ALIGN_ANY,AFX_IDW_DOCKBAR_TOP);
// Call this to position the default toolbars as // configured by the DefineDefaultToolBar command // above. Don't do this if you are going use // LoadBarState/LoadState below, as these functions // will call it anyways on nonexistent state info. pToolBarMgr->SetDefaultDockState();
6.9.14 To reposition customizable toolbars at run time
1. Obtain a pointer to the customizable toolbar. See Section 6.9.15 and Section 6.9.16.
2. After you identify a controlbar as a customizable toolbar, use the DockControlBarEx mem- ber of CFrameWnd to modify the position of the toolbar. For example:
DockControlBarEx(pBar, AFX_IDW_DOCKBAR_RIGHT);
6.9.15 To obtain a pointer to a specific customizable toolbar
Use the CFrameWnd::GetControlBar() method. Pass the ID of the toolbar you want to access as a parameter. For example,
SECCustomToolBar* pBar = STATIC_DOWNCAST( SECCustomToolBar, GetControlBar(AFX_IDW_TOOLBAR));
6.9.16 To iterate the customizable toolbars
Use the m_listControlBars member of the SECFrameWnd or SECMDIFrameWnd class declared as a CPtrList to iterate through the configured controlbars of the frame window:
CControlBar* pBar; POSITION pos=m_listControlBars.GetHeadPosition();
while(pos) { pBar=(CControlBar*) m_listControlBars.GetNext(pos);
if(pBar-> IsKindOf(RUNTIME_CLASS(SECCustomToolBar))) { // do something with this custom toolbar } }
110 6.9.17 To implement the toolbar customization dialog
1. Incorporate toolbars with a toolbar manager. See Section 6.9.1, “To incorporate customiz- able toolbars into your application,”for more information.
2. Create a handler method in which to instantiate the Customization dialog. For example:
void CMainFrame::OnCustomize() { }
3. Within the handler, instantiate a property sheet of type SECToolBarSheet. For example:
SECToolBarSheet toolbarSheet;
4. If you need a toolbar page that shows and hides toolbars, create a property page of type SECToolBarsPage. Then, add it to the property sheet after specifying the toolbar manager for the page. For example:
SECToolBarsPage toolbarPage; toolbarPage.SetManager((SECToolBarManager*)m_pControlBarManager); toolbarSheet.AddPage(&toolbarPage);
5. If you need a toolbar command page to drag-and-drop additional buttons onto toolbars, create a property page of SECToolBarCmdPage. Specify the toolbar manager, define the button groups, and add the page to the property sheet. For example:
SECToolBarCmdPage cmdPage(SECToolBarCmdPage::IDD, IDS_COMMANDS); cmdPage.SetManager((SECToolBarManager*)m_pControlBarManager); cmdPage.DefineBtnGroup(_T("File"), NUMELEMENTS(fileButtons), fileButtons); cmdPage.DefineBtnGroup(_T("Help"), NUMELEMENTS(helpButtons), helpButtons); cmdPage.DefineBtnGroup(_T("Browse"), NUMELEMENTS(browseButtons), browseButtons); cmdPage.DefineBtnGroup(_T("Debug"), NUMELEMENTS(debugButtons), debugButtons); cmdPage.DefineBtnGroup(_T("Palette"), NUMELEMENTS(paletteButtons), paletteButtons); cmdPage.DefineBtnGroup(_T("Resource"), NUMELEMENTS(resourceButtons), resourceButtons);
toolbarSheet.AddPage(&cmdPage);
6. You can add additional property pages to the property sheet. For example:
// We have a dummy page to demonstrate window activation // handling when swapping to and from the toolbar page CPropertyPage dummyPage(IDD_DUMMY); toolbarSheet.AddPage(&dummyPage);
Chapter 6 Customizable Toolbars 111 7. To invoke the dialog, call the DoModal() method:
toolbarSheet.DoModal();
6.9.18 To invoke the toolbar customization dialog with a toolbar button
1. Create a handler to create the toolbar Customize dialog. See Section 6.9.17, “To implement the toolbar customization dialog,” for more information.
2. Map a button event to an additional handler, which posts a message to the message queue to launch the toolbar Customization dialog. For example,
void CMainFrame::OnMyDialogButton() { PostMessage(WM_COMMAND,IDC_CUSTOMIZE,NULL); }
Do not use SendMessage(). The button message handler must return prior to invoking the Customization dialog.
6.9.19 To hide and show customizable toolbars
1. Obtain a pointer to the desired toolbar. See Section 6.9.15, “To obtain a pointer to a specific customizable toolbar,” for more information.
2. Use the CFrameWnd::ShowControlBar() method to show or hide the toolbar.
6.9.20 To set the docking order of customizable toolbars
Specify the docking order via the nDockNextToID parameter of DefineDefaultToolBar. Set the value of this ID to the previous toolbar in the docking order. Here is the complete prototype for the method:
void SECToolBarManager::DefineDefaultToolBar(UINT nID, const CString& strTitle, UINT nBtnCount, UINT* lpBtnIDs, DWORD dwAlignment /* = CBRS_ALIGN_ANY */, UINT nDockBarID /* = AFX_IDW_DOCKBAR_TOP */, UINT nDockNextToID /* = NULL */, BOOL bDocked /* = TRUE */, BOOL bVisible /* = TRUE */)
6.9.21 To changing the font for text buttons
Use the static SECTBTextButton::SetTextFont() accessor method to reset the style before using the toolbar manager to create any customizable toolbars, preferably in your CMainFrame construc- tor. For example:
112 CMainFrame::CMainFrame() { CFont* pFont=LoadCustomFontFromSomewhere(); SECTBTextButton::SetTextFont(pFont); }
6.9.22 To save and restore customizable toolbars
Method 1: SECWorkspaceManagerEx
Implement the SECWorkspaceManagerEx to save the state of your toolbars, docking windows, and views. For more information, see SECWorkspaceManagerEx in the Objective Toolkit Class Reference.
Method 2: LoadBarState/SaveBarState
The LoadBarState()and SaveBarState() methods are members of the SECFrameWnd and SECMDIFrameWnd frame classes. For example:
LoadBarState(_T("VizBarState"));
Method 3: LoadState/SaveState
The LoadState()/SaveState() methods are members of SECToolbarManager. For example: pToolBarMgr->LoadState(_T("VizBarState"));
If you do not want to support toolbar persistence, you can use the SECToolBarManager::SetDockState() method directly to place default toolbars.
6.9.23 To draw owner-draw controls embedded in a vertically docked toolbar
In the appropriate SECWndBtn-derived class, override SetMode() and always pass FALSE through to the base implementation. For example: void CMyWndBtn::SetMode(BOOL /* bVertical */) { SECWndBtn::SetMode(FALSE); }
Take a look at the Toolbar sample located in \Samples\Toolkit\MFC\Docking\Toolbar.
Chapter 6 Customizable Toolbars 113 114 Chapter 7 Menu Bars
7.1 Overview
The Objective Toolkit menu bars implement the newer Cool Look style of dockable, flat-look menu bars. The menu bars provide you with additional functionality. You can:
Drag items onto them.
Rearrange their buttons.
Associate iconic cues with them.
Customize them. For example, you can show or hide them. Figure 77 – Sample Application with Objective Toolkit menu bars
Chapter 7 Menu Bars 115 Figure 78 – Sample Application with Objective Toolkit customizable menu bars
116 7.2 Menu Bar Classes
The following figure is of the class hierarchy for the menu bar classes. Figure 79 – Objective Toolkit Menu Bar Class Hierarchy
SECCustomToolBar
SECMenuBar
SECMDIMenuBar
7.2.1 SECMenuBar
SECMenuBar replaces your normal menu with a dockable bar that resembles the Visual Studio and Office 97 menus. A simple button class represents the menu bar buttons that display the appropri- ate HMENU when clicked. Because SECMenuBar derives from SECCustomToolBar, you can customize the menu bar when used it is used in conjunction with SECToolBarManager. Refer to Chapter 6, “Customizable Toolbars,” for more information. In addition, you can include bitmaps with menus so they look like the most current menus. Integrating this class into an existing applica- tion that uses the SECToolBarManager takes as little as three lines of code.
7.2.2 SECMDIMenuBar
SECMDIMenuBar is an SECMenuBar derivative that handles the system menu and caption but- tons when an MDI child window is maximized. The rest of its features are the same as the SECMenuBar class.
See the three MDI samples in the samples\toolkit\MFC\docking\menubar subdirectory for infor- mation on using this class.
Chapter 7 Menu Bars 117 7.3 Customizing the Display of Menu Pop-ups
When a menu pop-up is displayed, a registered message WM_SECGETMENU is sent to the SECFrameWnd/SECMDIFrameWnd. The WPARAM parameter specifies the ID of the menu contain- ing the pop-up. The LPARAM parameter specifies the index of the pop-up within that menu. The message handler needs to return the HMENU of the pop-up menu to be displayed.
The default handler for this message retrieves the pop-up menu by searching the CMultiDocTemplate list for the correct menu ID. If the list does not contain the menu ID, the han- dler searches the frame menu resource. By providing your own handler for this message, you can customize the returned HMENU, the only restriction is that the HMENU handle must persist after this function returns.
Note that both SECFrameWnd and SECMDIFrameWnd have member variables (m_hMenuFrame and m_nIDMenuResource) that contain the handle of the frame window's menu and its ID (when menu bar support is enabled).
118 7.4 Menu Button Map Macros
Two macros are provided for defining menu buttons in the button map.
MENU_BUTTON(id, style, menuId, popupIndex, title) MENU_BUTTON_EX(id, style, menuId, popupIndex, title, bitFlag)
Table 26 – Parameters for Menu Button Map
Macro parameter Description
id The unique ID for this button.
style The style for this button (should include SEC_TBBS_N- ODISABLE so that the button is not disabled if it does not have a command handle).
menuId The ID of the menu resource containing the pop-up menu for this button.
popupIndex The index of pop-up menu within menuId.
title The title for this button.
bitFlag The bit flag for this menu button.
Chapter 7 Menu Bars 119 7.5 WM_EXTENDCONTEXTMENU
The SECControlBar::OnContextMenu() method sends the WM_EXTENDCONTEXTMENU message to the application’s main frame after creating the default context menu. Trap this message if you need to customize the context menu. To customize the menu, simply cast the wParam parameter to an SECControlBar type and the lParam parameter to an CMenu type and modify the menu using the CMenu operations.
120 7.6 Using the Menu Bar Classes
The following sections give details and tips on using the menu bar classes.
7.6.1 To Incorporate Objective Toolkit Menubars Into Your Code—Simple Case
1. Instantiate the menubar object in your mainframe constructor in addition to the SECToolBarManager object created for customizable toolbar support. If you’re creating a SDI application, use SECMenuBar. If you’re creating an MDI application, use SECMDIMenuBar.
m_pMenuBar is a member variable of SECFrameWnd or SECMDIFrameWnd (base class of CMainFrame).
CMainFrame::CMainFrame() { m_pMenuBar = new SECMDIMenuBar; // or SECMenuBar for SDI }
2. If you want to have bitmap support enabled for your menubar menus, include a call to the EnableBmpMenus() method in the constructor.
3. Delete the menubar in the main frame destructor.
CMainFrame::~CMainFrame() { if(NULL != m_pMenuBar) { delete m_pMenuBar; m_pMenuBar = NULL; } }
4. In your mainframe OnCreate() handler, use the SetMenuInfo() method of SECToolBarManager to define the menu resources used by the application. This member takes a variable number of arguments based on the number of toolbars to autoconfigure. The syntax is:
SetMenuInfo(
For example:
pMgr->SetMenuInfo(4,IDR_MAINFRAME,IDR_EDITVIEW, IDR_LISTVIEW, IDR_FILEVIEW);
Chapter 7 Menu Bars 121 Internally these functions assign a unique bit flag to each menu resource. The code in the preceding example assigns the bit flags in the following manner:
Menu Resource Bit Mask
IDR_MAINFRAME 0x00000001
IDR_EDITVIEW 0x00000002
IDR_LISTVIEW 0x00000004
IDR_FILEVIEW 0x00000008
Then, the menu bar is populated with SECTBMenuBtn instances for all of the menu resources. Each SECTBMenuBtn is assigned the bit flag for its parent menu resource. In the preceding example, all menu buttons belonging to IDR_MAINFRAME would have bit 0 set in their bit flag, menu buttons belonging to IDR_EDITVIEW would have bit 1 set, etc.
When a MDI child window becomes active, the SECMenuBar::SwitchMenu() function is called with the ID of the menu resource associated with that window (taken from the docu- ment template). SwitchMenu() looks up the bit flag associated with the given ID, and shows all the SECTBMenuBtns that have that bit set and hides those that do not with the button style TBBS_HIDDEN.
5. If you want to apply the cool look to your menubar, call SECToolBarManager::EnableCoolLook() in your mainframe's OnCreate() handler For example:
pMgr->EnableCoolLook();
6. Call EnableDocking(), as you would for any standard toolbar. This step assumes that you called EnableDocking(CBRS_ALIGN_ANY) on the frame window. For example:
// dock the menubar m_pMenuBar->EnableDocking(CBRS_ALIGN_ANY);
7. Dock the menu bar using either the DockControlBar() or DockControlBarEx() methods. You can float the menu bar afterward, but it must be docked for initialization.
DockControlBar(m_pMenuBar);
7.6.2 To Incorporate Objective Toolkit Menubars Into Your Code--Advanced Case
You can make the menu bar more efficient by using the toolbar manager (see the MDIADV sample). With the button map, you can define the bit flags that specify to which menu a particular menu button belongs. This enables you to use the toolbar manager to create a single bar that shows and hides the buttons instead of multiple bars that you need to switch between. You can still use the SwitchMenu() function; however, an additional button map allows greater customization. When you create a button map fewer buttons are created which results in a reduction of the memory required.
// IDs for menu buttons #define ID_MENUBAR_FILE 0x80000001 #define ID_MENUBAR_EDIT 0x80000002
122 #define ID_MENUBAR_VIEW 0x80000003 #define ID_MENUBAR_TOOLS 0x80000004 #define ID_MENUBAR_WINDOW 0x80000005 #define ID_MENUBAR_HELP 0x80000006
// View Bit Flags #define BITFLAG_MAINFRAME 0x00000001 #define BITFLAG_EDITVIEW 0x00000002 #define BITFLAG_ALL BITFLAG_MAINFRAME | \ BITFLAG_EDITVIEW
////////////////////////////////////////////////////// // Define the button map // NOTE: MENU_BUTTON_EX and MENU_BUTTON are macros. Line // continuation // characters are required if the text is to be used as formatted // here. They may be removed if your macro only uses one line. BEGIN_BUTTON_MAP(btnMap) MENU_BUTTON_EX(ID_MENUBAR_FILE, SEC_TBBS_NODISABLE, \ IDR_MDIADVTYPE, 0, _T("&File"), \ BITFLAG_ALL) MENU_BUTTON_EX(ID_MENUBAR_EDIT, SEC_TBBS_NODISABLE, \ IDR_MDIADVTYPE, 1, _T("&Edit"), \ BITFLAG_EDITVIEW) MENU_BUTTON_EX(ID_MENUBAR_VIEW, SEC_TBBS_NODISABLE, \ IDR_MDIADVTYPE, 2, _T("&View"), \ BITFLAG_ALL) MENU_BUTTON_EX(ID_MENUBAR_TOOLS, SEC_TBBS_NODISABLE, \ IDR_MDIADVTYPE, 3, _T("&Tools"), \ BITFLAG_ALL) MENU_BUTTON_EX(ID_MENUBAR_WINDOW, SEC_TBBS_NODISABLE, \ IDR_MDIADVTYPE, 4, _T("&Window"), \ BITFLAG_EDITVIEW) MENU_BUTTON_EX(ID_MENUBAR_HELP, SEC_TBBS_NODISABLE, \ IDR_MDIADVTYPE, 5, _T("&Help"), \ BITFLAG_ALL) END_BUTTON_MAP()
Now you have two different menus: one for when no view is available (IDR_MAINFRAME), and the other for an edit view (IDR_EDITVIEW). You have declared that the menu buttons ID_MENUBAR_FILE, ID_MENUBAR_VIEW, ID_MENUBAR_TOOLS, and ID_MENUBAR_HELP appear in both menus by specifying the BITFLAG_ALL bit flag. You set ID_MENUBAR_EDIT and ID_MENUBAR_WINDOW to appear only on the IDR_EDITVIEW menu by specifying the BITFLAG_EDITVIEW bit flag. Although BITFLAG_MAINFRAME is defined, it is only used by the BITFLAG_ALL definition.
In your CMainFrame::OnCreate() method, use the SECToolBarManager::SetMenuMap() method to define how the bit flags map onto menu resource IDs, and also use the SECToolBarManager::LayoutMenuBar() to define the initial menu button layout for the menu bar.
You need to create a table that specifies the order of the buttons on the menu bar.
// Table mapping bitflag to menu resource // Default menu bar layout static UINT menuButtons[] = { ID_MENUBAR_FILE, ID_MENUBAR_EDIT,
Chapter 7 Menu Bars 123 ID_MENUBAR_VIEW, ID_MENUBAR_TOOLS, ID_MENUBAR_WINDOW, ID_MENUBAR_HELP };
Then, you need to associate each menu type with a bit flag.
static SECMenuMap menuMap[] = { { IDR_MAINFRAME, BITFLAG_MAINFRAME }, { IDR_MDIADVTYPE, BITFLAG_EDITVIEW } };
The following code is not complete. It only shows the steps necessary to implement the menu bar. The code that implements toolbars, status bars, and other objects in the main frame is not shown. This example assumes that simple persistence is implemented with storage under a key named Menu60.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (SECFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // Verify the presence of the toolbar manager and cast it to // the correct type so that we can access the proper methods. ASSERT(m_pControlBarManager != NULL); ASSERT_KINDOF(SECToolBarManager, m_pControlBarManager); SECToolBarManager* pToolBarMgr = (SECToolBarManager*)m_pControlBarManager;
// Set the menu map for the toolbar manager using our // previously defined menuMap. pToolBarMgr->SetMenuMap(menuMap, NUMELEMENTS(menuMap));
// Use the previously defined menu button layout to set the // order and presence of the default buttons. pToolBarMgr->LayoutMenuBar(NUMELEMENTS(menuButtons), menuButtons);
// Allow docking on all four sides. EnableDocking(CBRS_ALIGN_ANY);
// Enable the cool look. Cool look is required to obtain // the Office 2003 and Vista Classic look and feel. pToolBarMgr->EnableCoolLook(TRUE);
// load old state (if any) LoadBarState(_T("Menu60")); pToolBarMgr->LoadState(_T("Menu60"));
return 0; }
When an SECMDIChildWnd is activated, it calls into SECMDIFrameWnd::ActivateMenu() with the ID of its menu resource. You can override this function to customize the way the menu bar is changed when views become active. You can change the state of the menu bar by calling SECMenuBar::SwitchMenu() or SECMenuBar::EnableBitFlag() to enable the buttons associated with the given menu ID or bit flag respectively.
124 SECMenuBar::SwitchMenu() is called with the menu ID of the menu you want to display.
BOOL SECMenuBar::SwitchMenu(UINT nIDResource)
SECMenuBar::EnableBitFlag() is called with the bitflag and a BOOL bUpdate. If you wish to have the menu bar redrawn immediately, you can pass TRUE in for bUpdate. void SECMenuBar::EnableBitFlag(DWORD dwBit, BOOL bUpdate)
7.6.3 To Implement SECMenuBar Or SECMDIMenuBar Without a Toolbar Manager
The following steps provide dockable cool look menus without customization.
1. Follow the steps for enabling docking window support. This consists of replacing your frame classes (SECFrameWnd) with SECMDIFrameWnd, replacing the child frames with SECMDIChildWnd, and changing all dockable and non-dockable bar types to the Stingray equivalent. If persistence is needed, instantiate a toolbar manager.
2. Instantiate the menubar object in your mainframe constructor. If you are creating an SDI application, use SECMenuBar. If you are creating a MDI application, use SECMDIMenuBar.
m_pMenuBar is a member variable of the base class.
CMainFrame::CMainFrame() { m_pMenuBar = new SECMDIMenuBar; // or SECMenuBar for SDI }
3. Delete the menubar in the main frame destructor.
CMainFrame::~CMainFrame() { if(NULL != m_pMenuBar) { delete m_pMenuBar; m_pMenuBar = NULL; } }
4. In MainFrame::OnCreate(), create the menubar. It is created in a manner similar to the other controlbars. For example:
// SDI: if (!m_pMenuBar->CreateEx(CBRS_EX_COOLBORDERS | CBRS_EX_GRIPPER, this) || !m_pMenuBar->LoadMenu(IDR_MAINFRAME)) { TRACE0("Failed to create menubar\n"); return -1; }
Chapter 7 Menu Bars 125 // MDI, use SetMenuInfo instead of LoadMenu: if (!m_pMenuBar->CreateEx(CBRS_EX_COOLBORDERS | CBRS_EX_GRIPPER, this) || !m_pMenuBar->SetMenuInfo(2, IDR_MAINFRAME, IDR_MDI2TYPE)) { TRACE("Failed to create menubar\n"); return -1; }
5. Call EnableDocking() as you would a normal toolbar. This step assumes that you called EnableDocking(CBRS_ALIGN_ANY) on the frame window. For example:
// dock the menubar m_pMenuBar->EnableDocking(CBRS_ALIGN_ANY); DockControlBar(m_pMenuBar);
7.6.4 To remove the close button from a floating menu
As the last statement in the OnCreate() method of your main frame, use the SECMenuBar::ModifyStyle() method to remove the WS_SYSMENU style flag. For example:
m_pMenuBar->ModifyStyle(WS_SysMenu,NULL);
7.6.5 To switch between menus
SDI Implementation Method
1. In the OnCreate() method of the main frame, replace the standard call to SECMenuBar::LoadMenu() with a call to SECMenuBar::SetMenuInfo(). Make sure you define every menu resource you want to use. For example, the following code defines a menubar that uses two menu resources, IDR_MAINFRAME and IDR_MENU2:
if (!m_pMenuBar->CreateEx(CBRS_EX_COOLBORDERS | CBRS_EX_GRIPPER, this, WS_VISIBLE | WS_CHILD | CBRS_TOP, AFX_IDW_CONTROLBAR_LAST) || !m_pMenuBar->SetMenuInfo(2, IDR_MAINFRAME, IDR_MENU2)) { TRACE0("Failed to create menubar\n"); return -1; }
2. In the OnCreate() method of the main frame, call the SECMenuBar::SwitchMenu() func- tion to activate the correct initial menu directly after the calls to DockControlBar(). For example, the following code activates the IDR_MAINFRAME menu:
m_pMenuBar->SwitchMenu(IDR_MAINFRAME);
3. To toggle the menu at run time, call the SECFrameWnd::SwapMenu() method. For example, the following code activates the menu IDR_MENU2:
SwapMenu(IDR_MENU2);
126 MDI Implementation Method
1. In the OnCreate() method of the main frame, ensure that the call to SECMenuBar::SetMenuInfo() defines all the menus that the application can use. For exam- ple, the following code defines that the menubar uses four menu resources— IDR_MAINFRAME, IDR_MAINFRAME_MENU2, IDR_MDITYPE and IDR_MDITYPE_MENU2.
if (!m_pMenuBar->CreateEx(CBRS_EX_COOLBORDERS | CBRS_EX_GRIPPER, this, WS_VISIBLE | WS_CHILD | CBRS_TOP, AFX_IDW_CONTROLBAR_LAST) || !m_pMenuBar->SetMenuInfo(4, IDR_MAINFRAME, IDR_MAINFRAME_MENU2, IDR_MDITYPE, IDR_MDITYPE_MENU2)) { TRACE0("Failed to create menubar\n"); return -1; }
2. Directly after this, add a call to SECMDIFrameWnd::LoadAdditionalMenus(). This method informs the menubar about menu resources that are not loaded by the document templates or the frame window’s menu. For example, the following code loads the IDR_MAINFRAME_MENU2 and IDR_MDITYPE_MENU2 menus by default. The menu IDR_MDITYPE is loaded automatically by the document template, and IDR_MAINFRAME is loaded automatically by the frame window so they are not defined here.
if(!LoadAdditionalMenus(2,IDR_MAINFRAME_MENU2, IDR_MDITYPE_MENU2)) { TRACE0("Failed to load additional menus\n"); }
To toggle the menus of the frame window or MDI child windows, call the SECMDIFrameWnd::SwapMenu() and SECMDIChildWnd::SwapMenu() methods. For exam- ple, the following activates the menu IDR_MDITYPE_MENU2.
SwapMenu(IDR_MDITYPE_MENU2);
7.6.6 To use bitmap menus without the cool-look toolbars
1. Replace your mainframe base class with SECFrameWnd for SDI or SECMDIFrameWnd for MDI. If applicable, change your childframe base class to SECMDIChildWnd.
2. In your mainframe constructor, call EnableBmpMenus().
CMainFrame::CMainFrame() { EnableBmpMenus(); }
3. Configure an appropriate toolbar bitmap resource to supply the bitmap resources in your CMainFrame::OnCreate().
Chapter 7 Menu Bars 127 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (SECMDIFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; // All other init... // Use the IDR_MAINFRAME toolbar resource for the // bitmap menus AddBmpMenuToolBarResource(IDR_MAINFRAME); }
For more information, see Section 7.6.7, “To use bitmap menus in context menus.”
7.6.7 To use bitmap menus in context menus
With Main Frame Message Processing
By default, bitmaps are not displayed in context popup menus because the bitmaps are added to the menus via a plug-in on the mainframe. If the WM_INITMENUPOPUP is handled by the view, there is no opportunity to add the bitmaps.
To circumvent this, parent the menu to the mainframe. This allows the bitmap menu plug-in to pro- cess the WM_INITMENUPOPUP the same way it processes the menus from the menubar, which makes adding bitmap support much simpler. For example:
void CMyView::OnRButtonDown(UINT nFlags, CPoint point) { CMenu menuText;
// Load the menu menuText.LoadMenu(IDR_MAINFRAME);
// Pick the popup you wish to use. You may add and // delete menu items at this point. CMenu* pMenuPopup = menuText.GetSubMenu(0);
// This puts the menu at the right spot on the screen. ClientToScreen(&point);
// Notice that this is parented to the mainframe. The // TMP_XXX style could be any of the valid ones. pMenuPopup->TrackPopupMenu( TPM_RIGHTALIGN , point.x, point.y, AfxGetMainWnd()); }
Without Main Frame Message Processing
Unfortunately, this has the effect of routing all context message commands directly to the main- frame. If you want to re-parent the context menu as a child of the view so you can route the commands to the parent view instead, complete the following steps.
1. Declare a pointer to an SECBmpMenuPlugIn object in your view header.
protected: SECBmpMenuPlugIn* m_pBmpMenuPlugin;
2. Initialize this pointer to NULL in your class constructor.
128 3. In your CView::OnInitialUpdate(), initialize the bitmap menu plugin, defining the tool- bar resource from which to load the bitmap images.
CMyView::OnInitialUpdate() { // Initialize the bitmap menu plugin m_pBmpMenuPlugin=new SECBmpMenuPlugIn; m_pBmpMenuPlugin->PlugInTo(this); m_pBmpMenuPlugin->AddToolBarResource(IDR_MAINFRAME); }
4. Override WindowProc() and then add the following code to forward events to the plugin.
LRESULT CMyView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // Plug the bitmap menu plugin into this window's WNDPROC if(m_pBmpMenuPlugin) { if(message==WM_INITMENUPOPUP) m_pBmpMenuPlugin->InitMenuPopup(wParam,lParam); else { LRESULT result = 0; m_pBmpMenuPlugin->OnWndMsg( message, wParam, lParam, &result ); if( m_pBmpMenuPlugin->m_bExitMessage ) return result; } } return CView::WindowProc(message, wParam, lParam); }
5. Delete the m_pBmpMenuPlugin object in your view destructor with the following code:
if(m_pBmpMenuPlugin) delete m_pBmpMenuPlugin;
Chapter 7 Menu Bars 129 7.7 MenuBar Sample
The viz sample project (in the samples\toolkit\MFC\docking\viz subdirectory) uses the new menubar classes. You can use the button map that is used in customizable toolbars to denote combo boxes, two-part buttons, and custom buttons to dynamically swap menus based on the cur- rently active view.
130 Chapter 8 Docking Windows
8.1 Overview
The Objective Toolkit docking windows architecture is a set of MFC extensions that gives your application the same docking windows features available in the Visual Studio IDE.
Docking windows can dock to the application’s main frame and float in a frame outside the appli- cation frame. In addition, you can make docking windows in MDI applications float as MDI children.
Depending on the docking location, docked windows can be resized in one or two dimensions. When they are floating, docking windows can be resized in both dimensions. During the process of docking, limited geometry management is available.
The Objective Toolkit docking windows architecture extends and enhances MFC’s docking control bar architecture without altering it. There are relatively few interface changes so your knowledge of MFC’s CControlBar, CDialogBar, and other classes still applies. You can add Objective Toolkit docking window features to any application, whether it is SDI, MDI, MTI, or FDI-based.
Objective Toolkit also supports embedding of Objective Toolkit’s enhanced docking windows inside an OLE IP Server. This addition allows you to use our cool look control bars and toolbars in an embeddable OLE Inplace Server so you can activate them using any OLE Container, such as Micro- soft Excel.
Menu bars and Docking Views are not supported in this configuration (inside an IP Server).
Chapter 8 Docking Windows 131 8.2 Features of Docking Windows
The Objective Toolkit docking windows architecture adds a host of features to the existing MFC control bar architecture. When docked, you can resize dockable windows using splitter bars that are along the window’s edge. The following figure shows how docking windows appear when docked. Figure 80 – Example of Objective Toolkit Docking Windows (docked)
You can float docking windows in their own frames, outside the frame of the application.
132 Figure 81 – Example of Objective Toolkit Docking Windows (floating)
Another significant feature added by the extended control bar architecture is the ability to float a control bar as an MDI child window and then turn it back into a docking control bar. When it is floating, a dockable window can be resized horizontally, vertically, and diagonally.
When it is floating as an MDI child, the docking window is clipped to the MDI application frame. Docking windows floating outside of the main frame are not constrained.
Each dockable window stretches automatically when resized. You can implement your own, alter- nate form of resize handling. In addition, each dockable window has a default context menu that you can access by right-clicking. The default context menu contains Hide and Allow Docking menu items by default. You can add or remove menu items from the context menu.
Chapter 8 Docking Windows 133 8.3 Flat-Style Drawing
To enable the flat drawing style, you will need to set the CBRS_EX_FLATSTYLE extended style while creating a docking window. Alternatively, you can set the flat drawing style later by calling SetExBarStyle (a member of the SECControlBar class).
Text inside a gripper window is taken from the window caption which can be set during the cre- ation of a window, or later in the program by calling the SetWindowText function (a member of the CWnd class). Figure 82 – Flat-Style Horizontal Gripper with Close and Expand Buttons Enabled
Figure 83 – Flat-Style Vertical Gripper with Close and Expand Buttons Enabled
To view sample code which shows how to enable the flat-style mode of docking windows during creation time, please see the CMainFrame::OnCreate function implementation in MAINFRM.cpp, VIZ sample.
m_wndProjectWorkspace.Create(this, _T("Project Workspace"), CBRS_RIGHT | WS_VISIBLE | CBRS_SIZE_DYNAMIC, CBRS_EX_STDCONTEXTMENU | CBRS_EX_ALLOW_MDI_FLOAT | CBRS_EX_COOL | CBRS_EX_BORDERSPACE | CBRS_EX_FLATSTYLE, ID_PROJECTWORKSPACE);
The VIZ sample demonstrates this feature and can be found in the Samples\Toolkit\MFC\Docking directory.
134 8.4 Auto-Hide Docking Windows
Auto-hide docking windows are similar to the pinnable windows in Visual Studio. They are an extension to the Docking Windows architecture that deals specifically with the SECControlBar class. With this new feature, you can unpin a control bar, essentially hiding it while still keeping it docked to the corresponding dockbar. To unpin a control bar, simply click the pin button.
When a control bar is unpinned, a new control bar (the SECAutoHideBar) is displayed adjacent to the corresponding dockbar region (i.e., top, bottom, left, right). It will display a tab along that dock- bar region for the newly hidden docking window. When the mouse is over the tabs of the auto-hide bar, the corresponding docking window is displayed in floating mode next to the auto hide bar. These floating windows can be repinned by clicking the pin button. This will, in turn, redock the docking window control bar in the position it was in previous to unpinning.
SECControlBars can be placed in the top dockbar region, but the top docking region is not limited to toolbars and menubars. To preserve the state of any existing SECControlBars that may be docked to the top, the auto-hide bar is docked to the very bottom of the top dockbar region. The auto-hide bar will be the last bar in the last row of control bars.
This means that any SECControlBars you dock to the top dockbar region will be displayed above the Auto Hide Bar. In order to keep the behavior of the auto -hide windows consistent, we do not recommend top docking auto-hide windows, even though it’s possible to do so.
If you must dock to the top and want to specify, for example, that certain derived objects cannot dock above toolbars and menubars, consider overriding OnLButtonUp() and specifying where the control bar should be docked. For more information, see the description of the SECMDIFrameWnd::DockControlBarEx() function in the Objective Toolkit Class Reference Guide.
Auto Hide is used with the existing SECFrameWnd and SECMDIFrameWnd classes.
8.4.1 Features
Auto Hide features include vertical frame docking, auto hide pins, vertical/horizontal text, float- ing grippers, auto-hide icons, and active windows.
8.4.1.1 Vertical Frame Docking
You can control the order of docking, allowing control bars to take up the full frame vertically. By default, docking order priority is Top, Bottom, Left, Right, with Top and Bottom docking taking priority across the frame.
You can specify the order of docking alignment by calling EnableDocking() from the frame class with all four alignment flags called separately. Calling EnableDocking with CBRS_ALIGN_ANY gives the default docking order. CBRS_ALIGN_ANY is called only once. If you specify the docking order, EnableDocking() is called exactly four times, as follows:
CMainFrame::OnCreate() { //Let’s specify the docking order. EnableDocking(CBRS_ALIGN_TOP);
Chapter 8 Docking Windows 135 EnableDocking(CBRS_ALIGN_LEFT); EnableDocking(CBRS_ALIGN_RIGHT); EnableDocking(CBRS_ALIGN_BOTTOM); ... }
8.4.1.2 Auto-Hide Pins
Auto-hide pins are displayed in the gripper bar of control bar windows that can be docked. Vertical pins represent a docked state.
8.4.1.3 Vertical/Horizontal Text
Text draws horizontally as well as vertically, depending on how the hidden control bar was previ- ously docked.
8.4.1.4 Floating Grippers
Floating, or unpinned, auto-hide windows display the gripper horizontally across the top. The auto-hide pin is displayed on its side to represent an unpinned, or hidden, state. Since auto-hide docking windows need a gripper, set the following style flags:
CBRS_EX_COOL CBRS_EX_BORDERSPACE CBRS_EX_FLATSTYLE
8.4.1.5 Icons
Assigning an icon to a control bar that has auto-hide properties is optional but recommended. Hid- den control bars that do not have an icon associated with them, such as the Output Window, display full text in the Auto Hide Bar. To set an icon to an auto-hide docking window, use the MFC function SetIcon(). You’ll need to pass as a parameter the handle to an icon that has already been loaded, such as via LoadIcon(). The following is an example:
HICON hndlYourIcon = AfxGetApp()->LoadIcon(IDI_ICON1); m_wndYourAutoHideCtrlBar.SetIcon(hndlYourIcon, FALSE);
8.4.1.6 Active Windows
Active displayed windows that are unpinned expand to text in the Auto Hide Bar. Inactive win- dows are displayed as icons. Hidden windows that are the only bar attached to an Auto Hide Bar, or that don’t have an icon associated with them, are always displayed as full text.
The delay of the active auto-hide window’s disappearance is set with SECControlBar’s SetAutoHideDelay() with a DWORD value in milliseconds. By default, it is set to 10 milliseconds.
136 8.4.2 Creating Auto-Hide Docking Windows
Your frame class should be derived from SECFrameWnd if you want SDI capability or from SECM- DIFrameWnd is you want MDI capability. Auto-hide docking windows are SECControlBar- derived classes, with the SetAutoHide (TRUE) function called. By default, SECControlBar classes do not have Auto Hide enabled. As noted in Section 8.4.1.4, “Floating Grippers,” creation of the control bar should contain the CBRS_EX_COOL, CBRS_EX_BORDERSPACE, and CBRS_EX_FLATSTYLE style flags.
Following is an example showing how to turn a SECControlBar class into an Auto Hide enabled docking window:
//Project Workspace Window if (!m_wndProjectWorkspace.Create(this,_T(“Project Workspace”), CBRS_RIGHT | WS_VISIBLE | CBRS_SIZE_DYNAMIC, CBRS_EX_STDCONTEXTMENU | CBRS_EX_ALLOW_MDI_FLOAT | CBRS_EX_COOL | CBRS_EX_BORDERSPACE | CBRS_EX_FLATSTYLE, ID_PROJECTWORKSPACE)) { TRACE(_T(“Failed to create dialog bar\n”)); return -1; } m_wndProjectWorkspace.EnableDocking(CBRS_ALIGN_ANY); DockControlBarEx(&m_wndProjectWorkspace, AFX_IDW_DOCKBAR_RIGHT, 0, 0 (float)1.00, 220); HICON hicPW = AfxGetApp()->LoadIcon(IDI_ICON1); m_wndProjectWorkspace.SetIcon(hicPW, FALSE); m_wndProjectWorkspace.SetAutoHide(TRUE);
To see the complete implementation of auto-hide docking windows, see the Viz sample located at
Chapter 8 Docking Windows 137 8.5 The Docking Window Classes
The extended control bar classes are divided into two categories: control bar derivatives and frame window derivatives. For each MFC control bar and frame window class, there is a corresponding Objective Toolkit class with a name prefixed by SEC. To use our enhanced docking window fea- tures, you must migrate from the MFC control bar and frame window classes to Objective Toolkit’s replacements. Figure 84 – Objective Toolkit Extended Control Bar Class Hierarchy
CControlBar CFrameWnd CObject
SECControlBar SECFrameWnd CCmdTarget
SECDialogBar CMDIChildWnd SECControlBarManager
SECToolBar SECMDIChildWnd CDockState
SECStatusBar CMDIFrameWnd SECDockState
SECCustomToolbar SECMDIFrameWnd
138 8.6 Docking Window Frame Classes
The following sections describe the Objective Toolkit frame classes.
To use the Objective Toolkit docking windows architecture, you must use the Objective Toolkit frame class.
8.6.1 SECFrameWnd
The SECFrameWnd class derives from CFrameWnd and adds the implementation details support- ing the docking window features. This class supports the SECControlBar class by adding members for an SECControlBar manager and the SECDockBars. It also adds improved serialization support for extension information.
8.6.2 SECMDIFrameWnd
The SECMDIFrameWnd class derives from CMDIFrameWnd and adds the implementation details supporting the docking window features. This class supports the SECControlBar class by adding members for an SECControlBar manager and the SECDockBars. It also adds improved serializa- tion support for extension information.
8.6.3 SECMDIChildWnd
The SECMDIChildWnd class derives from CMDIChildWnd and adds the implementation details that support the docking window features. This class supports the SECControlBar class. It is com- patible with the improved serialization support.
Chapter 8 Docking Windows 139 8.7 Docking Window Control Bar Classes
The following sections describe the Objective Toolkit Control bar classes.
8.7.1 SECControlBar
The SECControlBar class derives from CControlBar and adds the internal state and implementa- tion details supporting sizing when docked. It also adds a gripper bar as a private class, a gripper close button, a gripper expand button, and methods for context menu manipulation. Virtual meth- ods are provided for advanced users to manipulate docking and other features.
8.7.2 SECDialogBar
SECDialogBar is an interface equivalent replacement for CDialogBar. SECDialogBar serves as the base class for all of your dialog bars.
SECDialogBar does nothing more than re-derive from SECControlBar, so that all member vari- ables and implementation details exist to facilitate sizing docked windows and more. This class introduces no new member variables or functions.
All dialog bars formerly derived from CDialogBar must be rederived from SECDialogBar. You cannot use CDialog- Bars with Objective Toolkit’s docking window enhancements because they lack the member variables required to perform the sizing calculations.
See the viz sample in the samples\toolkit\MFC\docking\viz subdirectory for an example of how to use this class.
8.7.3 SECControlBarManager
The SECControlBarManager class manages control bars as well as the state of an application’s main frame. It supports dynamic save and restore of control bars. This class derives from CCmdTarget.
8.7.4 SECDockState
TheSECDockState class derives from CDockState and adds the additional states introduced by SECControlBarInfo. The docking states are stored in member variables that are not recorded by CDockState. SECDockState inherits the core docking state from CDockState and adds all the new attributes required for enhanced docking window functionality.
If your application uses our docking window architecture, you must replace all occurrences of CDockState with SECDockState.
140 8.8 Message Routing Issues
MFC routes command messages to the frame window, view, document, doc template, and the CWinApp instead of a control bar. Controls are not included in MFC's default message routing. If you are working strictly with MFC and CControlBar, the client of a CControlBar is not visited in the default routing of messages either.
When you apply focus to a control bar, command messages are still routed to the active MDI child (or SDI frame). This is not unique to Objective Toolkit; using CControlBar yields the same result.
For more information, see Section 8.11.21, “To route messages to the client area of SECControlBar.”
Chapter 8 Docking Windows 141 8.9 Extended ControlBar Styles
The SECControlBar class introduces extended control bar styles. Set these extended control bar style bits via the m_dwExStyle class variable of the SECControlBar::Create() method. Here is an overview of the extended control bar styles that can be set for any class derived from SECControlBar.
Table 27 – Extended Control Bar Styles
Extended Style Flag Description
CBRS_EX_STDCONTEXTMENU When the extended control bar style is set, the control bar is automatically given the standard context menu items (for example, Show/Hide and Allow Docking).
CBRS_EX_STRETCH_ON_SIZE The control bar is automatically stretched when resized so that all child windows of the control bar are proportionally scaled to fit the new size exactly. If you require a custom form of resize handling, do not set this extended style and override SECControlBar::OnSize().
CBRS_EX_DRAWBORDERS Draw a border around the bar.
CBRS_EX_BORDERSPACE Leave border space for ease of dragging. This style causes a very wide border around the cli- ent area of the window while floating.
CBRS_EX_ALLOW_MDI_FLOAT Control bar can be re-parented by an MDI child window. Set this style if you want the control bar to have a context menu item that allows the control bar to be floated as a normal MDI child window. This style can only be used in MDI applications.
CBRS_EX_SIZE_TO_FIT Size the (single) child to fit.
CBRS_EX_UNIDIRECTIONAL The control bar can be sized horizontally or vertically but not diagonally (for example, a tool- bar). The control bar can be sized in only one direction per sizing operation.
CBRS_EX_COOLBORDERS Floating buttons, no border. This style only applies to toolbars.
CBRS_EX_GRIPPER Draw the dragging gripper.
CBRS_EX_GRIPPER_CLOSE Draw the close button on gripper.
CBRS_EX_GRIPPER_EXPAND Expand/contract control bar button.
142 Table 27 – Extended Control Bar Styles (Continued)
Extended Style Flag Description
CBRS_EX_COOL CBRS_EX_COOLBORDERS | CBRS_EX_GRIPPER | CBRS_EX_GRIPPER_CLOSE | CBRS_EX_GRIPPER_EXPAND Gives the control bar the cool look – a flat, painted look similar to the control bars seen in Microsoft Visual Studio. These extended style options allow you to cus- tomize the cool look for your application. By default, the customizable toolbars are: CBRS_EX_COOLBORDERS | CBRS_EX_GRIPPER; all other control bars are CBRS_EX_COOL. Note: Gripper requires cool- borders, and Close requires Gripper. In addition, the gripper drawing code has been made virtual, so you can easily plug in your own gripper or modify the existing gripper with just one or two overrides.
CBRS_EX_FULL_ROW Control bar always occupies entire row (menubars).
CBRS_EX_TRANSPARENT Toolbar buttons drawn transparently.
CBRS_EX_MENU_STYLE Do not become large unless a large object is dropped on bar.
The extended control bar styles are distinct from the window styles to avoid value collisions.
Chapter 8 Docking Windows 143 8.10 Embedding CViews in Docking Windows
Classes derived from CView pose special challenges when docking is concerned. To circumvent these challenges, the Objective Toolkit docking windows architecture only allows you to embed a class inside an SECControlBar if it is a CWnd that is not CView-derived. This is an MFC limitation inherited from the CControlBar class (for example, you cannot embed a CView inside a CControlBar).
144 8.11 Using the Docking Window Architecture
The following topics describe how to use docking windows classes and handle special situations.
8.11.1 To create an application with Objective Toolkit docking windows
Use the Objective Toolkit AppWizard to create a project.
8.11.2 To incorporate Objective Toolkit docking windows into an existing MDI application
1. Integrate the library into your application. For more information, see Section 2.3.10, “To incorporate Objective Toolkit into your application.”
2. From the View menu in Visual Studio, click Resource Includes… Ensure that the _AFX_NO_SPLITTER_RESOURCES is either absent or commented out.
// #define _AFX_NO_SPLITTER_RESOURCES
3. Replace the base class of your CMainFrame class. Replace CMDIFrameWnd with SECMDIFrameWnd. The MDI parent frame acquires the functionality it needs to host its resizable SECControlBar children.
4. Replace the base class of all existing MDI child frames (CMDIChildWnd) with SECMDIChildWnd.
5. Replace the base class of all windows derived from CControlBar with SECControlBar.
6. Replace the base class of all windows derived from CDialogBar with SECDialogBar.
7. Replace the base class of all toolbars derived from CToolBar or SECToolBar with SECCustomToolBar.
8. Replace the base class of the status bar derived from CStatusBar with SECStatusBar.
You need to re-derive any status bar derived from CStatusBar from SECStatusBar. You cannot use CStatusBars with our docking window enhancements because they do not have the member variables the class expects.
9. Replace the base class of all windows derived from CDockContext with SECDockContext.
10. Modify the OnCreate() member of your CMainFrame class so that all calls to CControlBar::Create(), CDialogBar::Create(), or CToolBar::Create() reflect the change in prototypes introduced by the re-derivations in the previous steps. In particular, the CControlBar::Create() member adds an additional parameter (dwExStyle) for pass- ing extended style bits. For example, CBRS_EX_STRETCH_ON_SIZE is an extended style bit that you can set in your call to SECDialogBar::Create().
Chapter 8 Docking Windows 145 8.11.3 To incorporate Objective Toolkit docking windows into an existing SDI application
1. Integrate the library into your application. For more information, see Section 2.3.10, “To incorporate Objective Toolkit into your application.”
2. From the View menu in Visual Studio, click Resource Includes… Ensure that the AFX_NO_SPLITTER_RESOURCES is either absent or commented out.
// #define _AFX_NO_SPLITTER_RESOURCES
3. Replace the base class of your CMainFrame class. Replace CFrameWnd with SECFrameWnd.
4. Replace the base class of all windows derived from CControlBar with SECControlBar.
5. Replace the base class of all windows derived from CDialogBar with SECDialogBar.
6. Replace the base class of all toolbars derived from CToolBar with SECToolBar.
7. Replace the base class of the status bar from CStatusBar with SECStatusBar.
8. Modify the OnCreate() member of your CMainFrame class so that all calls to CControlBar::Create(), CDialogBar::Create(), or CToolBar::Create() reflect the change in prototypes introduced by the re-derivations in the previous steps. In particular, the CControlBar::Create() member adds an additional parameter (dwExStyle) for pass- ing extended style bits. For example, CBRS_EX_STRETCH_ON_SIZE is an extended style bit that you can set in your call to SECDialogBar::Create().
8.11.4 To use Objective Toolkit docking windows inside an OLE IP server
1. Use AppWizard to generate a full server or check ActiveX document server support.
2. Integrate the library into your application. For more information, see Section 2.3.10, “To incorporate Objective Toolkit into your application.”
3. Replace the base class of the server document class (COleServerDoc) with SECOleServerDoc. Replace each base class invocation in the source file when it is appropriate.
4. Replace the base class of your OLE Server Item (COleServerItem) with SECOleServerItem.
If you selected ActiveX document server support when you were generating the applica- tion using AppWizard, replace CDocObjectServerItem with SECDocObjectServerItem instead. This provides you with CDocIPFrameWnd support.
5. Use the OnCreateControlBars() method of your COleIPFrameWnd derived class to create your controlbars.
You must cast the pWndFrame pointer from CFrameWnd to SECFrameWnd. This ensures that the proper SEC non-virtual method overrides are called— most notably, EnableDocking().
Each controlbar must set the inplace frame object as its owner, but it should be created with the pWndFrame pointer as the parent.
146 Refer to the following sample code for more information. In addition, please try secoleip in the samples\toolkit\MFC\docking\secoleip subdirectory. You need to run this sam- ple once to register your server. Open an OLE container like Excel, select Insert Object and then select SecOle document. Embedded Objective Toolkit docking windows and toolbars appear as well as the toolbar customization dialog. Again, Objective Toolkit MenuBars and Docking Views are not supported inside an IP Server.
BOOL CInPlaceFrame::OnCreateControlBars(CFrameWnd* pWndFrame, CFrameWnd* pWndDoc) { // Remove this if you use pWndDoc UNREFERENCED_PARAMETER(pWndDoc);
// Must cast the pWndFrame to an SECFrameWnd to insure the // proper "SEC" nonvirtual overrides are called. This // operation should be type safe if all the docking windows // enablement steps were properly followed (please refer to // the user's guide). ASSERT_KINDOF(SECFrameWnd,pWndFrame); SECFrameWnd* pSecWndFrame=(SECFrameWnd *)pWndFrame; m_pDockingFrameWnd=pSecWndFrame; // save ptr for OnClose //handler
// A toolbar manager is needed to provide toolbar // customization support. In normal Objective Toolkit docking windows, // we can simply instantiate the m_pControlBarMgr member of // SECFrameWnd/SECMDIFrameWnd. Since this is an // COleIPFrameWnd object, though, we must manually track // this ptr and clean up as needed. // Note 2: all controlbars must have pWndFrame as a parent, // but this COleIPFrameWnd as the owner for proper command // routing. // Use the second toolbar mgr constructor overload to provide // this necessary linkage. SECToolBarManager* pToolBarMgr= new SECToolBarManager(pSecWndFrame,this); m_pToolBarMgr=pToolBarMgr; // save for memory cleanup pSecWndFrame->SetControlBarManager(pToolBarMgr);
// Configure the customizable toolbars VERIFY(pToolBarMgr->LoadToolBarResource( MAKEINTRESOURCE(IDR_SECOLETYPE_SRVR_IP), MAKEINTRESOURCE(IDR_SECOLETYPE_SRVR_IP_LG))); pToolBarMgr->SetButtonMap(btnMap); pToolBarMgr->DefineDefaultToolBar(AFX_IDW_TOOLBAR,_T("File"), NUMELEMENTS(fileButtons),fileButtons, CBRS_ALIGN_ANY,AFX_IDW_DOCKBAR_TOP); pToolBarMgr->DefineDefaultToolBar(AFX_IDW_TOOLBAR + 5, _T("Edit"),NUMELEMENTS(editButtons), editButtons,CBRS_ALIGN_ANY, AFX_IDW_DOCKBAR_TOP,AFX_IDW_TOOLBAR); pToolBarMgr->DefineDefaultToolBar( AFX_IDW_TOOLBAR + 6, _T("Debug"), NUMELEMENTS(debugButtons), debugButtons, CBRS_ALIGN_ANY, AFX_IDW_DOCKBAR_TOP, AFX_IDW_TOOLBAR);
Chapter 8 Docking Windows 147 pToolBarMgr->EnableCoolLook(TRUE);
pSecWndFrame->EnableDocking(CBRS_ALIGN_ANY);
// Output Window m_wndOutput.SetOwner(this); // mandatory! if (!m_wndOutput.Create(pSecWndFrame, _T("Output Window"), CBRS_BOTTOM|WS_VISIBLE | CBRS_SIZE_DYNAMIC|CBRS_TOOLTIPS, CBRS_EX_STDCONTEXTMENU|CBRS_EX_ALLOW_MDI_FLOAT | CBRS_EX_COOL|CBRS_EX_BORDERSPACE, ID_OUTPUTWINDOW)) { TRACE(_T("Failed to create dialog bar\n")); return -1; } m_wndOutput.EnableDocking(CBRS_ALIGN_ANY); pSecWndFrame->DockControlBarEx(&m_wndOutput, AFX_IDW_DOCKBAR_BOTTOM, 0, 0, (float)0.75, 130); // Project Workspace Window // mandatory! m_wndProjectWorkspace.SetOwner(this); if (!m_wndProjectWorkspace.Create(pSecWndFrame, _T("Project Workspace"), CBRS_RIGHT | WS_VISIBLE | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS, CBRS_EX_STDCONTEXTMENU | CBRS_EX_ALLOW_MDI_FLOAT | CBRS_EX_COOL | CBRS_EX_BORDERSPACE, ID_PROJECTWORKSPACE)) { TRACE(_T("Failed to create dialog bar\n")); return -1; } m_wndProjectWorkspace.EnableDocking(CBRS_ALIGN_ANY); pSecWndFrame-> DockControlBarEx(&m_wndProjectWorkspace, AFX_IDW_DOCKBAR_RIGHT, 0, 0, (float)1.00, 180); // Load default toolbar state pSecWndFrame->LoadBarState(_T("SecOleIPBarState")); pToolBarMgr->LoadState(_T("SecOleIPBarState")); return TRUE; }
8.11.5 To create a docking window based on a dialog resource
1. Create a dialog resource for the docking window using the resource editor in Visual Studio.
2. Create an SECDialogBar-derived class to manage the client area of the docking window.
148 3. Instantiate an object of the SECDialogBar-derived class as a member of the frame in which the docking window is included (either SECFrameWnd or SECMDIFrameWnd).
4. In the frame window’s OnCreate() method, call the Create() method of the instantiated control bar to initialize it and then pass the resource ID of the dialog resource.
8.11.6 To create a docking window not based on a dialog resource
1. Ensure your frame class is either SECFrameWnd or SECMDIFrameWnd-derived.
2. Create an SECControlBar-derived class to manage the client area of the docking window.
3. As a data member of your frame class, instantiate the SECControlBar-derived object.
4. In the frame window’s OnCreate() method, call the Create() method of the instantiated control bar to initialize it.
8.11.7 To set the style of a docking window
1. Specify the CBRS_ styles either in the Create() call for the SECControlBar-derived class or call the CControlBar::SetBarStyle() method.
See the Objective Toolkit Class Reference for more information on the CControlBar::SetBarStyle() method and descriptions of these styles.
2. Specify the CBRS_EX_ style extensions in the Create() call for the SECControlBar-derived class.
See Section 8.9, “Extended ControlBar Styles,”for a list and a description of the extended docking windows styles.
The SECControlBar::SetExBarStyle() method will set the extended bar style.
8.11.8 To make a docking window dockable
Call SECControlBar::EnableDocking(), SECMDIFrameWnd::EnableDocking(), and SECMDIFrameWnd::DockControlBarEx().
This also applies to SECFrameWnd.
For example:
CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) {
... EnableDocking(CBRS_ALIGN_ANY);
Chapter 8 Docking Windows 149 // Create the control bar if (!m_wndControlBar.Create(this, _T("Control Bar 1"), CBRS_BOTTOM | WS_VISIBLE | CBRS_SIZE_DYNAMIC, CBRS_EX_COOL, ID_OUTPUTWINDOW)) {
TRACE(_T("Failed to create control bar\n")); return -1; }
m_wndControlBar.EnableDocking(CBRS_ALIGN_ANY); DockControlBarEx(&m_wndControlBar, AFX_IDW_DOCKBAR_BOTTOM, 0, 0, (float)0.75, 130); ... }
8.11.9 To create a non-dockable control bar
1. Notice the following lines in the OnCreate() method of your frame class. The following VC++ AppWizard generated comment is incorrect:
// TODO: Delete these three lines if you do not // want the toolbar to be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar);
If you follow the directions and delete these three lines, a pseudo-docked toolbar that draws incorrectly appears. This occurs whether or not you are using Objective Toolkit. This comment is incorrect. You still need to call EnableDocking(), but you also need to pass a value of zero to create the CDockContext().
2. Instead of deleting the lines, call SECControlBar::EnableDocking() with a parameter of zero. For example:
m_wndToolBar.EnableDocking(0);
3. Call either ToggleDocking() or FloatControlBar() on the control bar. ToggleDocking() automatically computes an initial point for you.
//m_wndToolBar.m_pDockContext->ToggleDocking(); FloatControlBar(&m_wndToolBar, CPoint(50,50));
8.11.10To dock a docking window that is floating
Call the DockControlBar() or DockControlBarEx() methods from your frame window class. These methods dock a control bar that is either floating or docked to another dock bar. The DockControlBarEx() method gives you more control over how and where the control bar is docked.
150 8.11.11To float a docking window that is docked
Call the FloatControlBar() method, which is a member of SECFrameWnd/SECMDIFrameWnd. This method removes a bar from its dockbar and floats it. It can also move a floating bar to a new location.
8.11.12To make an SECDialogBar size diagonally when floated
Conditionally typecast pFrameWnd to SECMDIFrameWnd or SECFrameWnd so that the FloatControlBar() method in SECMDIFrameWnd is called instead of CFrameWnd. For example: if (pFrameWnd-> IsKindOf(RUNTIME_CLASS(SECMDIFrameWnd))) ((SECMDIFrameWnd*)pFrameWnd->FloatControlBar(. . .); else if (pFrameWnd-> IsKindOf(RUNTIME_CLASS(SECFrameWnd))) ((SECFrameWnd*)pFrameWnd-> FloatControlBar(. . .); else pFrameWnd->FloatControlBar(. . .);
8.11.13To receive notifications when the docked state of a docking window changes
1. Create an SECControlBar-derived class.
2. Override the following callback methods.
Callback method Description
OnBarBeginDock() Called before a bar is docked. The default imple- mentation calls OnBarDock().
OnBarDock() Called before a bar is docked. The default imple- mentation does nothing.
OnBarEndDock() Called after a bar is docked. The default imple- mentation does nothing.
OnBarBeginFloat() Called before a bar is floated. The default imple- mentation calls OnBarFloat().
OnBarFloat() Called before a bar is floated. The default imple- mentation does nothing.
OnBarEndFloat() Called after a bar is floated. The default implemen- tation does nothing.
OnBarBeginMDIFloat() Called before a bar is docked as an MDI child. The default implementation calls OnBarMDIFloat().
Chapter 8 Docking Windows 151 Callback method Description
OnBarMDIFloat() Called before a bar is floated as an MDI child. The default implementation does nothing.
OnBarEndMDIFloat() Called after a bar is floated as an MDI child. The default implementation does nothing.
8.11.14To hide a docking window
Use ShowControlBar(), which is a member of SECFrameWnd/SECMDIFrameWnd. Calling ShowWindow() has no effect on the control bar.
8.11.15To control the docking location of a docking window
Call the SECControlBar::EnableDocking() method. This method controls the ability to dock the window as well as where the window can be docked on its parent window. Refer to the Objective Toolkit Class Reference for more information on this method and its parameters.
8.11.16To determine where a docking window is docked
1. Use either CFrameWnd::GetControlBar() or CDockBar::FindBar() to get a pointer to a control bar.
2. Refer to the dock bar ID map, which is defined in both SECFrameWnd and SECMDIFrameWnd.
const DWORD SECFrameWnd::dwSECDockBarMap[4][2] = { { AFX_IDW_DOCKBAR_TOP, CBRS_TOP }, { AFX_IDW_DOCKBAR_BOTTOM, CBRS_BOTTOM }, { AFX_IDW_DOCKBAR_LEFT, CBRS_LEFT }, { AFX_IDW_DOCKBAR_RIGHT, CBRS_RIGHT }, };
const DWORD SECMDIFrameWnd::dwSECDockBarMap[4][2] = { { AFX_IDW_DOCKBAR_TOP, CBRS_TOP }, { AFX_IDW_DOCKBAR_BOTTOM, CBRS_BOTTOM }, { AFX_IDW_DOCKBAR_LEFT, CBRS_LEFT }, { AFX_IDW_DOCKBAR_RIGHT, CBRS_RIGHT }, };
3. By using the information above, you can add a member to your mainframe that determines to which dockbar a particular control bar is docked.
UINT CMyMainFrame::GetControlBarDockSite(...) {
152 // In case we don't find a place holder, // find a bar with the correct alignment // and keep it in pPossibleBar.
CDockBar* pDockBar= NULL; for (int i = 0; i < 4; i++) { pDockBar = (CDockBar*) GetControlBar(dwSECDockBarMap[i][0]); if ((pDockBar->FindBar(pBarFind, -1) != -1) { bFound = TRUE; break; } }
if (bFound) { switch (dwSECDockBarMap[i]) { case AFX_IDW_DOCKBAR_TOP: return CBRS_TOP; } } }
8.11.17To determine the row and column of a docked window
Call the SECControlBar::GetBarSizePos() method. This method returns information about the control bar position. In addition, it can also return information about the dockbar position and size.
8.11.18To modify a control bar’s context menu
A context (shortcut) menu is a pop-up menu that appears when the user presses the right mouse button. The SECControlBar bar defines a standard context menu and a convention for extending or modifying it. By default, the control bar is given two context menu items (Hide and Allow Dock- ing). There are two techniques for extending the standard context menu.
If the menu item applies to all control bars of a given class, override the SECControlBar::OnExtendContextMenu() method in a derived class and extend the menu through the pMenu parameter.
To learn how to use this method of context menu extension, see the source file samples\toolkit\MFC\docking\viz\outbar.cpp and the OutputControlBar::OnExtendContextMenu() method.
If the menu item represents a capability that the main frame window enables, handle theWM_EXTENDCONTEXTMENU message in your CMainFrame class and extend the menu through the menu handle passed via LPARAM.
SECControlBar always sends this message to its parent frame window after constructing the default context menu.
Chapter 8 Docking Windows 153 For an example of this form of context menu extension, see the source file src\toolkit\mdi\swinmdi.cpp and the SECMDIFrameWnd::OnExtendContextMenu() method.
8.11.19To add a toolbar to a control bar
1. Override SECDialogBar::OnCreate() and create the toolbar as a child of the dialog bar.
2. Override SECDialogBar::OnSize() and layout the toolbar and dialog template so they do not overlap.
8.11.20To access controls in the docking window inside a message handler
Use the following code in your message handler:
const MSG* pMsg = CWnd::GetCurrentMessage();
HWND hWnd = HWND(pMsg->lParam); ASSERT(::IsWindow(hWnd));
CComboBox* pCombo = STATIC_DOWNCAST( CComboBox, CWnd::FromHandle(hWnd) );
8.11.21To route messages to the client area of SECControlBar
Override OnCmdMsg() and check the focus window. If it is your control bar window, route the mes- sage to it. If not, let default handling occur.
We have solved this problem in our Docking Views.
154 8.12 Customizing Objective Toolkit Docking Windows
This section describes how you can modify the behavior of Objective Toolkit docking windows code.
8.12.1 Key Extended Control Bar Members
SECControlBar::m_bOptimizedRedrawEnabled. A static boolean variable that enables the redraw optimizations that eliminate extra redraws and flicker when set to TRUE. We have tested this to ensure no redraw problems exist when redraw optimizations are in effect. However, if your control bars are not being redrawn properly, set this member to false and see if the problems per- sist. If necessary, please contact Professional Services, as discussed in Section 1.4.3, “Professional Services”.
For more information, see Section 10.2.4.14, “Key WDI Methods and Data Members.” The same key members exist in the SECControlBar class as in SECWorkbookWnd/SECWorksheetWnd.
8.13 Docking Windows Sample
The Objective Toolkit viz sample in the samples\toolkit\MFC\docking\viz subdirectory illus- trates how to use docking windows in an MDI application.
Chapter 8 Docking Windows 155 156 Chapter 9 Image Classes
9.1 Overview
The Objective Toolkit image classes provide basic support for viewing the most popular graphic image types. With our image classes, you can create applications that read, display, write, convert, and manipulate images.
The image classes are viewer helpers. Although the image classes read and display the standard image formats (and some of their variations), we do not support the multitude of possible options for each format and the intricacies of converting from one to another. Some of the known restric- tions are listed in the following sections.
The Objective Toolkit image classes are contained in the Stingray Foundation Library. To avoid naming conflicts, these classes are wrapped in the stingray::foundation namespace. To use these classes you must either:
Add this namespace reference wherever these classes are used.
or
Map the entire namespace with:
using namespace stingray::foundation;
Exporting an entire namespace into your project is not a good way to maintain compartmental- ization; it can possibly cause naming conflicts.
If you include the component header files instead of secall.h, the namespace is exported to your project automatically. For example:
#include “Toolkit\ot_secdib.h”
The Stingray Studio Getting Started Guide discusses this topic in greater detail. Look for details about the image classes in the Foundation Class Reference instead of the Objective Toolkit Class Reference.
Chapter 9 Image Classes 157 Several other “Objective Toolkit” classes are also part of the Stingray Foundation Library— including color well con- trols and certain parts of the Layout Manager.
9.2 The Image Classes
Figure 85 shows the hierarchy of the Objective Toolkit image classes. Figure 85 – Objective Toolkit image class hierarchy
CObject
SECImage
SECDib
SECGif
SECJpeg
SECPcx
SECTarga
SECTiff
9.2.1 SECImage
SECImage is an abstract base class from which the individual image file format classes derive. The SECImage class contains most of the functionality provided by Objective Toolkit’s image support such as reading, writing, format conversion, and limited image manipulation.
The format-specific derivatives act as translators for reading the format-specific image bits into the internal SECImage format and writing from the internal SECImage format to the specific image for- mat. For example, SECPcx is an SECImage derivative that can read a .PCX file, convert it to the internal SECImage format and then write the SECImage format out as a .PCX file.
This architecture isolates image format-specific code to the derived image classes and places gen- eral image handling routines in the SECImage base class.
Because SECImage is an abstract base class, you cannot create an instance of it. Instead, use one of the image format-specific derivative classes: SECDib, SECGif, SECJpeg, SECPcx, SECTarga, or SECTiff.
158 9.2.2 SECDib
The SECDib class supports the reading and writing of the Windows Device Independent Bitmap (.DIB) format. Typically, these files have .bmp or .dib extensions. SECDib supports all color and compression formats for DIBs.
9.2.3 SECGif
The SECGif class supports reading and writing for Graphic Information File (.GIF) images. The GIF format is defined by CompuServe and is currently one of the standard image types used by Inter- net World Wide Web (WWW) browsers. Support is also included for interlaced as well as transparent GIF images.
9.2.4 SECJpeg
The SECJpeg class supports the JPEG compression scheme found in JFIF (JPEG File Interchange Format) files, which is used in many Internet World Wide Web browsers and professional image applications. SECJpeg is based on the version 1.02 JFIF standard. Objective Toolkit includes support for progressive JPEG images.
9.2.5 SECPcx
The SECPcx class supports the PC eXchange (PCX) format that many Windows graphics applica- tions use for exchanging images. The current version of SECPcx only supports writing out to 256 colors.
9.2.6 SECTarga
The SECTarga class handles the TGA (TARGA Image File) format as defined by Truevision. TGA is used in video-capturing applications and supports 24-bit color. SECTarga only supports 24-bit-per- pixel images.
9.2.7 SECTiff
The SECTiff class can read and write Tagged Image File Format (TIFF) files. TIFF files are common in scanning applications. SECTiff supports version 6.0 of the TIFF standard and includes support for all image depths and compression schemes.
Chapter 9 Image Classes 159 9.3 SECImage Format
SECImage stores its image data internally in device independent bitmap (DIB) format. This has some unique advantages and disadvantages. The main disadvantage is that the image is not com- pressed in any way. The advantages include the ability to access data members such as m_lpSrcBits (pointer to the actual data bits) and m_lpBMI (pointer to the BITMAPINFO structure) directly. You can use these data members directly in Windows APIs such as StretchDIBits().
If you want to modify the SECImage format for editing or other purposes, we suggest you review how the image manipulation routines (for example, Rotate90() and FlipVert()) are imple- mented to become familiar with the internal format.
160 9.4 Using the Image Classes
Typically, an image class loads the image from a file, renders the image on the display with the StretchDIBits() API, performs any number of image processing manipulations on the image, and then saves the modified image to a new file. The sections that follow explain how to perform each of these actions with the SECImage family of classes.
SECImage is serializable, so if you include an SECImage instance in your document, it is serialized with the rest of your data.
9.4.1 To read an image from a file
The standard method for reading images is LoadImage(). LoadImage() is a virtual function in SECImage that is implemented by each format-specific derived image class. The SECImage deriva- tive classes read image data from a format-specific image file and translate it to the intermediate format used by the parent SECImage class. When an image is loaded, the m_pPalette member of SECImage is created, which creates a palette for the loaded image based on the loaded color map.
The following code loads a .PCX file.
// . . . SECPcx pcx; if (pcx.LoadImage(“check.pcx”) == FALSE) ASSERT(1); //LoadImage FAILED! //Now we have an image loaded, and it can be displayed
9.4.2 To view GIF/TIFF images
Two Objective Toolkit classes use LZW compression: SECGIF and SECTiff. These classes contain stub routines where the LZW compression algorithms belong. As a result, if you attempt to load or save images of GIF or TIFF format, an error occurs at run time.
GIF is a popular format for graphics to be viewed in Web browsers, while TIFF (tag-based image file format) is a dig- ital data format compatible with a variety of scanners, faxes, and other image-processing applications.
We offer a GIF/TIFF Unlock Pack (lzwcode.zip) that allows you to replace the stubbed classes with the source code of the algorithm.
9.4.3 To display an image
Once an image has been successfully created or loaded from an image file, you can display it on any device context (DC) by treating the data contained by SECImage as a device independent bit- map (DIB). A DIB is typically rendered to a DC via the StretchDIBits() API. Objective Toolkit encapsulates the StretchDIBits() call through its own StretchDIBits() method.
The advantage of using the Objective Toolkit encapsulated StretchDIBits() is that it increases the resolution of the image you’re manipulating to a resolution greater than the one available on your DC. In this case, Objective Toolkit automatically displays the image correctly. For example, if you
Chapter 9 Image Classes 161 attempted to display a 24-bits-per-pixel image on an 8-bits-per-pixel display in the WIN32 environ- ment, Objective Toolkit would make a call to the CreateHalftone() palette API, which creates a palette with the closest matching color values to the image in memory. The approximated palette contains the standard colors for the image. In the 16-bit environment, Objective Toolkit uses its own internal quantize routine to perform an operation similar to CreateHalftone().
The following code displays an image. void CImageView::OnDraw(CDC* pDC) { SECImage * pImage = pDoc->GetImage(); CPalette *pOldPalette;
// If a palette has been created for the image, select it. if (pImage->m_pPalette) pOldPalette = pDC->SelectPalette(pImage->m_pPalette, TRUE);
// Call encapsulated StretchDIBits API pImage->StretchDIBits(pDC, 0,0, pDoc->GetDocSize().cx, pDoc->GetDocSize().cy, 0,0, pImage->m_dwWidth, pImage->m_dwHeight, pImage->m_lpSrcBits, pImage->m_lpBMI, DIB_RGB_COLORS, SRCCOPY );
// Restore the palette if (pImage->m_pPalette) pDC->SelectPalette(pOldPalette, TRUE); }
9.4.4 To convert an image
The SECImage family of classes allows you to convert from one image format to another easily. For example, if you wanted to convert an GIF image to an JPEG image, you would add a few lines of code using the Objective Toolkit image classes.
Image format conversion is performed using the ConvertImage() method. Given a source image and a destination image, ConvertImage() can use image instances interchangeably. For example, a .PCX image can be loaded into memory through an instance of the SECPcx class and then con- verted with an instance of any other derived image class. Unlike CopyImage(), ConvertImage() does not duplicate image data. Once an image is converted, you can safely delete the source image class instance.
The following code demonstrates how to convert an SECPcx image into an SECGif image: void TestConversion(SECPcx *pSrc) { // Create destination instance SECGif *pDest = new SECGif(); pDest->ConvertImage(pSrc);
// Now pDest is a valid image, while pSrc // contains no data... pDest->SaveImage(“convert.gif”);
162 // Convert back to validate the source image again. pSrc->ConvertImage(pDest);
// delete the destination, will not affect // pSrc data members at all delete(pDest); }
9.4.5 To copy an image
SECImage supplies a CopyImage() routine that allows you to create a duplicate of a source image. You can use this routine to make a copy of an image before allowing your user to change it. Then, you can allow the user to revert to the original image.
CopyImage() behaves the same way the ConvertImage() method does, except it does not alter the source image so the user can use it after the copy is performed.
The following code copies a TIFF image to a JPEG image: void TestCopy(SECTiff *pSrc) { // create the destination image SECJpeg *pJpeg = new SECJpeg(); if (!pJpeg) return;
if (!pJpeg->CopyImage(pSrc)) { delete pJpeg; return; }
// Now you have two independent copies of the // same image in 2 different formats
// destruction of object will destroy the // copied image data, while pSrc is left intact. delete pJpeg; }
Images often require a large amount of memory. Creating a copy does not perform any compression or savings in memory. In effect, it requires twice the amount of memory.
9.4.6 To manipulate an image
Once you create an image and load it into memory, you can manipulate the image through a num- ber of SECImage methods.
For example, you can flip and rotate the image. You can flip an image vertically or horizontally by calling the FlipVert() or FlipHorz() methods. You can rotate images 90 degrees counter-clock- wise by calling the Rotate90() method.
Chapter 9 Image Classes 163 ContrastImage() accepts a signed integer to modify the contrast of the image. A positive value increases the sharpness of the image and a negative value decreases its sharpness.
CropImage() accepts coordinates of a clipping rectangle used to crop the image currently loaded in memory. Coordinates are passed in as the left, top, right and bottom positions. If positions are passed that extend beyond the maximum reach of the current image, the clipping coordinates are limited to the rightmost and bottommost positions of the image.
The following code demonstrates how to use the image manipulation methods.
void Manipulate(SECPcx *pSrc) { // First rotate it pSrc->Rotate90();
// Next Flip it on the horizontal axis pSrc->FlipHorz();
// Flip again on the vertical axis pSrc->FlipVert();
// Dull the image by decreasing contrast pSrc->ContrastImage(-1);
// Then crop the image to a hypothetical region pSrc->CropImage(50, 50, 100, 100); }
9.4.7 To write an image to a file
SECImage and derivatives allow you to save an image to a file via the SaveImage() method. SaveImage() succeeds only when a legitimate image is loaded in the image class. The following code demonstrates how to save a .PCX image to a file named new.pcx.
if (pcx.SaveImage(“new.pcx”) == FALSE) ASSERT(1); //SaveImage failed!
9.4.8 To convert to a CBitmap object
Using Objective Toolkit, you can create a device-specific bitmap from an SECImage instance. To do this, ensure that then image is at the same resolution as the device. Otherwise, the CBitmap is cre- ated for an incorrect display type. You can create a CBitmap object with the MakeBitmap() method, which returns a pointer to a new CBitmap object. MakeBitmap() accepts a pointer to the current device context as an argument (CDC pointer).
9.4.9 To convert from a CBitmap object
When you perform GDI drawing functions to a device context (CDC object), you need to convert the image of the bitmap selected in the device context to the SECImage format. To do so, use the CreateFromBitmap() method, which accepts CBitmap and CDC pointers as arguments. The cre-
164 ated SECImage instance contains the same dimensions and depth as the CBitmap itself. If the CDC is a memory device context, ensure that you clear the bitmap with a GDI call before making the call to CreateFromBitmap().
9.4.10 To create from a CDC object
This is a two-step process:
1. Create a CBitmap object from your CDC.
2. Instantiate an SECImage object and call SECImage::CreateFromBitmap().
You can create a CBitmap with the following code:
CBitmap bitmap; bitmap.CreateCompatibleBitmap(&dc);
CDC dcMem; dcMem.CreateCompatibleDC(&dc);
CBitmap* pOldBitmap = dcMem.SelectObject(&bitmap);
// Todo: draw to the memory dc here...
dcMem.SelectObject(pOldBitmap);
SECImage::CreateFromBitmap() takes a pointer to a CBitmap object and to a CDC object to copy the image data from the CBitmap.
9.4.11 To load an image from a resource
The SECImage base class does not support direct loading of image data from a resource; however, you can load images indirectly. After you have imported your image file as binary data in the resource editor, do the following to load it:
1. Obtain a pointer to the resource data.
2. Attach the data to a CMemFile object.
3. Instantiate an SECImage-derived object and call LoadImage() using the CMemFile.
The following section of code demonstrates this:
// The image is stored as a resource in file format.
HINSTANCE hinst = AfxGetInstanceHandle(); HRSRC hRes = FindResource(hinst, szResNavn, szResType); if (hRes == NULL) { TRACE2("Couldn't find restype %s resource %s!\n", szResType,szResNavn); return FALSE; }
Chapter 9 Image Classes 165 // need the pointer to the image data and it's length DWORD len = SizeofResource(hinst, hRes); BYTE* lpImage = (BYTE*)LoadResource(hinst, hRes); ASSERT(lpRes);
// CMemFile is CFile-derived, and will soon be used to // to load the image using SECImage::LoadImage CMemFile* pImgMemFile = new CMemFile(); SECJpeg* pJpeg; \\ let's assume I know the image will be JPEG
// Attach the image data to a CMemFile, which will allocate space. // ImageBufLen is the size of the image buffer pImgMemFile->Attach(lpImage, lImageBufLen);
// now use the CMemFile to load into the SECJpeg object // for manipulation or display pJpeg = new SECJpeg(); if (!pJpeg->LoadImage(pImgMemFile)) { TRACE0("Couldn't LoadImage"); return FALSE; }
// can delete the CMemFile now since LoadImage allocated its own // space delete pImgMemFile; pImgMemFile = NULL;
FreeResource((HANDLE)lpRes); return(str);
. . .
9.4.12 To stream image data
Although the SECImage class does not directly support streaming, you can save SECImage to a CMemFile and then stream the data from CMemFile.
// The image is stored in the database in file format. It has // been retrieved here to a buffer called pImageInBuffer;
LPBYTE lpImage = pImageInBuffer; CMemFile* pImgMemFile = new CMemFile(); \\ CFile derived class SECJpeg* pJpeg; \\ let's assume I know the image will be JPEG
// Attach the image data to a CMemFile, which will allocate space. // ImageBufLen is the size of the image buffer pImgMemFile->Attach(lpImage, lImageBufLen);
// now use the CMemFile to load into the SECJpeg object // for manipulation or display pJpeg = new SECJpeg(); if (!pJpeg->LoadImage(pImgMemFile)) error("Couldn't LoadImage");
166 // can delete the CMemFile now since LoadImage allocated its // own space delete pImgMemFile; pImgMemFile = NULL;
// display the image in the pJpeg and or whatever manipulations // are required to it ...
// now save it back to a CMemFile pImgMemFile = new CMemFile; if (!pJpeg->SaveImage(pImgMemFile)) error("Couldn't SaveImage");
// can now get the image back to the database via the lpImage ptr // this will store the image length in lImageBufLen and the // image itself // into lpImage lImageBufLen = pImgMemFile->GetLength(); lpImage = pImageMemFile->Detach();
// probably don't want to delete the pImageMemFile until you've // copied lpImage to the database or at lease to some other buffer // since Detach() just returns a pointer to CMemFile's buffer.
Ensure that you set the nGrowBytes for the CMemFile. The default is 1024.
Chapter 9 Image Classes 167 9.5 Key Image Methods
Here is an overview of some of the key SECImage methods.
Table 28 – Methods for SECImage
SECImage method Description
LoadImage() Loads an image from file. To load a GIF, use SECGif; to load a TIFF, use SECTiff. SaveImage() Saves an image to file. The format of the image is based on the type of the object through which SaveImage is called. For example, SECGif::SaveImage writes the GIF format.
CopyImage() Creates a copy of an image.
ConvertImage() Converts one image to another type. The conversion actually takes place during writing or reading of the image because SECImage uses a standard internal for- mat for all image types. ConvertImage() copies the internal image and deletes the original without the over- head of actually copying the data.
FlipHorz() Flips an image horizontally.
FlipVert() Flips an image vertically.
Rotate90() Rotates an image 90 degrees counter-clockwise.
ContrastImage() Sharpens or dulls an image.
NumColors() Returns the number of colors used by the image.
9.6 Image Sample
The Objective Toolkit imagetst sample (samples\toolkit\MFC\image\imagetst) demonstrates all of the SECImage features covered here. Be sure to load in several images to see how to print pre- view and print them using the MFC document/view architecture.
168 Chapter 10 MDI Alternatives
10.1 Overview
Objective Toolkit offers the following MDI alternatives and enhancements:
Multiple Top-level Interface (MTI)
Floating Document Interface (FDI)
Workbook Document Interface (WDI)
Although you can easily convert your MDI application to any of our MDI alternatives, you need to consider your application users when you select an interface. Our Multiple Top-Level Interface (MTI) and Floating Document Interface (FDI) are radically different from MDI, whereas our Work- book Document Interface (WDI) augments the capabilities of MDI without changing the interface drastically.
Chapter 10 MDI Alternatives 169 10.2 Benefits of MDI Alternatives
With the release of Windows 95, Microsoft made it known in The Windows Interface Guidelines for Software Design that they are moving away from MDI in their Office products; however Microsoft has not provided Windows operating-system-level support or MFC support for any of the MDI alternatives described in their design guide. Currently, MFC only supports the Multiple Document Interface (MDI) and Single-Document Interface (SDI), which are waning in popularity. Objective Toolkit proves you with three additional alternatives: MTI, FDI, and WDI.
10.2.1 Multiple Top-level Interface (MTI)
MTI is a combination of SDI and MDI. As in SDI, each top-level window manipulates one docu- ment. As in MDI, the user can have multiple documents open simultaneously. MTI creates a new top-level window for each new document. MTI departs from the MDI model in which one parent frame owns and contains every document window.
From the user’s standpoint, an MTI application most closely resembles an SDI application because he can only associate one document with a frame.
170 Figure 86 – Example of a MTI Application
However, note that when the user loads or creates document, an additional frame is created to hold the document instead of loading the document into the existing frame.
Chapter 10 MDI Alternatives 171 Figure 87 – Example of an MTI Application (new document)
MTI-based applications create document windows that float freely on the desktop. This approach is common in other GUI operating systems such as the OSF/Motif windowing system for UNIX. It has also become a popular Windows interface. For example, you can easily activate MTI windows from the Windows 98 taskbar.
10.2.2 MTI Class – SECToplevelFrame
The SECToplevelFrame class is the basis for the MTI MDI-alternative. MTI applications derive from SECToplevelFrame whereas an MDI application would derive from CMDIChildWnd.
The following figure is the hierarchy for SECToplevelFrame. Figure 88 – Objective Toolkit MTI Class Hierarchy
CFrameWnd
SECFrameWnd
SECToplevelFrame
172 10.2.2.1Using MTI
The following sections describe how to create an MTI application from a new or existing MFC project.
10.2.2.2To convert an existing SDI application to MTI
1. Replace the base class of your CFrameWnd-derived class with SECToplevelFrame.
2. Replace the instantiation of a CSingleDocTemplate in the InitInstance() method of your CWinApp-derived class to CMultiDocTemplate.
10.2.2.3To convert an existing MDI application to MTI
1. Replace the base class of each existing MDI child frame (CMDIChildWnd) with SECToplevelFrame. This ensures that the MDI child windows retain all of their previous capabilities and can float freely on the desktop instead of being confined to the MDI frame window.
2. Remove the CMainFrame class and all references to it from your application. Because MTI has no equivalent to an MDI frame window, your CMainFrame class has no role in a MTI implementation. If you have a significant amount of code in your CMainFrame class, you need to consider moving the code to a new location.
3. The next step is to modify the OnInitInstance() method of your CWinApp-derived class. The OnInitInstance() method typically includes code to instantiate a document template and the MDI frame window. You must remove the instantiation of the MDI frame window and all references to it from the application.
4. In most cases, it is not necessary to modify the code in OnInitInstance() method which instantiates the document template. The CMultiDocTemplate is still used by MTI because it does not include anything that is MDI-specific. It manages multiple documents (docu- ment/view documents, not MDI documents) and, in that capacity, remains useful for MTI without modification.
5. Override the OnCreate() method of your SECToplevelFrame-derived class or classes and create your control bars (toolbars, status bars, and more). CFrameWnd::OnCreate() is the method that usually creates these objects and SECToplevelFrame-derived classes are no exception.
10.2.2.4To create a new MTI-based application
1. Create a new MDI application using the Visual C++ | MFC App Wizard.
2. Follow the steps described in Section 10.2.2.3.
10.2.2.5Customizing MTI
The following sections show you how to modify the default behavior of an MTI application and present some information about message handling.
Chapter 10 MDI Alternatives 173 10.2.2.6To load the document into the initial, empty frame
By default, MTI-based applications behave the same way as MDI apps. For example, when you open a MTI application one top-level frame window containing an empty, untitled document appears. If you select Open from the File menu and select a file, a new top-level window is created, and the document is displayed therein. When you open a file, you are actually opening two win- dows. One window is empty whereas the other window contains the document of interest. This is exactly the same behavior MDI applications exhibit. In some applications, it is preferable to load the document into the initial empty frame rather than create a new one.
1. Derive a class from CMultiDocTemplate and override its OpenDocumentFile() method.
2. You may also want to change the standard call to the OnFileNew() method in CYourApp::InitInstance() to OnFileOpen() so your application will display an open file instead of an empty document in the first top-level frame when you start it.
10.2.2.7Message Dispatching in an MTI Application
There are a couple of key MTI data members that you need to consider if you’re setting up message dispatching for your MTI application:
SECToplevelFrame::s_tlfList. A static list of open top-level frame windows. You may need to dispatch a message or member function call to every top-level frame window on the desktop. Only those owned by the MTI application in question are accessible. Iterate over the top-level frames in this list and dispatch messages to them individually.
If you are using MTI in a DLL, use the accessor functions GetTLFList() and SetTLFList().
theApp.m_pMainWnd. In SDI and MDI applications, only one main frame window is allowed by definition. Consequently, m_pMainWnd is initialized at startup and remains constant until the application exits. With MTI, the m_pMainWnd is constantly changing to reflect the top-level frame that currently has focus. If you need to dispatch a message or member function call to the active top-level frame, reference this variable.
10.2.2.8Other Uses For SECToplevelFrame
The SECToplevelFrame class can act as more than a MDI alternative in your application. Because SECToplevelFrame is only varies slightly from CFrameWnd, you can use it anywhere you would have used CFrameWnd as a base class. SECToplevelFrame contains nothing that binds it to the doc- ument/view architecture, so you can use it in applications that do not adhere to doc/view architecture. When you use this class as a specialized frame window instead of an MDI alternative, SECToplevelFrame gives you the capability to create a top-level frame with any arbitrary client. The top-level frame is given its own entry in the Windows 98 task bar, and it can remain open when other application windows are iconified.
174 10.2.2.9MTI Sample
The Objective Toolkit mt_scrib sample (
10.2.3 Floating Document Interface (FDI)
FDI is like MDI except in FDI the MDI children can float freely on the desktop. In MDI, the MDI children are confined to the MDI parent window. As with MDI, you can have multiple open docu- ments in FDI. FDI creates a new floating child window for each new document. Each FDI child window appears as a top-level window and manipulates one document. Optionally, each FDI child window can include a menu bar containing menu items specific to that window. Figure 89 – Example FDI application
As for the main window, all menu items need to apply at the application level or to all FDI chil- dren; otherwise, focus becomes an issue. For example, if you activate an FDI child and then pick a menu item from the main application window, the FDI child loses activation and consequently its menu pick. FDI-based applications have a look-and-feel that is similar to Microsoft Visual Basic.
Chapter 10 MDI Alternatives 175 10.2.3.1Differences between FDI and MTI
Because FDI allows you to place document windows on the desktop, its interface is somewhat sim- ilar to MTI. In MTI, no main window owns all the other windows in the application. However, the concept of a main frame window remains to serve as a menu strip or primary application window. Because MTI document windows are root-level windows, they are given their own Windows 98 task bar entries. FDI document windows are not root-level windows. You can iconify MTI docu- ment windows independently of all other windows. In FDI, when the main application window is iconified, all the FDI children are iconified as well.
10.2.3.2FDI Classes
FDI is implemented in two classes that both derive from SECFrameWnd. This hierarchy is as follows. Figure 90 – Objective Toolkit FDI class hierarchy
CFrameWnd
SECFrameWnd
SECFDIChildWnd
SECFDIFrameWnd
10.2.3.3SECFDIChildWnd
The SECFDIChildWnd class is a document window that is similar to a MDI child window, except it can float freely on the desktop whereas a MDI child window is tied to its parent frame. FDI applica- tions derive from SECFDIChildWnd. MDI applications derive from CMDIChildWnd.
10.2.3.4SECFDIFrameWnd
The SECFDIFrameWnd class is a main frame window that adds support for the Window menu and the Windows… dialog. FDI applications derive from SECFDIFrameWnd. MDI application would derive from CMDIFrameWnd.
10.2.3.5Using FDI
The following sections tell how to use FDI in new and existing projects.
10.2.3.6To convert an existing SDI application to FDI
1. First, convert your SDI application to an MDI application. This transition is typically com- prehensive. It may require you to re-derive several of your application’s classes.
2. Follow the steps described in Section 10.2.2.3.
176 10.2.3.7To convert an existing MDI application to FDI
1. Replace CMDIChildWnd, the base class of all existing MDI child frames, with SECFDIChildWnd so that the MDI child windows retain all of their previous capabilities and float freely on the desktop instead of being confined to the MDI frame window.
2. Replace CMDIFrameWnd, the base class of your main frame class, with SECFDIFrameWnd.
3. If you want your main frame window to serve as a menu strip, override SECFDIFrameWnd::PreCreateWindow() and then specify the initial window size and position.
4. Override the OnCreate() method of your SECFDIChildWnd-derived class or classes and create your control bars (toolbars, status bars, and more).
10.2.3.8To create a new FDI-based application
1. Generate an MDI application using AppWizard.
2. Follow the steps in Section 10.2.3.7.
10.2.3.9FDI Sample
The Objective Toolkit fdi sample (
10.2.4 Workbook Document Interface (WDI)
The WDI classes enhance MDI by allowing the user to place every document in a tabbed window. This reduces MDI modality. All of the documents are part of a workbook of worksheets. The user can open a specific worksheet by clicking a tab instead of selecting the Window menu and search- ing for it.
Chapter 10 MDI Alternatives 177 Figure 91 – Example MDI Application
Because WDI adds an optional Workbook View to MDI, there is no cost associated with converting your MDI application to WDI. WDI enhances your MDI application without losing any functional- ity or fundamentally changing the MDI user interface. In other words, a WDI application with workbook viewing mode deactivated is equivalent to MDI.
10.2.4.1Adding Flat Style Drawing to the Workbook Window
New ‘flat’ style drawing has been added to the workbook window. In order to enable flat style drawing, you need to call the SetFlatStyleMode function (a member of the SECWorkbook class). Figure 92 – A Workbook Window with Flat Style enabled
To view sample code which shows how to set the flat drawing style, please see the CMainFrame::OnCreate function implementation in MAINFRM.cpp, VIZ sample:
SetFlatStyleMode(TRUE);
178 The Viz sample demonstrates this feature, and can be found at
10.2.4.2Adding Flat Style Drawing to the Shortcut Window
New ‘flat’ style drawing has been added to the shortcut window. In order to enable flat style draw- ing, you need to call the SetFlatStyleFunction function (a member of the SECShortcutBar class). Figure 93 – A Shortcut Window in Mouse Hover mode with Flat Style Enabled
To view sample code which shows how to set the flat drawing style, please see the CShortcutList- DockBar::OnCreate function implementation in LSTDBAR.cpp, VIZ sample: m_scListBar.SetFlatStyleMode(TRUE);
The Viz sample demonstrates this feature, and can be found at
10.2.4.3Adding Flat Style Drawing to the 3D Tab Control Window
New ‘flat’ style drawing has been added to the 3D tab control window. In order to enable flat style drawing, you need to set the TWS_FLATSTYLE window style while creating the tab control win- dow. Alternatively, you can enable flat style drawing at a later time by calling the SetTabStyle function (a member of the SEC3DTabWnd class). Figure 94 – A 3D Tab Control Window with Flat Style Enabled
To view sample code which shows how to enable flat style drawing for tabbed control windows during creation time, please see the ProjectWorkspaceWnd::OnCreate function implementation in PRJBAR.cpp fo the Viz sample: m_wndTab.Create(this,WS_CHILD|WS_VISIBLE|TWS_TABS_ON_BOTTOM| TWS_FLATSTYLE);
Chapter 10 MDI Alternatives 179 To view sample code which shows how to toggle flat style drawing for tabbed control windows, please see the CChildFrame2::OnSwitchFlat function implementation in CHLDFRM2.cpp of the TabDemo sample:
m_bFlatStyle = !m_bFlatStyle; DWORD dwStyle = m_tabWnd.GetTabStyle(); if( !m_bFlatStyle ) dwStyle &= (~TWS_FLATSTYLE); else dwStyle |= TWS_FLATSTYLE; m_tabWnd.SetTabStyle( dwStyle );
The TabDemo sample does not ship with the product. For information on where you can obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
The Viz sample also demonstrates this feature. It can be found in at
10.2.4.4WDI Classes
WDI support is provided by a combination of three MFC extensions: SECWorkbookWnd, SECWorksheetWnd, and SECWorkbookClientWnd. Figure 95 – Objective Toolkit WDI Class Hierarchy
CWnd
CMDIFrameWnd
SECMDIFrameWnd
SECWorkbookWnd
CFrameWnd
CMDIChildWnd
SECMDIChildWnd
SECWorksheetWnd
SECWorksheetClientWnd
10.2.4.5SECWorkbookWnd
The SECWorkbookWnd class is derived from SECMDIFrameWnd. It adds the workbook interface (WDI) enhancements. Derive your main frame window class from SECWorkbookWnd if you want the workbook interface enhancements.
180 10.2.4.6SECWorksheetWnd
The SECWorksheetWnd class is derived from SECMDIChildWnd. It adds the workbook interface (WDI) enhancements. Derive your MDI child windows from SECWorksheetWnd if you want to implement the workbook interface enhancements.
10.2.4.7SECWorkbookClientWnd
The SECWorkbookClientWnd subclasses the MDI client window and is implemented as a part of the workbook interface. SECWorkbookClientWnd allows the WDI framework to hook into CFrameWnd’s window layout calculation and specify a client area that allots space for drawing the border and tabs.
10.2.4.8To convert an existing MDI application to WDI
1. Replace CMDIChildWnd, the base class of all existing MDI child frames, with SECWorksheetWnd so the MDI child windows retain all of their previous functionality and become tabbed worksheets.
2. Replace CMDIFrameWnd, the base class of your CMainFrame class, with to SECWorkbookWnd.
3. Replace the base class of all toolbars derived from CToolBar with SECToolBar.
4. Replace CStatusBar, the base class of the status bar, with SECStatusBar.
5. Call SetWorkbookMode(TRUE) in CMainFrame::OnCreate().
10.2.4.9Customizing WDI
SECWorkbookWnd has overridable functions that you can use to customize several aspects of WDI including:
The order in which tabs are displayed
The tab label
The tab icon
The interface’s general appearance
10.2.4.10To change the tab display order
Override the AddSheet() and RemoveSheet() member functions. These members are expected to assign values to SECWorksheetWnd::m_nPosition for every worksheet in your workbook. In your override, you can assign any tab position to newly created worksheets.
10.2.4.11To draw a different worksheet tab label
Override the SECWorkbookWnd::GetTabLabel() function.
Chapter 10 MDI Alternatives 181 10.2.4.12To change the icon
Override the SECWorkbookWnd::GetTabIcon() function.
10.2.4.13To change the appearance of the tabs
Override the SECWorkbookWnd::OnDrawTab() and SECWorkbookWnd::OnDrawTablconAndLabel() functions.
10.2.4.14Key WDI Methods and Data Members
A summary of the key methods and data members that you can use to customize the WDI is pre- sented in the table below.
Table 29 – Key Methods and Data Members for WDI
Member Description
SECWorksheetWnd::m_nPosition A data member that specifies the position of the tab associated with this worksheet within the row of tabs in the workbook. By default, the application display the tabs by order of creation. You can change the order by assign- ing a value to this member.
SECWorkbookWnd::AddSheet() A virtual method that is called whenever a new MDI child window is created. This mem- ber creates a new tab associated with the new MDI child and assigns it a position within the row of tabs. To change the order in which tabs are displayed, override the AddSheet() member and set the SECWorksheetWnd::m_nPosition member.
SECWorkbookWnd::RemoveSheet() A virtual method called whenever an MDI child window is destroyed. Override this member if you require additional work to occur whenever a sheet is removed from the workbook.
SECWorkbookWnd::GetTabLabel() A virtual method that returns the label to be drawn on the tab. By default, this label is the title of the MDI child’s active document. If this label is not appropriate for your application, override this member and return the label you need.
182 Table 29 – Key Methods and Data Members for WDI (Continued)
Member Description
SECWorkbookWnd::GetTabIcon() A virtual method that returns the icon to be drawn on the tab. If NULL is returned, no icon is drawn. By default, this icon is the one asso- ciated with the MDI child frame via the resource file. If you prefer a different icon, override this member and return a different icon.
SECWorkbookWnd::OnDrawTab() A virtual method that draws a blank tab at the position within the row of tabs specified by SECWorksheetWnd::m_nPosition. By default, the tab has a 3D look. If you want to change the look of the tab, override this member and draw the tab with the look you prefer.
SECWorkbookWnd::OnDrawTabIcon A virtual method that renders the icon and AndLabel() tab label on top of the blank tab drawn by SECWorkbookWnd::OnDrawTab(). Over- ride this member if you require the tab’s inscription to be rendered differently.
Chapter 10 MDI Alternatives 183 184 Chapter 11 Shortcut Bar
11.1 Overview
The Objective Toolkit Shortcut Bar closely resembles the Microsoft Outlook Bar™. You can use it as a container class to embed any CWnd-derived objects. Because the shortcut bar is a CWnd-derived class, you can embed it anywhere. For example, you could easily embed it in a docking window, in a pane of a splitter window, or even in the entire client area of the frame window.
The shortcut bar is a variant of the tab window. However, instead of displaying tabs, it displays horizontal bars that are stacked vertically. The window representing the currently activated bar is displayed directly beneath the bar. Instead of instantly tabbing to the selected window, the process of displaying a window when a bar is selected is animated. Figure 96 – Shortcut Bar Displaying a List of Icons
Chapter 11 Shortcut Bar 185 The following figure is of a shortcut bar that holds a tab control that, in turn, holds a tree control. The shortcut bar is held by a docking window. Figure 97 – Example Shortcut Bar with an Embedded Window
186 11.2 The Shortcut Bar Classes
The Shortcut bar is implemented in the SECShortcutBar class, which is derived from CWnd. SECShortcutBar utilizes the classes SECBar or SECListBar and SECShortcutListCtrl to display the bars and windows that it contains. Figure 98 – Objective Toolkit shortcut bar class hierarchy
CWnd
SECShortcutBar
11.2.1 SECShortcutBar
The SECShortcutBar class derives from CWnd, and it acts as a container class for other CWnd- derived objects. Because it is CWnd-derived, SECShortcutBar can also be held by other CWnd- derived objects.
The bars that are displayed in the SECShortcutBar window are either instantiations of SECBar or SECListBar, or a combination, depending on the overload of AddBar(), which was called to create them. If the SECShortcutBar is acting as a container for an arbitrary CWnd object, the bar is of type SECBar. If the SECShortcutBar is a container for a Microsoft Outlook Bar™-like list of icons, the bar is of type SECListBar and the window that displays the list of icons is of type SECShortcutListCtrl. The following figures are of these contained bars and windows. Figure 99 – Containment of SECBar in SECShortcutBar
Chapter 11 Shortcut Bar 187 Figure 100 – Containment of SECListBar and SECShortcutListCtrl in SECShortcutBar
11.2.2 SECBar
An SECBar object represents a single bar window that a user can select. It is displayed inside the SECShortcutBar window. An SECBar object is created when the version of AddBar() that accepts a CWnd parameter is called. A bar that contains the embedded CWnd object is added to the shortcut bar.
11.2.3 SECListBar
The SECListBar class derives from SECBar and represents a single bar window that a user can select. It is displayed inside the SECShortcutBar window. Every time a bar that contains an embed- ded SECShortcutListCtrl (displays icons like the Microsoft Outlook Bar™) is added, an SECListBar is created.
If you use an SECBar derivative class, you can mix bars of different types in the shortcut bar. For example, one bar can contain an SECListBar and another can contain an SECBar with an SECTreeCtrl associated with it.
11.2.4 SECShortcutListCtrl
The SECShortcutListCtrl contains the list of labeled icons that will appear in a pane in the Shortcut bar.
188 11.3 Shortcut Bar Styles
The following table lists the short bar styles that you can specify in calls to the Create() or ModifyBarStyles() methods.
Table 30 – Shortcut Bar Styles
Shortcut bar style Description
SEC_OBS_VERT Orients the shortcut bar vertically. This is the default orientation.
SEC_OBS_HORZ Orients the shortcut bar horizontally. This is not a default style.
SEC_OBS_BUTTONFEEDBACK Draws a button-down look for the bar when it is pressed. This is not the default style.
SEC_OBS_CONTEXTMENU Enables the display of a context menu when the user clicks the right mouse button on the shortcut bar. You can associate the displayed menu with the shortcut bar via the SECShortcutBar::SetBarMenu() method. This is not the default style.The context menu associated with this flag does not appear when an SECShortcutListCtrl window is right clicked. SECShortcutListCtrl has its own con- text menu that is displayed in response to a right click.
SEC_OBS_ANIMATESCROLL Enables animated scrolling. This is not the default style.
SEC_OBS_BUTTONFOCUS Draws the focus rectangle on the contained bars when they are given the focus. This is not the default style.
SEC_DEFAULT_OUTLOOKBAR The default style for the shortcut bar when none is specified. This style is the same as spec- ifying (WS_VISIBLE | WS_CHILD | SEC_OBS_VERT).
Chapter 11 Shortcut Bar 189 11.4 Shortcut Bar Notification Messages
SECShortcutBar sends the following notification messages to its parent.
Table 31 – SECShortcutBar’s Notification Messages
Notification message Description
NM_LB_REORDERED Notification sent when items are reordered.
SEC_NM_ITEMCLICKED Notification of item clicked.
11.5 Shortcut Bar Callbacks
You can override the following virtual functions to modify the default behaviors.
Table 32 – Callback Methods for the Shortcut Bar
Callback method Description
OnStyleChange() Called when styles changing.
OnChangeBar() Called when trying to change bar.
OnRemoveBar() Called when trying to remove a bar.
OnDisableBar() Called when trying to disable a bar.
OnEnableBar() Called when trying to enable a bar.
OnCreatePaneWnd() Called after creating CWnd for bar object.
OnCreateBar() Called after creating SECBar object.
190 11.6 Using SECShortcutBar
The following topics describe how you can use SECShortcutBar in your projects.
11.6.1 To incorporate an SECShortcutBar into your application
1. In the class for the parent window, instantiate an SECShortcutBar object. For example:
SECShortcutBar m_scBar;
2. During the creation of the parent frame, call the SECShortcutBar::Create() method to create the shortcut bar window. For example:
m_scBar.Create(this, WS_CHILD | WS_VISIBLE | SEC_OBS_VERT | SEC_OBS_ANIMATESCROLL, IDC_SHORTCUTBAR);
11.6.2 To add selectable icons to a shortcut bar
1. In one of your classes, create two CImageList members to hold the normal and small bit- map images. You need to create both lists for the images to ensure the icons appear correctly in the shortcut bar. For example, in the declaration file type:
CImageList m_imlNormal; CImageList m_imlSmall;
In the implementation file, insert:
m_imlNormal.Create( 32, 32, ILC_COLOR|ILC_MASK, 8, 1); m_imlSmall.Create( 16, 16, ILC_COLOR|ILC_MASK, 8, 1);
CBitmap bmpNormal; CBitmap bmpSmall;
VERIFY(bmpNorm.LoadBitmap(IDB_INBOX)); VERIFY(bmpSmall.LoadBitmap(IDB_INBOX_SMALL)); m_idInbox = m_imlNormal.Add( &bmpNorm, RGB(255,0,255)); m_imlSmall.Add( &bmpSmall, RGB(255,0,255)); bmpNorm.DeleteObject(); bmpSmall.DeleteObject();
VERIFY(bmpNorm.LoadBitmap(IDB_CONTACTS)); VERIFY(bmpSmall.LoadBitmap(IDB_CONTACTS_SMALL)); m_idContacts = m_imlNormal.Add( &bmpNorm, RGB(255,0,255)); m_imlSmall.Add( &bmpSmall, RGB(255,0,255));
Chapter 11 Shortcut Bar 191 bmpNorm.DeleteObject(); bmpSmall.DeleteObject();
2. Use the AddBar() method to create an SECListBar with a label. For example:
SECListBar* pListBar = NULL; pListBar = m_wndShortcutBar.AddBar(_T(“Fill With”)); ASSERT_VALID(pListBar);
When you embed CWnd objects in the shortcut bar, the bar class is SECBar, not SECListBar.
3. Add the image lists to the SECListBar.
pListBar->SetImageList( &m_imgNormal, LVSIL_NORMAL ); pListBar->SetImageList( &m_imgSmall, LVSIL_SMALL );
4. Set the notification window if you want to receive notification messages. This is important if the shortcut bar is embedded in a splitter window.
pListBar->SetNotifyWnd( this );
5. You can also set some extra information about the list bar.
//Little bit of info used to figure out who I am... pListBar->SetExtraData( (void*)FillPane );
6. Add icons using the image ID’s in the image lists using either the InsertItem() or AddItem() methods. For example:
//School Data records... pListBar->InsertItem( 0, _T("School Data"), 0 ); pListBar->SetItemData( 0, (DWORD)IDS_SCHOOL_FILE );
//Factory Data records pListBar->InsertItem( 1, _T("Factory Data"), 1 ); pListBar->SetItemData( 1, (DWORD)IDS_FACTORY_FILE );
11.6.3 To embed a window in a shortcut bar
Call the overloaded AddBar() method, which accepts a CWnd parameter. For example:
m_scBar.AddBar( &m_tabWnd, _T("3D Tab Wnd") );
11.6.4 To change the way the bars are drawn
Derive a class from SECBar and then override the Draw() method. For example:
class MyBar : public SECBar { //Required if you want to use your own bar objects //without deriving a new class from SECShortcutBar TOOLKIT_DECLARE_DYNCREATE(MyBar)
192 public: MyBar(); protected: virtual void Draw( CDC& dc ); };
//After creating the SECShortcutBar but before adding //any bar objects, add this line. m_wndShorcutBar.SetBarClass( RUNTIME_CLASS(MyBar) );
//If you don’t want to use your new bar class //for all the bars, you could do this CRuntimeClass* pOrigBarClass = m_wndShortcutBar.GetBarClass(); m_wndShortcutBar.SetBarClass( RUNTIME_CLASS(MyBar) ); // //Add as many bars of your new class as you want // //Prepare to add standard bars m_wndShortcutBar.SetBarClass( pOrigBarClass ); // //Add standard bars
For an SECListBar derivative, the call to SetBarClass()in the above code should be replaced with a call to SetListBarClass().
11.6.5 To allow shortcut bars to behave like buttons
Use the SEC_OBS_BUTTONFEEDBACK style flag as a parameter for the Create() or ModifyBarStyles() methods. When this style is specified, the bar remains pressed, like a button, giving the user additional feedback on which bar was clicked. For example: m_scBar.ModifyBarStyle( 0, SEC_OBS_BUTTONFEEDBACK);
See Section 11.3 for more style flags and their descriptions.
11.6.6 To enable context menus in a shortcut bar
1. Use the SEC_OBS_CONTEXTMENU style as a parameter for the Create() or ModifyBarStyles() methods. For example:
m_scBar.ModifyBarStyle( 0, SEC_OBS_CONTEXTMENU);
2. Associate a context menu with the shortcut bar by calling the SetBarMenu() method.
//Grab the zoom menu CMenu * pPopupMenu = AfxGetApp()->m_pMainWnd ->GetMenu()->GetSubMenu(3); ASSERT(pPopupMenu != NULL);
m_scBar.SetBarMenu(pPopupMenu);
Chapter 11 Shortcut Bar 193 The context menu specified here does not appear when an SECShortcutListCtrl window is right clicked. The SECShortcutListCtrl has its own context menu that is displayed when a right click occurs.
See Section 11.3 for more style flags and their descriptions.
11.6.7 To have the shortcut bars display the focus rectangle
Use the SEC_OBS_BUTTONFOCUS style flag as a parameter for the Create() or ModifyBarStyles() methods. For example:
m_scBar.ModifyBarStyle( 0, SEC_OBS_BUTTONFOCUS);
See Section 11.3 for more style flags and their descriptions.
11.6.8 To enable/disable animated scrolling
1. Use the SEC_OBS_ANIMATESCROLL style flag as a parameter for the Create() or ModifyBarStyles() methods. For example:
m_scBar.ModifyBarStyle( 0, SEC_OBS_ANIMATESCROLL);
2. To control the scrolling behavior further, call the SetAnimationSpeed() and SetAnimationStep() methods.
See Section 11.3 for more style flags and their descriptions.
11.6.9 To receive notifications when an icon in the SECShortcutListCtrl is clicked
1. In your parent window class (frame window, dialog, or other), add the ON_NOTIFY_RANGE macro to your message map macro list using the SEC_NM_ITEMCLICKED notification mes- sage. For example:
ON_NOTIFY_RANGE( SEC_NM_ITEMCLICKED, SEC_IDW_BARCLIENT_FIRST, SEC_IDW_BARCLIENT_LAST, OnListBarClicked )
2. Override SECShortcutBar::OnListBarClicked(). The prototype looks like this.
afx_msg void OnListBarClicked( UINT nID, NMHDR* pNMHDR, LRESULT* pResult );
See Section 11.4 for more information on notification messages.
194 11.6.10To determine which icon is clicked in an SECListBar window
When the user clicks an icon, it generates an SEC_NM_ITEMCLICKED notification. Typically, you would add a message map entry like the following to your listbar’s parent window (frame win- dow, dialog).
ON_NOTIFY_RANGE( SEC_NM_ITEMCLICKED, SEC_IDW_BARCLIENT_FIRST, SEC_IDW_BARCLIENT_LAST, OnListBarClicked )
The prototype for OnListBarClicked() is as follows: afx_msg void OnListBarClicked( UINT nID, NMHDR* pNMHDR, LRESULT* pResult );
The following is an example handler. void CMainFrame::OnListBarClicked( UINT nID, NMHDR* pNMHDR, LRESULT* pResult ) { ASSERT( pNMHDR->idFrom == nID ); ASSERT( nID >= SEC_IDW_BARCLIENT_FIRST ); ASSERT( nID <= SEC_IDW_BARCLIENT_LAST );
// Get the item clicked and display it SEC_SCNMHDR* pSCNMHDR=(SEC_SCNMHDR *)pNMHDR; TCHAR szMsg[80];
SECListBar* pListBar = (SECListBar*)&(m_scListBar.GetActiveBar()); SECShortcutListCtrl* pCtrl = pListBar->GetListCtrl(); CString strLab = pCtrl->GetItemText( pSCNMHDR->iSelItem,0); wsprintf(szMsg,_T("You clicked icon number %d\n Item Label: %s\n"), pSCNMHDR->iSelItem, strLab); AfxMessageBox(szMsg);
// Apply focus back to the listbar such that // the hot-tracked state is properly cleaned // up from the recent activation change. ::SetFocus(pNMHDR->hwndFrom); }
Chapter 11 Shortcut Bar 195 11.6.11To change the orientation of the shortcut bar at run time
Call the SetAlignStyle() method. For example:
//Change the SECShortcutBar to horizontal alignment m_wndShortcutBar.SetAlignStyle( SEC_OBS_HORZ );
//change back to vertical m_wndShortcutBar.SetAlignStyle( SEC_OBS_VERT );
11.6.12To embed an SECShortcutBar into a splitter pane
1. Derive a new class from CSplitterWnd. In the derived splitter class, introduce a handler for the WM_MOUSEWHEEL message and remove the call to the base CSplitterWnd handler. Return FALSE instead. For example:
BOOL CMySplitterWnd::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { //Do not call the base class handler. // Return false instead. return FALSE; }
2. Create a splitter window using the run-time class SECShortcutBar to create the shortcut bar as a child of the splitter window. For example:
// 1 row, 3 cols m_splitter.CreateStatic( this, 1, 3 ); m_splitter.CreateView( 0, 0, RUNTIME_CLASS(SECShortcutBar), CSize(0,0), pContext );
3. Retrieve a pointer to the shortcut bar from the splitter window. For example:
//m_pShortcutBar is a pointer to SECShortcutBar m_pShortcutBar = (SECShortcutBar*)m_wndSplitterWindow.GetPane(0,0); ASSERT_VALID(m_pShortcutBar);
4. Use the AddBar() method to add bars to the shortcut bar. See Section 11.6.2 and Section 11.6.3.
11.7 Shortcut Bar Samples
The functionality of SECShortcutBar is demonstrated in the Viz sample at
196 Chapter 12 Framework-Tailored Shortcut Bars
12.1 Overview
The new Shortcut Bar component is a framework (MFC, ATL) independent container that can be used for hosting regular HWND based Windows objects as well as 'visual components' that simply render themselves onto any given device context. This framework independence is achieved using the new Stingray Foundation Library (SFL). SFL, in conjunction with our existing Model View Con- troller (MVC) architecture, provides all the necessary plumbing that paves the way for the shortcut bar to be abstracted from the message/command mechanisms of MFC/ATL and to have a common core that can be plugged into either framework.
The term 'visual component', in the MVC context, refers to an instance of any class that derives from the MvcVisu- alComponent base. An MVC viewport is also a visual component. Please refer to the MVC documentation for detailed information on visual components, viewports and the MvcVisualComponent class.
Chapter 12 Framework-Tailored Shortcut Bars 197 Figure 101 – The Shortcut Bar
The SFL and MVC combination, together with the framework independence, makes it possible to provide two distinct variations of the shortcut bar - a regular windowed control and a non-win- dowed control. The windowed version has its own window handle while the non-windowed control uses the window handle of the host container.
For ease of use, four specialized implementations of the shortcut bar have been made available:
SECATLShortcutBarHosted
SECATLShortcutBarWnd
SECMFCShortcutBarHosted
SECMFCShortcutBarWnd
198 12.2 The Shortcut Bar Classes
Figure 102 – Shortcut bar class hierarchy
SECShortcutBarComp
CEventRouterMap
CWindowImpl
IVisualWindow
SECATLShortcutBarWnd
SECShortcutBarComp
CEventRouterMap
SECATLShortcutBarHosted
12.2.1 ATL
The SECATLShortcutBarWnd class is the windowed version of the shortcut bar that has been tai- lored for use in an ATL environment. In addition to the SFL base classes, SECATLShortcutBarWnd derives from SECShortcutBarComp and also ATL's CWindowImpl. CShortcutBarComp ties up the MVC triad and provides the common interface for the four variants of the shortcut bar; the CWindowImpl lineage provides the requisite windowing support.
SECATLShortcutBarHosted derives from the SECShortcutBarComp base class and provides the non-windowed version of the ATL component. When using SECATLShortcutBarHosted, the par- ent housing the control is expected to provide the window handle; that is, it should implement the SFL IVisualWindow interface.
12.2.2 MFC
Like the ATL implementations, the SECMFCShortcutBarWnd and SECMFCShortcutBarHosted classes respectively provide the windowed and non-windowed versions of the shortcut bar for use in an MFC-only environment.
Chapter 12 Framework-Tailored Shortcut Bars 199 12.3 Shortcut Bar Styles
Table 33 lists the bar styles that can be applied to shortcut bars.
Table 33 – Shortcut bar styles
Shortcut bar style Description
SEC_TABBAR_VERT Orients the shortcut bar vertically. This is the default orientation.
SEC_TABBAR_HORZ Orients the shortcut bar horizontally. This style is yet to be implemented.
SEC_TABBAR_BARCURSOR Uses a hand cursor for the bar objects, similar to MS Outlook. The default behavior is to use the arrow cursor.
SEC_TABBAR_NOANIMATE By default bar switching is animated. Setting this style disables the animation.
SEC_TABBAR_NOHILIGHT Moving the cursor over any of the bars in the shortcut bar will highlight it. Setting this style dis- ables this effect.
SEC_TABBAR_ CNTXTMENU When this style is set, right-clicking the shortcut bar will result in a WM_TABBAR_CNTXTMENU mes- sage being sent to the owner window. The wParam of the message is the index of the active bar while the IParam contains a menu handle that the shortcut bar displays upon return. Handling this message allows the shortcut bar's parent to customize the context menu.
200 12.4 Using the Shortcut Bar
We provide a windowed shortcut bar and a non-windowed shortcut bar; this section discusses using each version separately.
12.4.1 Using the Windowed Shortcut Bar
1. Depending on your application's framework, include either the ot_atlshortcutbar.h or ot_mfcshortcutbar.h header to your project.
2. To the parent class add a member of type SECATLShortcutBarWnd or SECMFCShortcutBarWnd, depending on which framework you use.
3. Handle the WM_CREATE message in the parent class. Within this handler, create the shortcut bar and set its initial styles.
// m_hWnd is the window handle of the parent. m_wndSCBar.Create(m_hWnd, rcBar); m_wndSCBar.SetBarStyle(m_wndSCBar.GetBarStyle() | SEC_TABBAR_CNTXTMENU);
4. Use the SECATLShortcutBarWnd::AddBarWnd() or SECATLShortcutBarWnd::AddBarVisual() methods to add either regular window-based clients or MVC visual component/viewport clients to the shortcut bar.
// m_pViewport is an instance of an MVC MvcViewport_T class m_wndSCBar.AddBarVisual(&m_pViewport, _T("Canvas Viewport"));
// m_wndTree is a standard C++ wrapper(CWnd/CWindow) for // a HWND m_wndSCBar.AddBarWnd(m_wndTree.m_hWnd, _T("Tree"));
5. Finally, invoke ActivateBar() to set the initially active bar.
m_wndSCBar.ActivateBar(0);
12.4.2 Using the Non-Windowed Shortcut Bar
When using the non-windowed version of the control, the shortcut bar is merely a visual entity that uses the device context provided by the host window to render itself. All client windows will be created as children of the hosting parent. When using the shortcut bar in this metaphor, it is up to the parent window to suitably expose a window handle in a manner that the shortcut bar under- stands. This is achieved through the SFL IVisualWindow interface that the shortcut bar expects the host window to implement.
1. Implement IVisualWindow in the parent class that will host the shortcut bar.
2. To the parent class add a data member of type SECATLShortcutBarHosted or SECMFCShortcutBarHosted.
3. When using ATL, plug this object into the ATL message chain using the CHAIN_MSG_MAP_MEMBER() macro.
BEGIN_MSG_MAP(CScribbleFrame)
Chapter 12 Framework-Tailored Shortcut Bars 201 MESSAGE_HANDLER(WM_CREATE, OnCreate) CHAIN_MSG_MAP_MEMBER(m_wndSCBar) CHAIN_MSG_MAP(baseClass) END_MSG_MAP()
4. When using MFC, override the CWnd::OnWndMsg() and CWnd::OnCmdMsg() functions in the host class and call the equivalent methods in the shortcut bar.
5. In the WM_CREATE handler, call the SECATLShortcutBarHosted::Create() method and pass in a pointer to the parent class implementing IVisualWindow.
m_wndSCBar.Create((IVisualWindow*)this, rcBar);
6. Provide a handler for the WM_SIZE message and set the shortcut bar's viewport size using the SECATLShortcutBarHosted::SetSize() function.
m_wndSCBar.SetSize(250, 750);
When using the windowed version of the shortcut bar, all client windows must be created as children of the shortcut bar. However, while using the non-windowed version of the control, child windows share a common parent with the shortcut bar.
12.4.3 Setting visual aspects of the shortcut bar
Various visual aspects of the shortcut bar such as the bar label font, background brush, back-color, bar icon, text color, text alignment etc., can be set using the appropriately titled methods that the class implements. Some of these are shown below.
// Sets a hashed background brush for the bar. The second // param is the bar index. m_wndSCBar.SetBarBrush(m_hHashBrush, 0);
// Sets the text color used for the bar labels m_wndSCBar.SetBarTextColor(RGB(0,0,255), 0);
// Sets the bar label font to m_hfBar. Specifying -1 sets the // particular aspect for all the bars. m_wndSCBar.SetBarFont(m_hfBar, -1);
// Displays, alongside the label, the IDI_ICON1 icon on bar 1. m_wndSCBar.SetBarIcon(1, IDI_ICON1);
// Center aligns the bar text. The other options available are // SEC_TABBAR_LBLALIGNLEFT & SEC_TABBAR_LBLALIGNRIGHT m_wndSCBar.SetLabelAlignment(SEC_TABBAR_LBLALIGNCENTER);
12.4.4 Adding a context menu to the shortcut bar
When the SEC_TABBAR_CNTXTMENU style is set, right-clicking anywhere on the bar portion causes the shortcut bar to generate a WM_TABBAR_CNTXTMENU notification message. Providing a handler for this message within the shortcut bar's notification target allows customization of the context menu.
The following excerpt demonstrates the usage.
202 // ATL Message map entry MESSAGE_HANDLER(WM_TABBAR_CNTXTMENU, OnBarContextMenu)
LRESULT OnBarContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // The lParam holds a pointer to the popup menu created by the // ShortcutBar. We can either directly modify this menu or, if // a menu resource is available, reinitialize this menu pointer // with a new menu. In this case, we will destroy the current // menu, create a new one based on our menu resource and reassign // lParam to refer to the new menu handle. This menu will be // destroyed later on by the Shortcut Bar.
if((int)wParam != -1) m_nCurrentHit = wParam; HMENU* phMenu = (HMENU*)lParam; DestroyMenu(*phMenu); *phMenu = GetSubMenu(LoadMenu(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDR_SHORTCUTBAR)), 0); return TRUE; }
12.5 Shortcut Bar Sample
The samples ATLShortcut and MFCShortcut provide a comprehensive illustration of the shortcut bar classes. These samples do not ship with the product. For information on how to obtain these samples, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 12 Framework-Tailored Shortcut Bars 203 204 Chapter 13 Tabbed Windows
13.1 Overview
Objective Toolkit includes a set of tabbed window classes that you can use as an alternative to MFC’s property sheet class. You can embed any type of window in the Objective Toolkit tabbed windows. For example, you can embed any CWnd-derived object, including CDialog and CView, into a tabbed window. For more information see the note in Section 13.5.8, “To create and add a view to the tabbed window.” In addition, you can embed the tabbed window anywhere. Tabbed windows use MFC’s document/view architecture. They allow you to add multiple views for single or multiple documents as tabs.
These classes provide a variety of customizable formats. There are two variants of the tabbed win- dow classes: a two-dimensional (Excel-like) format and a three-dimensional (Visual Studio-like) format. If you use the three dimensional format to create your tabbed window, you can place the tabs on the left, right, top, or bottom side of the control. The two-dimensional tabbed window classes restrict tab placement to the bottom of the control. Figure 103 – Example of the Two-Dimensional Tabbed Windows
Chapter 13 Tabbed Windows 205 Figure 104 – Example of the Three-Dimensional Tabbed Windows
206 13.2 The Tabbed Window Classes
A tabbed window is a small, rectangular window that draws tabs and processes mouse events. A tabbed window contains and manages the layout of a tab control and one or more sub-windows (or pages). When the user selects a tab with the mouse, the associated page is activated.
The following figure shows the relationship of the various tabbed window classes. Figure 105 – Objective Toolkit Tabbed Window Class Hierarchies
CWnd CWnd
SECTabControlBase SECTabWndBase
SECTabControl SECTabWnd
SEC 3DTabControl SEC 3DTabWnd
13.2.1 SECTabControlBase
SECTabControlBase is an abstract base class that defines the interface of a tab control. SECTabControlBase does not implement the tab control’s functionality or appearance. That is the responsibility of derived classes. SECTabControlBase defines the interface for a generic tab control. The derived classes add the implementation details necessary to define a specific look-and-feel.
13.2.2 SECTabControl
TheSECTabControl class implements a tab control with a two-dimensional look- and-feel that is similar to Microsoft Excel’s. This class handles drawing and activating the tabs for the tabbed window. Figure 106 – The SECTabControl Window
The SECTabControl inherits its interface from SECTabControlBase and adds the implementation details that define its appearance. Typically, you would not use this class directly. It is created as a child of the SECTabWnd object, and all its operations are performed through the SECTabWnd interface.
For each tab on the control, the SECTabControl references an SECTab object, which in turn refer- ences an associated CWnd.
Chapter 13 Tabbed Windows 207 13.2.3 SEC3DTabControl
TheSEC3DTabControl class implements a tab control with a three-dimensional look-and-feel that is similar to the Visual Studio’s tabbed windows. This class is responsible for drawing the tabs and handling tab activation. Figure 107 – The SEC3DTabControl Window
You can orient tabs so that they are on the top, bottom, left, or right of the tabbed window. The SEC3DTabControl inherits its interface from SECTabControlBase and adds the implementation details that define its appearance. Like SECTabControl, this class is typically not used directly. It is created as a child of the SEC3DTabWnd object, and all its operations are performed through the SEC3DTabWnd interface.
For each tab on the control, the SEC3DTabControl references an SEC3DTab object, which in turn references an associated CWnd.
13.2.4 SECTabWndBase
SECTabWndBase is an abstract base class that defines the interface of a tabbed window, which sup- ports the dynamic creation, renaming, and destruction of tabs. SECTabWndBase supports a rich set of operations that allows you to perform a number of actions on windows objects, such as adding, deleting, renaming, activating, scrolling into view, and more. In addition, you can customize the appearance of the tabs with alternative fonts and other features.
This class does not implement the tabbed window’s functionality or appearance. That is the responsibility of derived classes. SECTabWndBase defines the methods that operate on a generic tabbed window. The derived classes inherit the methods common to all tabbed windows and add the implementation details necessary to define a look-and-feel.
13.2.5 SECTabWnd
TheSECTabWnd class implements a tabbed window with a two-dimensional look and feel similar to the tabbed worksheet pages in Microsoft Excel. If an SECTabWnd does not have enough room to display each of its tabs, scroll buttons appear on the dialog (depending on the style settings) so the user can navigate to each of the tabs.
208 The SECTabWnd inherits its interface from SECTabWndBase and adds the implementation details that define its appearance. The SECTabWnd contains the SECTabControl, draws its own border, and activates tab-associated CWnds for display.
13.2.6 SEC3DTabWnd
TheSEC3DTabWnd class implements a tabbed window with a three-dimensional appearance that is similar to the Visual Studio’s tabbed windows. You can position tabs on the top, bottom, left, or right. SEC3DTabWnd does not display scroll buttons for navigating the tabs.
The SEC3DTabWnd inherits its interface from SECTabWndBase and adds the implementation details that define its appearance. The SEC3DTabWnd contains the SEC3DTabControl and is responsible for drawing its own border and activating the tab-associated CWnds for display.
Only the three-dimensional tab classes support styles that allow you to position tabs on the top, left, and right. These styles are not available in the two dimensional tab classes.
Chapter 13 Tabbed Windows 209 13.3 Tabbed Window Styles
You can apply the following tabbed window styles using the dwStyle parameter of the SECTabWnd::Create() method.
The following styles only apply to the SECTabWnd class. They have no effect on the SEC3DTabWnd class.
Table 34 – Tabbed Window Styles for SECTabWnd
2D Tabbed window (SECT- Description abWnd) Style
TWS_LEFTRIGHTSCROLL Only the left and right scroll buttons are shown. The user can only scroll the tabs to the left and right. There are no buttons for jumping to the first tab or to the last tab. This style is only valid for SECTabWnd. TWS_FULLSCROLL All four of the scroll buttons are shown in the lower left corner of the tabbed window. These four scroll buttons allow the user to scroll the tabs in the tabbed window to the first tab, to the last tab, a few pixels to the left, and a few pixels to the right. If you do not require the
You can apply the following tabbed window styles with the dwStyle parameter of SEC3DTabWnd::Create() method.
The following styles apply only to the SEC3DTabWnd class.
Table 35 – Tabbed Window Styles for SEC3DTabWnd
3D Tabbed window Description (SEC3DtabWnd) Style
TWS_TABS_ON_BOTTOM Places tab on the bottom of the window. This style is only valid for SEC3DtabWnd. TWS_TABS_ON_TOP Places tab on the top of the window. This style is only valid for SEC3DtabWnd. TWS_TABS_ON_LEFT Places tab on the left side of the window. This style is only valid for SEC3DtabWnd. TWS_TABS_ON_RIGHT Places tab on the right side of the window. This style is only valid for SEC3DtabWnd.
210 Table 35 – Tabbed Window Styles for SEC3DTabWnd (Continued)
3D Tabbed window Description (SEC3DtabWnd) Style
TWS_NOACTIVE_TAB_ By default, the active tab is drawn enlarged. The ENLARGED TWS_NOACTIVE_TAB_ENLARGED style flag dis- ables this feature.
TWS_DRAW_STUDIO_LIKE Provides tabs in the style similar to that in Visual Studio.
TWS_DRAW_3D_NORMAL Provides a normal 3D border for the client area.
TWS_DYNAMIC_ARRANGE_TABS Allows drag-and-drop rearrangements of the tabs.
Chapter 13 Tabbed Windows 211 13.4 Tab Control Notification Messages
The tab control notification messages provide feedback information from user generated events or various method calls. See Section 13.5.12 for information on using these notifications.
Table 36 – Tab Control Messages
Tab Control Definition Description Message
TCM_TABSEL WM_USER+1000 Sent to the parent window when a tab is selected as the active tab. This can occur as a result of a left button click on the tab or as a result of a call to the ActivateTab() or SelectTab() methods.
TCM_TABDBLCLK WM_USER+1001 The tab control sends this notification to the tab window when the mouse is double-clicked on a tab. This message needs to be handled in a derived SECTabWnd/SEC3DTabWnd class. TCM_TABSELCLR WM_USER+1002 The tab control sends this notification to the tab window when the tab selection is cleared. This occurs when the ClearSelection() method, which marks all the tabs as unse- lected, is called.
TCM_TABREACTIVATE WM_USER+1003 The tab control sends this notification to the tab window (not the parent) when the mouse is clicked on a tab that is already selected as the active tab or by a call to the ReactivateTab() method. This message can be directly handled in a derived SECTabWnd/SEC3DTabWnd class. It can also be overridden by the SECTabWndBase::OnReActivateT ab() virtual function.
212 13.5 Using SECTabWnd and SEC3DTabWnd
13.5.1 To add SECTabWnd or SEC3DTabWnd to a frame window
The steps for adding SECTabWnd and SEC3DTabWnd are identical.
1. Add an SECTabWnd (orSEC3DTabWnd) data member to your CFrameWnd-derived class. For example:
SECTabWnd m_tabWnd;
If your application Then: is:
SDI-based Add the data member to your CMainFrame class.
MDI-based Add the data member to your CMDIChildWnd descendant. FDI-based Add the data member to your SECFDIChildWnd descendant.
2. Override the OnCreateClient() method of the frame class and call the tabbed window Create() method to create the tabbed window. For example:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext *pContext) { BOOL rtn_val; lpcs; //UNUSED
rtn_val = m_tabWnd.Create(this); ... }
3. In the OnCreateClient() frame class method, add the views or any CWnd-derived objects to the tabbed window object using the AddTab() method.
For example, the following line of code creates a new instance of a CView-derivative and inserts it into the tabbed window.
m_tabWnd.AddTab(RUNTIME_CLASS(CDemoView1), "Tab One", pContext, nID);
The next line inserts any pre-existing CWnd-derived object into the tabbed window.
m_tabWnd.AddTab(pWnd, "Tab Two");
Chapter 13 Tabbed Windows 213 4. As the last step in your OnCreateClient() override, activate and scroll into view the tab that you want to be selected initially. For example:
m_tabWnd.ActivateTab(0); m_tabWnd.ScrollToTab(0);
13.5.2 To add a tabbed window to a dialog
1. Edit the dialog resource in the resource editor.
2. Add an arbitrary control (for example, an edit control or a static control). Position and size it where you want the tabbed window, and give the control a unique control identifier.
3. In the OnInitDialog() handler for the dialog, retrieve the rectangle for the control and window you just added. For example:
CWnd* pWnd = GetDlgItem(uiControlID); CEdit* pwndEdit=(CEdit*)pWnd; // Retrieve the previous window in the tab order // and the rectangle to use for the call to create // (in parent client-area coordinates). CWnd* pwndPrev = pwndEdit->GetWindow(GW_HWNDPREV); CRect rc; pWnd->GetWindowRect(&rc); this->ScreenToClient(&rc);
// Now we no longer need the original window and can // safely destroy it. pWnd->DestroyWindow();
4. Now, call the tabbed window Create() method. Then, set the size, position, and tab order for the control.
if (m_tabWnd.Create(this)) { SetWindowPos(pwndPrev, rc.TopLeft().x, rc.TopLeft().y, rc.Width(), rc.Height(), 0); }
13.5.3 Removing the 2D Tab Scroll Buttons
In the call to SECTabWnd::Create(), leave off the TWS_FULLSCROLL or TWS_LEFTRIGHTSCROLL flags.
13.5.4 To put 3D tabs on the side or top of the tabbed window
1. Ensure that the font used on the tabs is a True Type font, such Arial or Times New Roman. For more information, see Section 13.5.11, “To change the font of a tab.”
214 2. In the call to SEC3DTabWnd::Create(), specify one of the following style flags:
TWS_TABS_ON_BOTTOM
TWS_TABS_ON_TOP
TWS_TABS_ON_LEFT
TWS_TABS_ON_RIGHT
For example:
rtn_val = m_tabWnd.Create(this, WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | TWS_FULLSCROLL | TWS_TABS_ON_LEFT);
13.5.5 To enable scroll bars in the 2D tabbed window
1. The contained object for the tab must be CScrollView-derived. Override CWnd::GetScrollBarCtrl() for the contained window class. For example:
CScrollBar* CMyScrollView::GetScrollBarCtrl(int nBar) const { ASSERT(GetParent()-> IsKindOf(RUNTIME_CLASS(SECTabWnd))); return ((SECTabWnd*)GetParent())-> GetScrollBar(nBar); }
2. For each tabbed window, pass WS_HSCROLL or WS_VSCROLL as required in the dwStyle parameter of the SECTabWndBase::SetScrollStyle() member function. For example:
m_tabWnd.SetScrollStyle(nTab, WS_HSCROLL | WS_VSCROLL);
13.5.6 To add keyboard accelerator support
1. Derive a class from SECTabWnd/SEC3DtabWnd and add handlers for the WM_CHAR and WM_KEYDOWN messages.
2. In OnChar() or OnKeyDown() or both, provide your own tab-activation code. Within the handler, you can use the SECTabWndBase::ActivateTab() method to activate a specific tab.
If the tab contains CView derived class objects:
The default message routing mechanism sends the keyboard messages to the window with the keyboard focus so the active view receives the messages.
Handle the message(s) in the view/control class contained in the tab to redirect the message(s) to the tabbed window. This ensures that your tab-window's handler is called. void CDemoView1::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { nChar; //UNUSED nRepCnt; //UNUSED nFlags; //UNUSED
Chapter 13 Tabbed Windows 215 // Forward message to parent ASSERT(GetParent()-> IsKindOf(RUNTIME_CLASS(SECTabWndBase)));
MSG msg = *GetCurrentMessage(); if (GetParent()) GetParent()->SendMessage( msg.message, msg.wParam, msg.lParam); }
If the tabbed window contains CDialog/CFormView derived class objects:
When a CDialog/CFormView derived object is the active window, the application sends keyboard messages to the control within the dialog that has the focus by default. You need to subclass the control and redirect the keyboard messages to the tabbed window.
13.5.7 To add a window to the tabbed window
Call the overloaded SECTabWndBase::AddTab() method with the following declaration.
void AddTab(CWnd* pWnd, LPCTSTR lpszLabel, HICON hIcon = NULL);
If the tab is removed at run time, don’t forget to destroy the associated CWnd. See Section 13.5.9.
13.5.8 To create and add a view to the tabbed window
Call the overloaded SECTabWndBase::AddTab() method with the following declaration.
CWnd* AddTab(CRuntimeClass* pViewClass, LPCTSTR lpszLabel, CCreateContext* pContext = NULL, HICON hIcon = NULL, UINT nID = -1);
If the tab creation is within CFrameWnd::OnCreateClient():
Use the pContext parameter passed to the OnCreateClient() method in the AddTab() method call.
If the tab creation is not occurring within CFrameWnd::OnCreateClient():
Create a CCreateContext on the stack and pass it to the AddTab() method call. For example:
void CMyFrameWnd::OnSheetNew() { CCreateContext context; context.m_pCurrentFrame = this; context.m_pCurrentDoc = GetDocToUse(); context.m_pNewViewClass = RUNTIME_CLASS(CMyView); context.m_pNewDocTemplate = GetDocTemplateToUse(); m_wndTab.AddTab(RUNTIME_CLASS(CMyView), &context); }
216 The implementations of the GetDocToUse() and GetDocTemplateToUse() methods are applica- tion-specific.
In general, you can embed a tabbed window anywhere. This is not true if the tabbed window contains views. You cannot embed a view in a tabbed window that is, in turn, embedded in a control bar (docking window) or a dialog. However, you can embed a tabbed window containing views into a view contained in a frame using the docking views architecture.
If the tab is removed at run time, don’t forget to destroy the associated CView. See Section 13.5.9.
13.5.9 To remove a tab
Call the RemoveTab() method. Don’t forget to destroy the contained CWnd. For example:
// Don't just delete the tab, destroy the associated // window too. if (m_tabWnd.GetTabInfo(nActiveTab, lpszLabel, bSelected, pActiveWnd, pExtra)) { pActiveWnd->ShowWindow(SW_HIDE); pActiveWnd->SendMessage(WM_CLOSE); }
13.5.10To access the CWnd associated with a tab
Call the GetTabInfo() method, which is defined as follows:
// Returns information about the tab with the supplied index. BOOL GetTabInfo(int nIndex, LPCTSTR& lpszLabel, BOOL& bSelected, CWnd*& pWnd, void*& pExtra);
For example: m_tabWnd.GetTabInfo(nActiveTab, lpszLabel, bSelected, pActiveWnd, pExtra);
Chapter 13 Tabbed Windows 217 13.5.11To change the font of a tab
Call one of the following font accessor methods.
Font accessor method Description
Get/SetFontActiveTab() Sets an active tab's current font to the specified font.
Get/SetFontInactiveTab() Sets an inactive tab's current font to the specified font.
If you are specifying the font for a tab on a 3D tabbed window and the tabs are placed on either the left or right side of the tabbed window, the font must be a True Type font.
13.5.12To receive user event notifications from the tabbed window
Add a message-map entry and message-handler member function to the parent class for each mes- sage. See Section 13.4. Each message-map macro entry takes the following form:
ON_MESSAGE(
memberFxn is the name of the parent member function you wrote to handle the notification and
TCM_TABSEL
TCM_TABDBLCLK
TCM_TABSELCLR
TCM_TABREACTIVATE
The parent's function prototype is as follows:
afx_msg LRESULT memberFxn(WPARAM wParam, LPARAM lParam);
wParam parameter contains the index of the activated tab. If this handler is called in response to a SelectTab() event, then the wParam is the index of the currently active tab.
13.5.13To get a pointer to the SECTabWnd from a contained view
Use the following code:
pTabWnd = (SECTabWnd*)pView->GetParent(); ASSERT_KINDOF(SECTabWnd, pTabWnd);
218 13.5.14To insert a splitter window into a tabbed window
1. Create the tabbed window.
m_tabWnd.Create(this);
2. Create the splitter window. Specify the tabbed window as its parent.
m_wndSplitter.CreateStatic(&m_tabWnd, 1, 2);
3. Insert your child windows into the splitter window.
m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CDemoView2), CSize(225,100), pContext); m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CDemoView2), CSize(225,100), pContext);
4. Insert the splitter window into the tabbed window.
m_tabWnd.AddTab(&m_wndSplitter, "Tab Two");
There is a known limitation in SECTabWnd, which is particularly problematic if you are using the SECTabWnd class in conjunction with a splitter window. You can create the tabbed win- dow with or without scroll bars, but they cannot be dynamically shown or hidden. If one tab requires scroll bars and another does not, the SECTabWnd class does not show and hide the scroll bars appropriately.
13.5.15Problem with Tabbed Windows in Docking Views
If you are using a tabbed window in conjunction with the docking views component of Objective Toolkit, you may experience a problem with view activation. SECTabWndBase::Create() asserts if the tab window is being added as a child of a docking view that already has an ID of AFX_ID_PANE_FIRST. A tab window is expected to have this ID if the tab window consumes the cli- ent area of an MDI child frame. In other words, it is to act as a container for one or more views that would normally otherwise have this ID. The same is true if the tab window consumes the client area in the SDI scenario.
When calculating the layout of the client area, MFC looks for a window with an ID of AFX_ID_PANE_FIRST. In a MDI application, the view window is typically the one with this ID. If multiple windows with this ID exist, view activation behavior becomes erratic.
To fix this problem, create a unique ID for the tab window and specify it during the call to Create(). For example:
VERIFY (m_wndTab.Create(this, WS_CHILD|WS_VISIBLE|TWS_TABS_ON_BOTTOM, ID_MYTAB)); // some unique id
Chapter 13 Tabbed Windows 219 13.6 Tabbed Window Sample
The Objective Toolkit sample tabdemo demonstrates the use of the SECTabWnd and SEC3DTabWnd classes. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
220 Chapter 14 Tree Control & Tree View
14.1 Overview
The Objective Toolkit tree control and tree view classes extend the functionality of the CTreeCtrl common tree control. A tree control is a window that displays a hierarchical list of items, such as the files and directories on a disk or the entries in an index.
The Win32 common tree control has some limitations. Because no source code is available, it lacks extensibility. It isn’t object-oriented and no hooks were introduced into the drawing process until Comctl32.dll. It is difficult to implement multiple selection. Additionally, CTreeCtrl is a very thin wrapper to the common tree control so it is difficult to extend as well.
Objective Toolkit’s tree control adds support for multiple selection, an integrated grid with a resiz- able header row, adjustable cell height, word wrap, tool tips, various font and color options through an architecture designed for extensibility. Options are controlled by styles that permit fea- tures to be enabled or disabled at run time.
Objective Toolkit also supports overlay images and state images. Editing labels in a multi column tree is possible if the TVS_EDITLABELS style and LVXS_HILIGHTSUBITEMS extended style is set. See the STATE sample.
Objective Toolkit also includes a view class, SECTreeView. Unlike CTreeView, SECTreeView truly is a tree. You can override any of its virtual functions the same way you would an SECTreeCtrl. You can change the text color in your SECTreeView/Ctrl derived class by overriding PickTextColors(). You can change the font for a particular item in that same class by overriding PickTextFont(). The preceding functions are the same functions that you would overload if you were using SECTreeCtrl.
Painting in the tree control is optimized for performance. The control is not necessarily invalidated after every insertion or deletion of items so that you can add or remove many items in a batch. See Section 14.8.14.
Chapter 14 Tree Control & Tree View 221 14.2 The Tree Control Classes
As the following hierarchy suggests, templatized base classes provide identical functionality to the tree control and tree view classes. Figure 108 – The Objective Toolkit Tree Control Class Hierarchy CWnd
SECListClient
SECListBaseC
SECListCtrl
SECTreeBaseC
SECTreeCtrl
14.2.1 SECTreeCtrl
The SECTreeCtrl class is not derived from CTreeCtrl. It is ultimately CWnd-derived. Multi-column support is provided through the SECListCtrl class.
14.2.2 SECListCtrl
This class supports the SECTreeCtrl class. Although the SECTreeCtrl class manages the first col- umn, which is the tree structure itself, the SECListCtrl class manages any additional columns in the tree control. This class is not supported outside the scope of the SECTreeCtrl class.
222 14.3 The Tree View Classes
The hierarchy for the tree view contains many classes; however, typically you only need to work with SECTreeView and SECListView. Figure 109 – The Objective Toolkit Tree View Class Hierarchy
CView
SECListClient
SECListBaseV
SECListView
SECTreeBaseV
SECTreeView
14.3.1 SECTreeView
The SECTreeView class has the same core code as SECTreeCtrl with the exception of its base classes. In fact, this class has the same API as an SECTreeCtrl with the addition of CView inherited mem- bers. Like the SECTreeCtrl class, SECTreeView multi-column support is provided through the supporting SECListView class. The SECTreeView also has print and print preview support.
14.3.2 SECListView
This is a supporting class for the SECTreeView class. Although the SECTreeView class manages the first column, which is the tree structure itself, the SECListView class manages any additional col- umns in the tree control. This class is not supported outside the scope of the SECTreeView class.
Chapter 14 Tree Control & Tree View 223 14.4 Tree Control Data Structures
The SECTreeCtrl and SECTreeView classes utilize the same data structures used by the CTreeCtrl class. The use of these data structures does not promote object-oriented programming. However, they are compatible with CTreeCtrl.
14.4.1 TV_ITEM
The TV_ITEM structure retrieves or specifies the attributes of a tree view item. It is defined as follows:
typedef struct _TV_ITEM { tvi UINT mask; // what is valid in this structure HTREEITEM hItem; // handle of this item UINT state; // selected, expanded, drop // highlighted, // also state and overlay // image indexes // via obscure macros // like INDEXTO… // that map to bit fields UINT stateMask; // what is valid in the “state” // member LPSTR pszText; // text or LPSTR_TEXTCALLBACK int cchTextMax; // only used when modifying text int iImage; // normal image index // or I_IMAGECALLBACK int iSelectedImage; // selected image # // or I_IMAGECALLBACK int cChildren; // # of children // or I_CHILDRENCALLBACK LPARAM lParam; // 32-bit user defined data } TV_ITEM;
For a complete description of the members of this structure, refer to the MSDN documentation for TV_ITEM or TVITEM, which is identical to TV_ITEM, but follows current naming conventions.
14.4.2 NM_TREEVIEW
The NM_TREEVIEW structure is used within the tree control message notification mechanism. It con- tains information about a specific tree view notification message. A pointer to this data structure is included as a parameter accompanying the WM_NOTIFY message. It is defined as follows:
typedef struct tagNMTREEVIEW { NMHDR hdr; UINT action; TVITEM itemOld; TVITEM itemNew; POINT ptDrag; } NMTREEVIEW, FAR *LPNMTREEVIEW;
224 For a complete description of the members of this structure, refer to the MSDN documentation for NM_TREEVIEW or NMTREEVIEW, which is identical to NM_TREEVIEW, but follows current naming conventions.
14.4.3 TV_HITTESTINFO
This structure contains information for determining the location of a point relative to a tree view control. It is defined as follows:
typedef struct _TVHITTESTINFO { POINT pt; // client coordinates of point to test UINT flags; // info about the results of hit test
HTREEITEM hItem; // handle of item that occupies point } TV_HITTESTINFO, FAR *LPTV_HITTESTINFO;
This structure is used as an optional parameter of the HitTest() method. For more information about the members of this structure, refer to the MSDN documentation for TV_HITTESTINFO or TVHITTESTINFO, which is identical to TV_HITTESTINFO, but follows current naming conventions. Refer to the documentation for SEC_TREECLASS::HitTest() in the Objective Toolkit Class Reference.
Chapter 14 Tree Control & Tree View 225 14.5 Tree Item States
The tree node states are represented by the state member of TV_ITEM. By retrieving the TV_ITEM structure for any given item, you can test the state of that item. The following figures show an example tree control and an example tree view. Figure 110 – Example Objective Toolkit Tree Control and Tree Item States
226 Figure 111 – Example Objective Toolkit Tree View and Tree Item States
Chapter 14 Tree Control & Tree View 227 14.6 Tree Control/Tree View Styles
The styles of the tree control are controlled by style flags. The user can modify the styles at run time.
Table 37 – Tree Control Style Flags
Tree Control Style Flag Description
TVS_DISABLEDRAGDROP Prevents the tree view control from sending TVN_DRAGDROP notification messages.
TVS_EDITLABELS Allows the user to edit the labels of tree view items.
TVS_HASBUTTONS Displays plus (+) and minus (-) buttons next to parent items. The user clicks the buttons to expand or collapse a parent item's list of child items. To include buttons with items at the root of the tree view, you need to specify TVS_LINESATROOT.
TVS_HASLINES Uses lines to show the hierarchy of items.
TVS_LINESATROOT Uses lines to link items at the root of the tree view control. This value is ignored if TVS_HASLINES is not also specified.
TVS_SHOWSELALWAYS Causes a selected item to remain selected when the tree view control loses focus.
TVXS_COLUMNHEADER Displays the column header. This style removes the LVS_NOCOLUMNHEADER style so that all the columns display headers.
TVXS_FLYBYTOOLTIPS Enable tooltips.
TVXS_MULTISEL Enables the user to select multiple items.
TVXS_WORDWRAP Enables word wrapping of text if the first col- umn is narrow. Specifying this style automatically enables the LVXS_WORDWRAP style, affecting all columns.
LVS_SINGLESEL Disables multiple selection of items.
LVXS_FITCOLUMNSONSIZE The item column fills the width not occupied by subitem columns.
LVXS_FLYBYTOOLTIPS Enable tooltips for additional columns. The TVXS_FLYBYTOOLTIPS style automatically enables this style.
LVXS_HILIGHTSUBITEMS
LVXS_LINESBETWEENCOLUMNS Paints vertical lines between columns.
LVXS_LINESBETWEENITEMS Paints horizontal lines between items.
228 Table 37 – Tree Control Style Flags (Continued)
Tree Control Style Flag Description
LVXS_NOGROWCOLUMNONDELETE Prevents automatic resizing of column 0 when a column is deleted.
LVS_NOCOLUMNHEADER Specifies that additional columns do not display column headers. This style is automatically removed by specifying the TVXS_COLUMNHEADER style, which causes all columns to display headers.
LVXS_WORDWRAP Enables word wrapping of item text if the col- umn is narrow. The TVXS_WORDWRAP style automatically enables this style.
LVXS_OWNERDRAWVARIABLE Reserved.
The following styles are not supported by SECTreeCtrl or SECTreeView:
TVS_CHECKBOXES
TVS_FULLROWSELECT (use LVXS_HILIGHTSUBITEMS)
TVS_INFOTIP
TVS_NONEVENHEIGHT
TVS_NOSCROLL (use LVS_NOSCROLL)
TVS_NOTOOLTIPS (use LVXS_FLYBYTOOLTIPS/TVXS_FLYBYTOOLTIPS)
TVS_RTLREADING
TVS_SINGLEEXPAND
TVS_TRACKSELECT
The following figure illustrates some of the standard styles that the Objective Toolkit tree control shares with CTreeCtrl in addition to TVXS_FLYBYTOOLTIPS.
Chapter 14 Tree Control & Tree View 229 Figure 112 – Examples Tree Control Styles
The following figure illustrates some of the extended styles.
230 Figure 113 – Examples Tree Control Extended Styles
Chapter 14 Tree Control & Tree View 231 14.7 Tree Control Notifications
The Objective Toolkit tree control supports a number of notifications messages sent in the form of a WM_NOTIFY message.
Table 38 – Tree Control Notifications
Notification Description
TVN_BEGINDRAG Notifies a tree view control's parent window that a drag-and-drop operation involving the left mouse button is being initiated.
TVN_BEGINLABELEDIT Notifies a tree view control's parent window about the start of label editing for an item.
TVN_ENDLABELEDIT Notifies a tree view control's parent window about the end of label editing for an item.
TVN_ITEMEXPANDED Notifies a tree view control's parent window that a parent item's list of child items has expanded or collapsed.
TVN_ITEMEXPANDING Notifies a tree view control's parent window that a parent item's list of child items is about to expand or collapse.
TVN_SELCHANGED Notifies a tree view control's parent window that the selection has changed from one item to another.
TVN_SELCHANGING Notifies a tree view control's parent window that the selection is about to change from one item to another.
TVN_SETDISPINFO Notifies a tree view control's parent window that it must update the information it maintains about an item.
TVN_GETDISPINFO Requests that a tree view control's parent window provide information needed to display or sort an item.
TVN_KEYDOWN Notifies a tree view control's parent window that the user pressed a key and the tree view control has the input focus.
TVN_DELETEITEM Notifies a tree view control's parent window that an item is being deleted.
TVN_BEGINLABELEDIT Notifies a tree view control's parent window about the start of label editing for an item.
LVN_BEGINLABELEDIT Notifies a list view control's parent window about the start of label editing for an item.
232 Table 38 – Tree Control Notifications (Continued)
Notification Description
LVN_DELETEITEM Notifies a list view control's parent window that an item is about to be deleted.
LVN_ENDLABELEDIT Notifies a list view control's parent window about the end of label editing for an item.
LVN_GETDISPINFO Sent by a list view control to its parent window. It is a request for the parent window to provide information needed to display or sort a list view item.
LVN_INSERTITEM Notifies a list view control's parent window that a new item was inserted.
LVN_KEYDOWN Notifies a list view control's parent window that a key has been pressed.
Chapter 14 Tree Control & Tree View 233 14.8 Using the Tree Control Classes
The following sections describe how to use the tree control and tree view classes.
14.8.1 To create a tree control in a dialog
1. In the Visual Studio resource editor, create a tree control resource on the dialog resource.
2. Instantiate an SECTreeCtrl object as a member of your dialog class.
3. In the OnInitDialog() method of your dialog class, call SubclassTreeCtrlId() on the SECTreeCtrl instance. For example:
m_pTreeCtrl->SubclassTreeCtrlId( IDC_TREE, this );
14.8.2 To create a tree control dynamically
1. Create a unique control ID for the tree control. In Visual Studio, you can create an ID with the Resource Includes dialog.
2. Instantiate an SECTreeCtrl object.
3. Call the Create() method and specify the desired styles, rectangle, and parent. For example:
DWORD dwStyle = TVS_SHOWSELALWAYS | TVS_HASBUTTONS | TVS_LINESATROOT | TVS_HASLINES | TVS_EDITLABELS | TVS_SHOWSELALWAYS | TVS_DISABLEDRAGDROP | WS_CHILD | WS_VISIBLE;
DWORD dwStyleEx = TVXS_MULTISEL | TVXS_FLYBYTOOLTIPS | LVXS_HILIGHTSUBITEMS;
m_pTreeCtrl->Create( dwStyle, dwStyleEx, rect, this, IDC_TREE);
4. If you are creating a tree control inside a control bar or other resizable window, remember to override the OnSize() method to resize the tree control with the parent window.
void CMyControlBar::OnSize(UINT nType, int cx, int cy) { SECControlBar::OnSize(nType, cx, cy);
if ( ::IsWindow(m_tree) ) m_tree.SetWindowPos( NULL, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER ); }
234 14.8.3 To add a tree item
1. Instantiate and initialize a TV_ITEM structure for the tree item to be added. For example the following initializes a TV_ITEM structure to be inserted at the root level of the tree.
TV_ITEM tvi; memset(&tvi,0,sizeof(tvi)); tvi.mask = TVIF_IMAGE|TVIF_TEXT|TVIF_SELECTEDIMAGE; tvi.pszText = LPSTR_TEXTCALLBACK; tvi.iImage = I_IMAGECALLBACK; tvi.iSelectedImage = I_IMAGECALLBACK;
2. Call the InsertItem() method using a TV_INSERTSTRUCT structure as a parameter.
TV_INSERTSTRUCT tvis; memmove(&(tvis.item), &tvi, sizeof(TV_ITEM)); tvis.hParent = TVI_ROOT; tvis.hInsertAfter = TVI_LAST; HTREEITEM htiItem1 = m_pTreeCtrl-> InsertItem(&tvis );
3. Alternatively, call one of the overloaded InsertItem() methods.
HTREEITEM htiitem2 = m_pTreeCtrl->InsertItem(LPSTR_TEXTCALLBACK, I_IMAGECALLBACK, I_IMAGECALLBACK, TVI_ROOT, TVI_LAST );
14.8.4 To create multiple columns
1. Call the InsertColumn() method.
m_pTreeCtrl->InsertColumn( 1 /*0-based column index*/, "Attendance", LVCFMT_CENTER, 40 /*width*/ ); m_pTreeCtrl->InsertColumn( 2 /*0-based column index*/, "Grade", LVCFMT_CENTER, 40 /*width*/ );
2. If you want, you can mark all items as needing a remeasurement when a WM_PAINT occurs, and invalidate the control.
m_pTreeCtrlX->ReMeasureAllItems(); m_pTreeCtrlX->Invalidate();
Chapter 14 Tree Control & Tree View 235 14.8.5 To set the text on subitems of multi-column trees
In trees with multiple columns, the objects called subitems are managed by the items of the tree (in column 0). These subitems control what is displayed in the additional columns.
Method 1
1. Handle the LVN_GETDISPINFO notification.
2. In the handler for the LVN_GETDISPINFO notification, manage the subitem text storage your- self and then provide it to the control on demand via the callback.
This is the default method demonstrated in the TREEDEMO sample. This method provides maximum performance in large trees with many columns of data.
Method 2
1. Call StoreSubItemText(TRUE) after creation to enable the tree control to manage subitem text storage for you.
2. Call the SetItemText() or SetItemString() methods to set the text directly.
This is an easier approach than using the callback method, but it is not as scalable for large trees when performance is an issue. This method is demonstrated in the STATE sample.
14.8.6 To create a standard image list for tree items
Call the SetImageList() method.
SetImageList( CImageList*, TVSIL_NORMAL);
Use of an image list is optional. If state images are also associated with a tree item, you can assign them different widths than the standard image, but not different heights.
14.8.7 To create a state image list for tree items
Call the SetImageList with the TVSIL_STATE flag.
SetImageList( CImageList*, TVSIL_STATE );
A state image is an additional image drawn to the left of the normal image like a check box. State images are optional. If the standard images are also associated with a tree item, they can be differ- ent widths than the state image, but must be the same height.
14.8.8 To create a tree item with a state image
1. Create a state image list containing each state image to be displayed. See Section 14.8.7.
2. Instantiate a TV_ITEM data structure. For example,
236 TV_ITEM tvi;
3. Specify the TVIF_SELECTEDIMAGE flag in the mask data member. For example:
tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_SELECTEDIMAGE | TVIF_STATE;
4. Specify the state image and TVIS_STATEIMAGEMASK to the state and stateMask data mem- bers, respectively.
tvi.state = INDEXTOSTATEIMAGEMASK(1); tvi.stateMask = TVIS_STATEIMAGEMASK;
5. Specify any additional data members as indicated by any other flags included in the mask data member.
tvi.pszText = _T("Line Species 1"); tvi.iImage = m_idiFolderClosed; tvi.iSelectedImage = m_idiFolderClosed; tvi.lParam = (LPARAM)m_secTree.m_hWnd;
6. Instantiate a TV_INSERTITEM structure and then initialize the item data member with a pointer to the TV_ITEM data structure.
TV_INSERTSTRUCT tvis;
7. Fill in the remaining TV_INSERTITEM data members.
tvis.item = tvi; tvis.hParent = TVI_ROOT; tvis.hInsertAfter = TVI_LAST;
8. Create the tree item with the InsertItem method.
HTREEITEM htreeitem = m_tree.InsertItem(&tvis);
14.8.9 To change a state image on a tree item
1. Create a state image list containing each state image to be displayed. See Section 14.8.7, “To create a state image list for tree items.”
2. Instantiate a TV_ITEM structure and update the data members to prepare for a request for the state image of the item. For example:
TV_ITEM tvi; tvi.hItem = htiItemClicked; tvi.mask = TVIF_STATE | TVIF_HANDLE; tvi.stateMask = TVIS_STATEIMAGEMASK;
3. Request the state image using the GetItem() method by passing the address of the TV_ITEM structure as a parameter.
m_secTree.GetItem(&tvi); UINT state = tvi.state & TVIS_STATEIMAGEMASK;
4. Change the state image in the TV_ITEM structure to the image.
int index = (state == INDEXTOSTATEIMAGEMASK(1)) ?
Chapter 14 Tree Control & Tree View 237 2 : // checked 1); // not checked
tvi.state = INDEXTOSTATEIMAGEMASK(index);
5. Call SetImage() to have the tree control use the new image.
m_tree.SetItem(&tvi);
14.8.10To add an overlay image to a tree item
1. Obtain a HTREEITEM handle for the tree item. For example:
HTREEITEM hti = m_tree.InsertItem(&tvi);
2. Instantiate a TV_ITEM structure and update the members for the desired overlay image.
TV_ITEM tvi; tvi.hItem = hti; tvi.mask = TVIF_HANDLE | TVIF_STATE; tvi.stateMask = TVIS_OVERLAYMASK; tvi.state = INDEXTOOVERLAYMASK( iImage );
3. Call the SetItem() method using the TV_ITEM as a parameter.
m_secTree.SetItem( &tvi );
14.8.11To find out which items are selected
Call the GetSelectionArray() method.
pArrSelected = m_secTree.GetSelectionArray();
14.8.12To specify different colors for tree items
1. Override PickTextColor().
2. In the PickTextColor() override, assign the rgbText member of the LvPaintContext structure supplied as a parameter. For example, the following code is in the Objective Tool- kit Build Wizard.
void CMyTreeView::PickTextColors(LvPaintContext* pPC) { ASSERT(pPC); SECTreeView::PickTextColors(pPC);
if(pPC->lvi.iSubItem == 0) // subitem (column) number 0 { // Inside tree column, get a convenient context. TvPaintContext* pTvPC = (TvPaintContext*)pPC;
// Check the properties of tree item (pTvPC->tvi), // and change color accordingly. For example,
238 // to change the color of root nodes: HTREEITEM hParent=GetParentItem(pTvPC->tvi.hItem); if(hParent == NULL) { pTvPC->rgbText= m_rootColor;
if ( GetFocus()== this && (pTvPC->lvi.state & LVIS_SELECTED) ) pTvPC->rgbTextBkgnd = RGB(255, 255, 0); // highlight } } }
14.8.13To specify different fonts for tree items
1. Override the PickTextFont() method.
2. In the PickTextFont() override, assign the pFont member of the LvPaintContext struc- ture supplied as a parameter. For example, the following code is in the Objective Toolkit Build Wizard.
void CMyTreeView::PickTextFont(LvPaintContext* pPC) { ASSERT(pPC); SECTreeView::PickTextFont(pPC);
if(pPC->lvi.iSubItem == 0) // subitem (column) number 0 { // Inside tree column, get a convenient context. TvPaintContext* pTvPC = (TvPaintContext*)pPC;
// Check the properties of tree item (pTvPC->tvi), // and change font accordingly. For example, // to change the font of root nodes: HTREEITEM hParent=GetParentItem(pTvPC->tvi.hItem); if(hParent == NULL) pTvPC->pFont= &m_fontRoot; } }
14.8.14To update the tree control
1. Call the following methods after making changes to the tree control/view.
ReMeasureAllItems(); Invalidate();
2. To update the GUI after every insert/delete, call EnableRedrawAfterInsert(TRUE). The dialog portion of the TREEDEMO sample demonstrates this. The Expand() function has an additional BOOL parameter to control redrawing of expanded/collapsed nodes.
Chapter 14 Tree Control & Tree View 239 14.8.15To incorporate SECTreeCtrl into an application already using CtreeCtrl
In the header file, locate your instance of CTreeCtrl.
1. Change this from CTreeCtrl to SECTreeCtrl.
2. Population of the tree is the same as for CTreeCtrl.
SECTreeCtrl is for the most part drop-in compatible with the CTreeCtrl, but not when you start changing or adding behaviors such as drag scrolling.
240 14.9 Tree Control Samples
See the samples TreeDemo and DynaTree in the
The DynaTree sample shows drag-and-drop using drag images and demonstrates using children on demand.
The State sample shows the use of state images and overlay images. Multi-column tree controls can store the subitem text internally if the StoreSubItemText( TRUE ) function is called after creation so that you can call SetItemText() or SetItemString() on subItems without using the LVN_GETDISPINFO callback. This feature is demonstrated in this sample. This sample also shows multi-column editing.
The following is a possible creation scenario for a multi-column tree that supports multiple selec- tion, full row select, label editing, auto column sizing, and tooltips.
// standard tree control and window styles go here DWORD dwStyles = TVS_SHOWSELALWAYS|TVS_HASBUTTONS | TVS_LINESATROOT|TVS_HASLINES | TVS_EDITLABELS|TVS_SHOWSELALWAYS | TVS_DISABLEDRAGDROP|WS_CHILD;
// Stingray extended styles go here DWORD dwStylesEx = TVXS_MULTISEL | TVXS_FLYBYTOOLTIPS | LVXS_HILIGHTSUBITEMS;
m_secTree.Create( dwStyles, dwStylesEx, rect, this, IDC_SECTREE);
/* make the columns resize if the window width changes. This is an alternative to having a horizontal scroll bar. */
m_secTree.ModifyListCtrlStyleEx( 0, LVXS_FITCOLUMNSONSIZE );
/* you can set the image and text foreground/background colors for selected and normal states */ COLORREF clrBack = RGB( 192, 220, 192);
// change the background color m_secTree.SetBkColor( clrBack ); // change the selected icon background color m_secTree.SetSelIconBkColor( clrBack ); // change the normal icon background color m_secTree.SetIconBkColor( clrBack ); // change the normal text color m_secTree.SetTextColor( RGB( 10, 10, 10 ) ); // change the selection text background color m_secTree.SetSelTextBkColor( ::GetSysColor(COLOR_INACTIVECAPTION) );
Chapter 14 Tree Control & Tree View 241 // change the selection text color m_secTree.SetSelTextColor( RGB( 255, 255, 255 ) );
/*as an alternative, you can skip all the color initialization and simply use the default system colors. In that case, you will want system color changes to be shown in the control. Do this by calling EnableSysColorTracking( TRUE ); */
//turn on the header control m_secTree.EnableHeaderCtrl( TRUE ); // set the header text for column 0 m_secTree.SetColumnHeading(0, _T("Object") ); // set the column width to 60% of the // view client rect. m_secTree.SetColumnWidth(0, (int)(rect.Width() * .60)); // add another column. Every tree item will // have a sub item. m_secTree.InsertColumn( 1, _T("Time"), LVCFMT_LEFT, (int)(rect.Width() * .40) );
/ * I don't want to use LVN_GETDISPINFO to populate my subitem text, so I must turn on subitem text storage! This option is a much requested change that allows setting subitem text directly using SetItemText( item, subItem, _T(“Text”) ) */ m_secTree.StoreSubItemText( TRUE );
242 Chapter 15 User Interface Extensions
15.1 Overview
This chapter describes a variety of Objective Toolkit components that you can use to enhance the user interface of your programs.
15.2 Bitmapped Dialog
SECBitmapDialog lets you create dialogs with tiled or centered bitmaps in the background. Use SECBitmapDialog to decorate your application dialogs with 16 or 256 color bitmaps.
The following figure demonstrates how you can use bitmaps in your dialogs. Figure 114 – Objective Toolkit BmpDialog32 Sample Dialog
SECBitmapDialog is a direct enhancement of CDialog.
Chapter 15 User Interface Extensions 243 Figure 115 – Objective Toolkit SECBitmapDialog Class Hierarchy
CWnd
CDialog
SECBitmapDialog
15.2.1 Using SECBitmapDialog
The following sections describe how you can implement Objective Toolkit’s User Interface Extensions.
15.2.1.1To incorporate the SECBitmapDialog class into your code
Use the SECBitmapDialog as you would use CDialog. SECBitmapDialog adds a SetBitmap() member function. Use SetBitmap() to specify the bitmap and a display mode. The following dis- play modes are available.
Display mode flag Description
SEC_BITMAP_TILE Tiles the bitmap in the dialog’s background.
SEC_BITMAP_CENTER Centers the bitmap in the dialog’s background.
SEC_BITMAP_FILL Fills the dialog with the specified bitmap.
The following code creates a dialog with a tiled bitmap in the background.
SECBitmapDialog bmpDlg(IDD_MODAL_BMPDLG); bmpDlg.SetBitmap(IDB_BRICKWALL, SEC_BITMAP_TILE); bmpDlg.DoModal();
15.2.1.2To set the image used by the SECBitmapDialog class
You can set the bitmap used in an SECBitmapDialog by calling the SetBitmap() method, which has three overloads. The first overload accepts a resource ID of a bitmap resource. The second over- load accepts the filename of a bitmap file. The third overload takes a pointer to an SECImage- derived object. Objective Toolkit can use any of the overloads for 256-color support.
To change the bitmap at run time, the application can call SetBitmap() multiple times. Use SetNullBitmap() to remove the bitmap from the dialog.
15.2.2 Customizing SECBitmapDialog
There is one overridable method in the SECBitmapDialog class: OnStaticCtlColor(). You can override this function to set the text color for Static controls.
244 SECBitmapDialog features are demonstrated in the sample DmpDialog32. SECBitmapDialog modes are demonstrated in the sample TodTest. These samples do not ship with the product. For information on how to obtain these samples, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
15.3 Gradient Caption Extension
The gradient caption extension provides a simple emulation of the smooth gradient caption effects introduced in Microsoft Office for Windows 95. The extension also allows you to control the align- ment of caption text.
In order to match the Windows XP look and feel in a themed application, gradient caption extension will be auto- matically disabled if running under Windows XP and hosting application is themed.
Figure 116 – Example Application with the Gradient Caption
15.3.1 The Gradient Caption Classes
The gradient caption feature is incorporated into the existing SECFrameWnd and SECMDIFrameWnd. Figure 117 – Objective Toolkit Gradient Frame Class Hierarchy CFrameWnd CMDIFrameWnd
SECFrameWnd SECMDIFrameWnd
15.3.2 SECFrameWnd
The SECFrameWnd class derives from CFrameWnd and adds support for the gradient caption. The class also adds support for extended docking windows.
Chapter 15 User Interface Extensions 245 15.3.3 SECMDIFrameWnd
The SECMDIFrameWnd class derives from CMDIFrameWnd and adds support for the gradient caption and extended docking window features.
15.3.4 Using the Gradient Caption Feature
To incorporate the gradient caption into your application:
1. Change the base class of your main frame window class, which is usually CMainFrame. If you’re working with an MDI application, replace the base class (CMDIFrameWnd) with SECMDIFrameWnd. If you’re working with an SDI application, replace the base class (CFrameWnd) with SECFrameWnd.
2. Enable the gradient caption by calling EnableCustomCaption() from your frame window’s OnCreate() member.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ...
// Enable the gradient caption feature. EnableCustomCaption(TRUE);
return 0; }
To change the font of the caption text:
1. Derive a class from either SECMDIFrameWnd or SECFrameWnd. See the preceding proce- dure for more information.
2. Override the CreateCaptionAppFont() method or the CreateCaptionDocFont() method or both. For example, the code below shows how to italicize the document font.
void CMyFrameWnd::CreateCaptionDocFont(CFont& font) { NONCLIENTMETRICS ncm; ncm.cbSize = sizeof(ncm); VERIFY(SystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)); ncm.lfCaptionFont.lfItalic = TRUE; font.CreateFontIndirect(&ncm.lfCaptionFont); }
246 15.4 Keyboard Shortcuts
The keyboard shortcut classes enable users to redefine the keyboard for your application. These classes enable end-users to update the accelerator table at run time by choosing key bindings.
15.4.1 The Keyboard Shortcut Classes
The following figure is the class hierarchy for the Keyboard Shortcut Classes. Figure 118 – Keyboard Shortcut Class Hierarchy
CArray
SECShortcutTable
CDialog
SECShortcutDlg
CArray
SECCommandList
15.4.2 SECShortcutTable
SECShortcutTable contains key bindings in the form of an array of ACCELs.
15.4.3 SECCommandList
SECCommandList contains a list of every command IDs that you can assign together with a short and a long description. You can default any and all parts of SECCommandList.
15.4.4 SECShortcutDlg
SECShortcutDlg is a dialog class that provides a front-end for entering application macros. It pres- ents a standard dialog for accelerator key entry to the application.
The Objective Toolkit shortcut classes only use the APIs found in Win32.
Chapter 15 User Interface Extensions 247 15.4.5 Using the Keyboard Shortcut Classes
The following sections describe how to use keyboard shortcut classes in your application.
15.4.5.1To incorporate keyboard shortcuts into your application
1. At the end of InitInstance(), add this code to load user-assigned shortcuts.
SECShortcutTable shortcuts; if (shortcuts.Load()) { shortcuts.Apply(); }
2. To invoke the shortcut dialog, use the following code. Generally, you can handle the short- cut dialog at the main frame window level because the shortcut handling is not view or document specific.
void OnAssignShortcuts() { SECCommandList commands; SECShortcutTable shortcuts;
SECShortcutDlg dlg(commands, shortcuts);
if (dlg.DoModal() == IDOK && dlg.m_bDirty) { shortcuts.Save(); shortcuts.Apply(); } }
15.4.5.2To update menus
The application updates the menus automatically to show the keys defined in the current accelera- tor table. Any accelerator descriptions you put into menu items in the resource file are discarded.
If you have menu items that modify themselves in their OnUpdate() method, you need to ensure that you preserve the accelerator that is currently defined. For example, the user can redefine the keystrokes for Undo. If your application changes the Undo menu to describe the last action, you need to preserve the text of the current accelerator.
15.4.5.3To allow or disallow certain keyboard combinations
1. Complete the steps in Section 15.4.5.1, “To incorporate keyboard shortcuts into your application.”
2. Before you invoke the SECShortcutDlg dialog and after you instantiate the SECCommandList object, call the SECCommandList::SetRules() method. For example:
// The default, appropriate for programs // that deal with text.
248 commands.SetRules(HKCOMB_NONE|HKCOMB_S, HOTKEYF_CONTROL);
// A good alternative for draw programs // that never need // character input in the main window. commands.SetRules(0,0); // Allow all keys, even // unmodified letters
// Very restrictive -- only CTRL+ALT // combinations will // be allowed, and anything else will // convert to a CTRL+ALT commands.SetRules((WORD)~HKCOMB_SC, HOTKEYF_CONTROL|HOTKEYF_ALT);
For more information on this method, see the documentation for CHotKeyCtrl::SetRules() in the Objective Toolkit Class Reference.
15.4.5.4Setting Up Commands
A default list of command IDs is automatically generated when you declare an instance of SECCommandList. This list is generated when the application reads the main frame window and template menus to look for IDs. The name of the macro is the menu sequence (for example, File:Open). The long description is the string resource of the same ID. This string resource is typi- cally shown in the status line when the user highlights a menu item.
You can either replace or add to this list of command IDs. For example: const SECDefaultCommandId defaultCommands[] = { { ID_VIEW_TOOLBAR, IDS_MAC_VIEW_TOOLBAR, IDS_DESC_VIEW_TOOLBAR }, { ID_FILE_OPEN, 0, IDS_DESC_FILE_OPEN }, // Default name { ID_FILE_SAVE, IDS_MAC_FILE_SAVE, 0 }, // Default description { ID_FILE_PRINT } // Default both }; SECCommandList commands;
SECCommandList commands; commands.ClearCommandIds(); commands.AddCommandIds(defaultCommands, sizeof(defaultCommands)/ sizeof(SECDefaultCommandId));
In the above example, the elements defined in defaultCommands comprise a custom list of IDs. These are the only command IDs that you can assign. The call to ClearCommandIds() removes each of the default IDs that you set up by default in the constructor for SECCommandList. The call to AddCommandIds() installs the custom list of IDs.
This example also shows how to customize the names and descriptions that the dialog uses. Here is the definition for SECDefaultCommandId().
Chapter 15 User Interface Extensions 249 struct SECDefaultCommandId { // Id of this command, such as ID_VIEW_TOOLBAR UINT m_nID;
// String ID that gives the short name of the // command. This name appears in the // "Select a macro:" listbox. If this is // zero, then the menu name or toolhelp // text is used. UINT m_nName;
// String ID that gives the description of // the command. This name appears in the // "Description:" listbox. If this is zero, // then the status bar text for this // id is used. UINT m_nDescription; };
As the definition of defaultCommands in the preceding example indicates, you can leave m_nName or m_nDescription (or both) at zero, so SECCommandList uses either the menu name or the corre- sponding string resource to find the name or description (or both).
If you remove an ID from this list during the course of development, the saved file can still use it. Select Reset All in the dialog to solve this problem.
Visual Studio does perform a dependency check on resource.h. Resource.h defines the values for every string and command ID. If you change the value of an ID when you are using a custom table, Visual Studio does not automati- cally recompile the module that contains the table. This can result in erratic behavior in the dialog class.
15.4.5.5Excluded IDs
Objective Toolkit automatically excludes some IDs even if you put them in a list because you can- not assign them or because you never would assign them. The virtual member function QueryExcludeId() in SECCommandList contains the default list of excluded IDs. When you derive your own class from SECCommandList, you can either add IDs to the list or replace this list. A new constructor is also needed for the derived class to change the default behavior of the base SECCommandList class. For example,
class MyCommandList : public SECCommandList { public: MyCommandList(): SECCommandList(FALSE) { SetRules(HKCOMB_NONE|HKCOMB_S, HOTKEYF_CONTROL); DeriveDefaults(); } public: virtual BOOL QueryExcludeId (UINT nID); };
The default list of excluded IDs is as follows:
250 MRU entries on the File menu
MDI child entries on the Window menu
ID_NEXT_PANE and ID_PREV_PANE
Although ID_HELP and ID_CONTEXT_HELP are not excluded by default, you might want to exclude them. You cannot reliably assign commands to these IDs.
15.4.5.6Saving the Shortcuts
The shortcuts are automatically saved to a file named
The filename is generated by the member function GetDataFileName() in SECShortcutTable. This function returns a fully qualified name and path. This function is virtual and can be overridden. The second argument to this function specifies either MAIN_NAME or ALTERNATE_NAME. This is the mechanism that switches from the application directory to the Windows directory.
You can also replace the storage mechanism completely by overriding Load() and Save() in SECShortcutTable. You would do this if you wanted to save the table in the registry. You can write the table to any variant of a CArchive object.
The shortcuts are loaded and applied in InitInstance() of the application class.
15.4.5.7Keyboard Shortcut Notes
The keyboard shortcut classes support multiple doc templates and multiple view menus. When you load and save the list of shortcuts, the shortcut classes scan every doc-template that is associ- ated with the application object and then updates the menu text to display the shortcut key. This only occurs if each menu has an unique command ID. Overlapping command IDs are resolved in the context of the active document's menu.
Menus are updated recursively through all levels of pop-up sub-menus to support cascading menus.
If you create an ID that appears on a toolbar but not in a menu, the shortcut classes use the Tool- help string resource to generate a name and description.
These classes support international and multi-byte versions of Windows.
These classes presume that a single accelerator table exists in the main frame window. View-spe- cific accelerator tables are not supported.
Multiple main frame windows are not supported.
15.4.6 Keyboard Shortcut Sample
The Objective Toolkit Shortcut sample is called ShortCut. It shows how to add shortcuts to a stan- dard AppWizard-generated MDI application. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 15 User Interface Extensions 251 15.5 Splash Window
A splash window is a transient window that appears temporarily when the user starts the applica- tion. Generally, the pop-up window displays a copyright notice while the application is initialized.
15.5.1 The SECSplashWnd Class
The SECSplashWnd class provides you with a ready-to-use splash window for your applications. All you need to do is insert a splash bitmap and text. The splash window deletes itself after a spec- ified time or when the user clicks it, so you do not have to keep track of the splash window in your application. Figure 119 – Objective Toolkit’s Splash Window Class Hierarchy
CWnd
SECSplashWnd
Table 39 lists and describes the SECSplashWnd methods.
Table 39 – SECSplashWnd Methods
Method Description
AllowUserDismiss() Sets whether the user can dismiss the Splash Screen by clicking the mouse or pressing a key. Default: True.
EnableTimer() You can create the Splash Screen without enabling the timer. Call this function to start the countdown.
SetTaskbarTitle() The Splash Screen can include a taskbar entry. Use this function to set the Taskbar Caption. Default: No taskbar entry.
SetAlwaysOnTop() You can set the Splash Screen to WS_EX_TOPMOST. Default: Not set to WS_EX_TOPMOST, unless it is created before the application’s main window.
PostSplashDraw() This is an overridable method that lets you paint on top of the Splash Screen after it is rendered to the screen.
Dismiss() This function dismisses the Splash Screen.
DisableParent() You can disable or enable the parent of the Splash Screen when the Splash Screen is dis- played. Default: Parent enabled.
The SECSplashWnd constructor has an alternate constructor that takes two additional parame- ters— bWaitForTimer and bAlwaysOnTop.
252 SECSplashWnd(UINT nNewBitmapID, UINT nNewDuration = 2500, BOOL bWaitForTimer = FALSE, BOOL bAlwaysOnTop = FALSE);
If you want to display a login or password dialog with SECSplashWnd as the parent, set the third parameter to TRUE and then call EnableTimer() when you dismiss the dialog.
15.5.2 Using SECSplashWnd
To add SECSplashWnd to your application:
1. In the Visual Studio resource editor, add a splash screen bitmap resource.
2. Create an instance of SECSplashWnd on the heap. In the constructor, specify the bitmap ID and the duration for the splash window. For example:
m_pSplashWnd = new SECSplashWnd(IDB_SPLASHWND,3500);
3. Call the Create() method to create the splash window.
m_pSplashWnd->Create();
15.5.3 SECSplashWnd Samples
The sample Splash51 demonstrates the 32-bit implementation of SECSplashWnd. This sample also uses the SECRegistry classes to read the user’s name from the registry and display it on the splash screen during application startup. When you open the project in Visual Studio, the bitmap used by SECSplashWnd appears in the list of application resources.
This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 15 User Interface Extensions 253 15.6 Custom Status Bar
Objective Toolkit’s custom status bar class, SECCustomStatusBar, is a Windows status bar that has more features and is easier to configure than MFC’s CStatusBar. The custom status bar allows you to configure the fonts used in status bar panes, the text alignment, and foreground and background colors. When you use CStatusBar, panes can only contain text. The custom status bar adds the abil- ity to embed bitmaps in status bar panes. Moreover, the custom status bar allows you to assign custom cursor bitmaps to individual status bar panes. When the cursor is inside the pane, the cur- sor takes the form of the specified bitmap. Outside of the pane, the cursor returns to its normal shape. In addition, the custom status bar helps process mouse events inside a status bar pane. Figure 120 – Example SECCustomStatusBar
In addition, the custom status bar incorporates a progress indicator that you can show program- matically in place of the status bar panes and then hide when the process finishes. Figure 121 – Example SECCustomStatusBar Progress Bar
SECCustomStatusBar inherits all the functionality of a standard MFC status bar and adds the fea- tures described previously. Figure 122 – Custom Status Bar Class Hierarchy
CWnd
CControlBar
SECControlBar
SECStatusBar
SECCustomStatusBar
15.6.1 Using SECCustomStatusBar
The following sections describe how to use the custom status bar and its associated progress bar in your application.
15.6.1.1To incorporate SECCustomStatusBar into your code
The following steps assume that you have created an application that already has an initial status bar based on CStatusBar or SECStatusBar.
254 1. Replace the class for your frame window’s status bar (CStatusBar or SECStatusBar) with SECCustomStatusBar.
a. For each pane you want to add to the status bar, create a resource symbol for the new status bar pane (for example, ID_INDICATOR_EDIT).
2. Add the new resource symbols as elements in the indicators array. This array is usually declared with module scope in the implementation file for your frame class. It specifies the positions of each pane in the status bar.
static UINT indicators[]= { ID_SEPARATOR, ID_INDICATOR_EDIT, // added here! ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL; };
3. Ensure that the indicators array is passed in to SECCustomStatusBar::SetIndicators().
if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create }
4. After the status bar has been created via Create() and initialized via SetIndicators(), create the status bar panes. Status bar panes can contain bitmaps, text, or CWnd-based controls.
To add bitmap or text panes, create a PANEINFOEX structure, set the appropriate data fields in the structure, and call SetPaneInfoEx(). ... // Configure a text pane. PANEINFOEX pex; pex.iIndex = 2; pex.strText = “Text”; pex.iFlags = SBP_TEXT; m_wndStatusBar.SetPaneInfoEx(&pex);
// Configure a text pane. pex.iIndex = 3; pex.pBitmap = m_pBitmap; pex.iFlags = SBP_BITMAP; m_wndStatusBar.SetPaneInfoEx(&pex); ...
The SBP_BITMAP and SBP_TEXT style flags shown above are mutually exclusive.
To add CWnd-derived controls, create the controls and then register them with the status bar via the RegisterWndToPane() member. The CommandToIndex() member fetches the correct index parameter.
For example, the following code adds an edit control to the status bar:
Chapter 15 User Interface Extensions 255 ... int nPanelIndex=m_wndStatusBar.CommandToIndex( ID_INDICATOR_EDIT); m_wndPanelEdit.Create(WS_VISIBLE|ES_LEFT| ES_AUTOHSCROLL, CRect(0,0,0,0), &m_wndStatusBar, ID_INDICATOR_EDIT);
m_wndStatusBar.RegisterWndToPane( nPanelIndex, &m_wndPanelEdit, SECCustomStatusBar::FitPaneToWnd); ...
You’re done. The CWnd object is now automatically sized and positioned in response to SECCustomStatusBar events. Call RegisterWndToPane() with a NULL CWnd* to unregister a window.
The sample \Samples\Toolkit\MFC\UIExt\statbar sampledemonstrates how to use the SECCustomStatusBar class. This sample is not shipped with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
15.6.1.2To display the progress bar over the status bar
SECCustomStatusBar includes routines that allow the application to replace the status bar with a progress control bar temporarily. The progress control bar is implemented as an SECProgressCtrl object so you can use the extended styles provided by SECProgressCtrl. In addition, you can dis- play a text string to the left of the progress bar.
1. Use the InitializeProgressControl() method to create and display the progress bar. This function sets the optional text, the range and initial value of the progress indicator, and the extended style flags.
2. Call SetProgress() or StepProgress() to update the progress indicator.
3. Call SetPaneText() for pane 0 to change the text to the left of the bar.
4. Call UninitializeProgressControl() to remove the progress bar.
SECCustomStatusBar does not support the SEC_EX_PROGRESS_SHOWTEXT style for the progress bar. Nor does it provide a method for setting the text string, and the m_pProgressCtrl member is protected. To use the SEC_EX_PROGRESS_SHOWTEXT style, cre- ate a new class derived from SECCustomStatusBar. You might add a new function to your class that passes the text along to the progress bar.
For example:
MyCustomStatusBar::SetProgressBarText(LPCTSTR pString) { m_pProgressCtrl->SetWindowText(pString); }
Then you can call SetProgressBarText() to update the text whenever you call SetProgress() or StepProgress() to update the progress indicator.
256 15.6.2 Customizing SECCustomStatusBar
The following section describes how to modify the behavior or appearance of the custom status bar.
15.6.2.1To customize panes with the PANEINFOEX structure
The SECCustomStatusBar class adds several configurable attributes to your frame window’s sta- tus bar. PANEINFOEX is a structure that aggregates every attribute of one pane of a custom status bar. The PANEINFOEX structure aggregates every attribute introduced by SECCustomStatusBar. It even includes attributes defined by its base class, SECStatusBar.
The following code shows how to set flags for each attribute you want to apply to a status bar pane.
// Configure the second pane to display // the light bitmap and // use the gripping hand cursor. PANEINFOEX pex; pex.iIndex = 2; pex.hCursor = AfxGetApp()->LoadCursor(IDC_GRIPPING_HAND); pex.pBitmap = m_pBitmap; pex.iFlags = SBP_CURSOR | SBP_BITMAP; m_wndStatusBar.SetPaneInfoEx(&pex);
The flags for the iFlags member of PANEINFOEX can include the following:
SBP_ID Set the ID of the pane to the uiID member of PANEINFOEX.
SBP_STYLE Set the style of the pane to that of the uiStyle member of PANEINFO.
SBP_WIDTH Use the cxWidth member of PANEINFO for the width.
SBP_TEXT Use the text set in the strText member of PANEINFO for the pane.
SBP_TEXT_ALIGN Use the iTextAlignment member of PANEINFO for text alignment. (Text align- ment flags like TA_LEFT are defined in WINGDI.H.)
SBP_FOREGROUND Use the COLORREF set in the crTextFore- ground member of PANEINFOEX for the foreground color.
SBP_BACKGROUND Use the COLORREF set in the crTextBackground member of PANEINFOEX for the background color.
Chapter 15 User Interface Extensions 257 SBP_BITMAP Display the CBitmap pointed to by the pBitmap member of PANEINFOEX in the pane.
SBP_CURSOR Display the cursor specified by the hCursor member of PANEINFOEX when the mouse pointer is over the pane.
These flags can be logically OR’d together. However, the following flags are mutually exclusive: SBP_BITMAP, SBP_TEXT, and SBP_STYLE.
15.6.2.2To extend the SECCustomStatusBar class
The SECCustomStatusBar class has the following virtual member functions that allow you to cus- tomize the behavior of the class.
Table 40 – Virtual Member Functions for SECCustomStatusBar
Method Description
InitializeProgressControl() Initializes and shows the progress indicator.
UninitializeProgressControl() Deletes the progress indicator and restores the status bar to its original content.
SetVisibleAllRegWnd() Sets the visibility of the registered windows.
ResizeAllRegWnd() Resizes all registered windows based on current attributes.
258 15.7 Thumbnail Classes
Many Windows applications like Microsoft PowerPoint and Delrina WinFax support thumbnails. Thumbnails let the user preview a file without having to open it. Objective Toolkit provides thumb- nail support through the document/view architecture. Figure 123 – Example Thumbnail
A snapshot of the current view is stored at the beginning of the archive file when the document is serialized. A specialized File Open dialog displays the stored image of highlighted files to aid in file selection.
The thumbnail classes are designed to display the special images stored in archive files. They can- not be used to display images from other file formats.
15.7.1 The Thumbnail Classes
The following classes work together to provide Objective Toolkit thumbnail support. SECTNBitmap, SECTNDC, and SECTNFileDialog are usually transparent to your application, but you need to know how they function.
Chapter 15 User Interface Extensions 259 Figure 124 – Thumbnail Class Hierarchy CWinApp CFileDialog
SECTNWinApp SECTNFileDialog
CDocument CBitmap
SECTNDocument SECTNBitmap
CView CDC
SECTNView SECTNDC
15.7.1.1SECTNBitmap
SECTNBitmap is a CBitmap derivative that creates, saves, and displays thumbnail images.
15.7.1.2SECTNDC
SECTNDC is a CDC derivative that is passed to your SECTNView’s OnDraw() method. The view draws the thumbnail image onto the SECTNDC. Objective Toolkit converts the image to an SECTNBitmap and then saves the image.
15.7.1.3SECTNDocument
Class SECTNDocument is an optional CDocument derivative that stores an SECTNView thumbnail image during serialization and bypasses the thumbnail image when reading.
15.7.1.4SECTNFileDialog
SECTNFileDialog uses a CFileDialog derivative to display a thumbnail. SECTNFileDialog also automatically reads and displays the thumbnail image when the user clicks a file name in the dialog.
15.7.1.5SECTNView
SECTNView is a CView derivative that can automatically generate a thumbnail by drawing onto an SECTNDC. This behavior is overridable so that applications can implement their own thumbnail drawing routines using an interface similar to CView printing.
260 15.7.1.6SECTNWinApp
SECTNWinApp automatically creates an SECTNFileDialog when the user selects File|Open.
15.7.2 Using the Thumbnail Classes
To enable thumbnails in your application:
1. Replace your application object’s base class with SECTNWinApp.
2. Change your CView-derived class to derive from SECTNView. Add any custom thumbnail code to this class.
3. Change your CDocument derivative to derive from SECTNDocument. Be sure to call SECTNDocument::Serialize() first in your ::Serialize() method.
By default SECTNView generates a thumbnail that is the size of your entire view. SECTNView can- not infer how you want your view’s thumbnail to appear, so you need to write special thumbnail- generating code.
To generate custom thumbnails:
1. Derive a class from SECTNView and override the OnDraw() method.
2. In the OnDraw() override, you can determine if a thumbnail is being drawn by calling IsThumbNailing(). If the view is a thumbnail, draw the view’s thumbnail on the specified DC.
15.7.3 Thumbnail Sample
The Objective Toolkit thumbnl sample (Samples\Toolkit\MFC\UIExt\thumbnl) demonstrates the MFC scribble tutorial application with thumbnail support. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 15 User Interface Extensions 261 15.8 Tip of the Day Dialog
A tip of the day dialog is displayed when the user starts the application. It displays random but useful information about the application. Figure 125 – Example Tip of the Day
15.8.1 The SECTipOfDay Class
SECTipOfDay stores tips in a plain ASCII file so you can easily create tip files (*.tip) with any edi- tor. SECTipOfDay is designed to be fully customizable. You can specify different fonts or icons and change other attributes by deriving your own tip class from SECTipOfDay. Figure 126 – Objective Toolkit SECTipOfDay Class Hierarchy
CDialog
SECTipOfDay
15.8.2 SECTipOfDay Resource IDs
The following resource IDs are available for the SECTipOfDay class. You can use them to display items on the dialog selectively. See Section 15.8.3.4, “To hide buttons on the tip of the day dialog.”
Table 41 – Resource IDs for SECTipofDay
Resource ID Description
IDC_TOD_OK_BUTTON The OK button ID.
IDC_TOD_NEXT_BUTTON The Next Tip button ID.
IDC_TOD_PREV_BUTTON The Previous Tip button ID.
262 Table 41 – Resource IDs for SECTipofDay (Continued)
Resource ID Description
IDC_TOD_HELP_BUTTON The Help button ID.
IDC_TOD_SHOW_CHECK The Show tips at startup check box.
IDC_TOD_GROUPBOX The tip itself.
15.8.3 Using SECTipOfDay
The SECTipOfDay class has the same interface as CDialog so you can make SECTipOfDay modal or modeless. The SECTipOfDay constructor takes arguments that specify the tip file, tip number, and other parameters specific to SECTipOfDay.
It is the application's responsibility to store the tip number so that it can provide the user with a new tip at every application invocation.
15.8.3.1To create a modal tip of the day dialog
The following changes are typically done in the InitInstance() method of the application, as part of the initialization of the application. The code is executed after the main frame has been cre- ated and displayed.
1. Load the startup status and tip from a file, registry, or other source. For example:
m_nLastTip = GetProfileInt(_T("SampleTip"),_T("CurrentTip"),0);
m_bShowTipAtStartup = (BOOL)GetProfileInt(_T("SampleTip"),_T("ShowAtStart"),1);
2. Instantiate an SECTipOfDay object by passing the tip and startup information to the con- structor and then calling the DoModal() method. For example:
if (m_bShowTipAtStartup) { SECTipOfDay MyTips(_T("todtest.tip"),++m_nLastTip); MyTips.DoModal(); }
15.8.3.2To create a modeless tip of the day dialog
1. Load the startup status and tip from a file, registry, or other source.
2. Create an SECTipOfDay object on the heap with the new operator.
m_pModelessTip = new SECTipOfDay(_T("todtest.tip"),++m_nLastTip, m_bShowTipAtStartup);
Chapter 15 User Interface Extensions 263 You can declare the object on the stack (for example, as the member of a class) as long as the object is not expected to go out of scope while the tip of the day window is displayed.
3. Display the dialog in a modeless manner by calling CDialog::Create() and CDialog::ShowWindow().
theApp.m_pModelessTip->Create(); theApp.m_pModelessTip->ShowWindow(SW_SHOW);
15.8.3.3To change the caption of the tip of the day dialog
1. Derive a class from SECTipOfDay.
2. Override the OnInitDialog() method. In the override, call the base class implementation and then call the CDialog::SetWindowText() method. For example:
CMyTipOfDay::OnInitDialog() { SECTipOfDay::OnInitDialog();
// Change the caption to something else this->SetWindowText( _T("This is my custom tip du jour"));
// FYI, by default SECTipOfDay, centers the tip, // you might want // to move it else where here.
return TRUE; }
15.8.3.4To hide buttons on the tip of the day dialog
1. Derive a class from SECTipOfDay.
2. Override the OnInitDialog() method. In the override, call the base class implementation and then call ShowWindow(SW_HIDE) for the dialog items to be hidden. See Section 15.8.2 for a list of resource IDS. For example:
CMyTipOfDay::OnInitDialog() { SECTipOfDay::OnInitDialog();
// Hide the “previous” button and the // “show at startup” button. CWnd * pWnd = (CWnd *)GetDlgItem(IDC_TOD_PREV_BUTTON); pWnd->ShowWindow(SW_HIDE);
pWnd = (CWnd *)GetDlgItem(IDC_TOD_SHOW_CHECK); pWnd->ShowWindow(SW_HIDE);
264 // FYI, by default SECTipOfDay, centers the tip, // you might want // to move it else where here.
return TRUE; }
15.8.4 SECTipOfDay Sample
The Objective Toolkit todtest sample (Samples\Toolkit\MFC\UIExt\todtest) demonstrates the SECTipOfDay class and shows how to customize the class to specify a different font and icon. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 15 User Interface Extensions 265 15.9 Tray Icon Class
The SECTrayIcon class helps you create applications that are invoked via the Windows tray inter- face. Animated icons are supported. A System Tray Icon is a user interface metaphor that was introduced by Windows 95. If you look at the rightmost edge of the Windows 95 taskbar, there is a small "tray" of application icons and a system clock.
SECTrayIcon provides your application with an easy-to-use mechanism for adding your own cus- tom icons to the system tray and providing user interface feedback such as tooltip text, context menu support, and animated icons. Figure 127 – Objective Toolkit Tray Icon Class Hierarchy
CObject
SECTrayIcon
15.9.1 To incorporate the Tray Icon Class into your application
1. In your main window class (main frame or dialog), add an SECTrayIcon data member for each tray icon you want to display. For example:
SECTrayIcon m_TrayApp;
2. In the initialization code for your main window class, create the tray icon by calling the Create() method.
m_TrayApp.Create(this);
3. In the resource editor, add an icon resource and then set the icon with the SetIcon() method.
m_TrayApp.SetIcon(IDI_STINGRAY);
4. Optionally, set tooltip text with the SetTip() method.
m_TrayApp.SetTip(_T("Stingray Tray Icon Demo"));
5. Display the tray icon with the Show() method.
m_TrayApp.Show(TRUE);
The SECTrayIcon destructor automatically cleans up the icon; however, you can still issue a Destroy() call directly.
266 15.9.2 To add notification handlers for mouse events
The following steps set up a notification handler to display a context menu in response to a right- click.
1. Complete the steps in Section 15.9.1.
2. For each tray icon, create a unique notification ID or use the GetNextNotifyID() method to generate one on the fly.
m_TrayNotifyId=SECTrayIcon::GetNextNotifyID();
Add the notification ID as the second parameter to the Create() method call.
m_TrayApp.Create(this, m_TrayNotifyId);
3. Add the WM_SEC_TRAYICON_NOTIFY message using the ON_MESSAGE macro in the message map. The tray icon sends notifications via this user message. You can also specify your own message ID as an optional parameter to the SECTrayIcon::Create() method call.
ON_MESSAGE(WM_SEC_TRAYICON_NOTIFY, OnTrayIconNotify)
Add a message handler for this message. The wParam contains the notification ID passed to the Create() method. The lParam contains the mouse message. For example:
LRESULT CTrayIconDlg::OnTrayIconNotify(WPARAM wParam, LPARAM lParam) { // Use the wParam to identify which tray icon if(wParam==m_TrayNotifyId) {
// lParam identifies the mouse message switch(lParam) { case WM_MOUSEMOVE: // mousemove is a good place to // change tooltip text – for example // if you were displaying time of day
case WM_RBUTTONUP: // the SECTrayIcon::ShowContextMenu // static member makes it a snap to // display popup menus—-all the // positioning and message routing // is done automatically for you. SECTrayIcon::ShowContextMenu(this, IDR_MENU_NOTIFY); break;
case WM_LBUTTONDBLCLK: AfxMessageBox( _T("You just double clicked me!")); break; } } return 0L; }
Chapter 15 User Interface Extensions 267 15.9.3 To animate a tray icon
1. Complete the steps in Section 15.9.1.
2. In the resource editor, add icons for each frame of the animation.
3. After the SECTrayIcon::Create() method call, call the AddState() method and specify a unique ID for each state, the icon to display, the tooltip to display, and a frame delay time. The default time delay is 255 milliseconds. If you need to specify a different time delay, multiply the delay parameter by 17 to determine the time in milliseconds.
m_tray.AddState(IDI_SCROLL_ON0, IDI_SCROLL_ON0, strOn, nFrameDelay); m_tray.AddState(IDI_SCROLL_ON1, IDI_SCROLL_ON1, strOn, nFrameDelay); m_tray.AddState(IDI_SCROLL_ON2, IDI_SCROLL_ON2, strOn, nFrameDelay); m_tray.AddState(IDI_SCROLL_ON3, IDI_SCROLL_ON3, strOn, nFrameDelay); m_tray.AddState(IDI_SCROLL_ON4, IDI_SCROLL_ON4, strOn, nFrameDelay); m_tray.AddState(IDI_SCROLL_ON5, IDI_SCROLL_ON5, strOn, nFrameDelay);
4. After the call to the Show() method, call the Play() method to start the animation and the Stop() to halt the animation.
m_TrayAnimated.Play(IDI_SCROLL_ON0,6);
15.9.4 Tray Icon Sample
Refer to the trayicon sample (\Samples\Toolkit\MFC\UIExt\TrayIcon) for more information. Animations are also demonstrated in this sample. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
268 15.10User-Tools Menu
Objective Toolkit’s user-tools menu classes implement a user-configurable Tools menu like the one in Microsoft Visual Studio. A user-tool is an executable that the application can spawn programmat- ically. The user can add his or her own menu items to the Tools menu and specify an action for each menu item. Figure 128 – Example User-Tools Dialog
15.10.1The User-Tools Menu Classes
Two classes are involved in the implementation of the user-tools menu feature. SECUserTool encapsulates the information required to execute a tool. SECUserToolsDlg allows the user to man- age the list of tools. Figure 129 – User-Tool Menu Class Hierarchy
CObject CDialog
SECUserTool SECUserToolsDlg
15.10.1.1SECUserTool
TheSECUserTool class provides an abstraction of a user-tool. An SECUserTool object encapsulates the filename, command-line arguments, and initial directory that describe how and where to run the executable. In addition, the SECUserTool interface contains an Execute() method that uses these attributes to launch the user-defined tool.
Chapter 15 User Interface Extensions 269 15.10.1.2SECUserToolsDlg
The SECUserToolsDlg class implements a user-tools dialog. A user-tools dialog allows the user to edit a list of user-tools, where each user-tool is represented by one SECUserTool object. Through this dialog, the user can create new user-tools, edit and delete existing user-tools, and reorder the list of user-tools.
15.10.2Using the User-Tools Menu Classes
To add user-tool support to your application:
1. Add a CObArray member to your main frame class (usually CMainFrame) to store the SECUserTool objects.
2. Instantiate an SECUserTool object and add it to the CObArray.
3. Call the SetMenuText() method to set the menu text associated with the user-tool.
4. Call the SetCommand() method to set the absolute path and filename of the executable for the user-tool.
5. Call the SetArgs() method to set the command-line arguments that are passed to the user- tool upon execution.
6. Call the SetDirectory() method to set the absolute path of the directory in which the user- tool is initially executed.
7. Alternatively, instantiate an SECUserToolsDlg dialog and initialize it by calling SetToolsArrayPtr() with the array of SECUserTool objects. Activate the dialog, which automatically performs calls the preceding methods using the information that the user provides for each user-tool. To execute a user-tool:
Call the Execute() method and pass the pReplacements parameter to run the user-tool with the specified arguments and initial directory.
To make a copy of a user-tool:
Call the Clone() method.
To serialize an array of user-tools:
Use the ReadUserToolFile() or WriteUserToolFile() global function.
To append an array of user-tools to a menu:
Use the AppendUserTools() function.
To delete an array of user-tools:
Use the EmptyUserToolArray() function.
270 15.10.3User-Tool Menu Sample
The Objective Toolkit toolmenu sample (Samples\Toolkit\MFC\UIext\toolmenu) demonstrates the capabilities of the user-definable tools menu and dialog. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
15.11Workspace Manager
Objective Toolkit’s workspace manager classes provide a flexible framework that includes menu and dialog resources for saving and restoring window configurations. You can save and restore workspaces to and from a file or the Win32 registry. The workspace save/restore feature is a user interface enhancement that does not require you to change or redesign your user interface. In addi- tion, you can use the workspace save/restore interface enhancement with Stingray’s MDI, FDI, MTI, or Extended Control Bar Architecture enhancements.
The extended workspace manager now provides a simple alternative to the LoadBarState() and SaveBarState() mechanisms utilized in previous releases of Objective Toolkit for automatically restoring and saving the state of your application’s window configuration.
The extended workspace manager requires you to use the enhanced frame window classes included in Objective Toolkit.
With WDI, the workbook mode must be saved as user data.
There are also limitations in using the SECWorkspaceManagerEx class with FDI applications. For example, there is currently no direct support for saving toolbar information in the FDI child frames.
15.11.1The Workspace Manager Classes
Objective Toolkit includes two workspace manager classes— SECWorkspaceManager and the more powerful SECWorkspaceManagerEx. Figure 130 – The Objective Toolkit Workspace Manager Class Hierarchy
CCmdTarget CWnd
SECWorkspaceManager SECWndPlugin
SECWorkspaceManagerEx
The next few sections describe the differences between these two classes.
Chapter 15 User Interface Extensions 271 15.11.1.1SECWorkspaceManager versus SECWorkspaceManagerEx
SECWorkspaceManagerEx supports all the features in SECWorkspaceManager and adds the following:
Persistence of workspaces directly to either a file or the registry.
Persistence of multiple views per document.
Persistence of an application’s current activation state.
Workspace versioning.
Full support for Objective Toolkit docking windows, toolbars, and menubars.
Support for Docking Views.
All data persisted by the workspace manager is stored in a tree of SECPersistentTreeNode (PTN) objects. Each object can have an arbitrary number of key-value pairs to represent one piece of data. This model is similar to the windows system registry.
By default, the extended workspace manager stores the application state in a preset tree where set- tings are grouped logically according to their role. For example, controlbar settings are in one subtree, child frame windows in another, etc. By overriding the appropriate Open() and Save() workspace manager methods, you can easily add your own child PTN objects to be included in the workspace state. See Section 15.11.2.3, “To add application specific information to the workspace state.”
This class is easier to integrate into your application than the legacy SECWorkspaceManager class. SECWorkspaceManagerEx has been completely redesigned. You can easily extend it with custom configuration information and a custom persistence protocol.
SECWorkspaceManagerEx is fully redesigned, and has many enhancements compared to its predecessor, SECWorkspaceManager. Unfortunately, the two classes are not code compatible with each other. You cannot replace previous instances of SECWorkspaceManager with SECWorkspaceManagerEx. We would like to encourage you to migrate to SECWorkspaceManagerEx in any future development. SECWorkspaceManager is an obsolete class that is still offered only to ensure backward compatibility.
15.11.1.2Support for Dynamically Created Controlbars
Unlike the legacy SECWorkspaceManager class, the new SECWorkspaceManagerEx class can now persist controlbars that have been created dynamically (for example, controlbars created using the new operator). The SECWorkspaceManager class can only restore the states of windows that already exist (for example, those created during CMainFrame::OnCreate) whereas the new SECWorkspaceManagerEx class can actually create controlbars based on stored run-time class information and also restore their state.
The extended workspace manager class, SECWorkspaceManagerEx, can also persist the run-time class information corresponding to each controlbar, which can then be used to reconstruct any dynamically created controlbars. This support is virtually seamless to your application. The only additional step required for this support is the implementation of the following two MFC serializa-
272 tion macros for each controlbar class: IMPLEMENT_SERIAL and TOOLKIT_DECLARE_SERIAL. These macros are already included in all the packaged Objective Toolkit SECControlBar-derived classes. Please consult the standard MFC references for more information on using these macros.
15.11.1.3Multiple Views per Document, Multiple Views Per Frame
The extended workspace manager has prebuilt support for multiple views tied to a single docu- ment when each view occupies its own frame window. This applies to Docking Views as well.
If you have multiple views sharing a single frame window (for example, inside a splitter or tab window), the workspace manager cannot predict how you want these additional views to be restored (this is an application specific function). What it can do, however, is supply the appropri- ate virtual overrides for you to hook in the application specific information required for this procedure. See SECWorkspaceManagerEx::SaveAdditionalViewPerFrame() and SECWorkspaceManagerEx::OpenAdditionalViewPerFrame() for more information. The work- space manager automatically stores the presence of multiple views per frame so that OpenAdditionalViewPerFrame() is automatically called with the appropriate information. It is your responsibility to supply any additional state information, and act upon that state information (for example, inserting a new tab, creating a new splitter, etc.).
15.11.2Using SECWorkspaceManagerEx
The following sections describe how to use SECWorkspaceManagerEx in a variety of application types.
15.11.2.1To add workspace management to your application
1. Include support for Objective Toolkit docking windows.
2. At the end of your CMainFrame::OnCreate() handler, add a call to the InitWorkspaceMgrEx() method. For example:
InitWorkspaceMgrEx( _T("Software\\MyCompany\\Sample\\v1.0"), FALSE);
The first parameter is a base registry key off HKEY_CURRENT_USER to store your workspace state information. This key must be unique to your application and its version number. The second parameter toggles the workspace manager in registry mode. If TRUE, the workspace manager saves workspace state information to a registry key off the path specified in the first parameter. If FALSE, the workspace manager prompts you to save/load workspace information from a file. The registry key is still used, but it only contains a list of Most Recently Used workspace paths.
3. If you’d like, you can add the following commands to your pull-down menus to hook into the workspace manager functionality automatically.
ID_WORKSPACE_NEW ID_WORKSPACE_SAVE ID_WORKSPACE_SAVEAS ID_WORKSPACE_OPEN
Chapter 15 User Interface Extensions 273 ID_WORKSPACE_DELETE ID_WORKSPACE_1 (automatic insertion of “Recent Workspaces” list)
15.11.2.2To load and store the workspace state automatically
1. Follow the steps described in Section 15.11.2.1.
2. In your application’s InitInstance() method, obtain a pointer to the workspace manager with the GetWorkspaceMgrEx() method and then call the OpenWorkspace() method. Insert this code after the code that initializes the frame but before the frame is made visible. For example:
// create main MDI Frame window CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE;m_pMainWnd = pMainFrame;
SECWorkspaceManagerEx* pWsMgr = pMainFrame->GetWorkspaceMgrEx(); if (pWsMgr) pWsMgr->OpenWorkspace(TRUE); // TRUE = open MRU, // FALSE = prompt
OpenWorkspace() can take a TRUE or FALSE parameter. If TRUE, the workspace manager automatically loads the name of the last stored workspace. If FALSE, a dialog is displayed that asks the user which workspace to load.
3. In your CMainFrame::OnClose(), save the workspace using the SaveWorkspace() method.
SECWorkspaceManagerEx* pWsMgr=GetWorkspaceMgrEx(); ASSERT(pWsMgr); pWsMgr->SaveWorkspace(_T(".\\SdiMgr.wsp"));
GetWorkspaceMgrEx() fetches the stored value from the SEC frame window. The SaveWorkspace() call uses the appropriate parameter based on the current storage mode (registry vs. file mode). Please refer to SECWorkspaceManagerEx::SaveWorkspace() in the Objective Toolkit Class Reference for more information.
15.11.2.3To add application specific information to the workspace state
1. Follow the steps described in Section 15.11.2.1.
2. Derive a class from SECWorkspaceManagerEx. Ensure that your derived class has properly implemented the TOOLKIT_DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE macros for run-time CObject instantiation.
3. Specify the run-time class of your SECWorkspaceManagerEx-derived class as a parameter passed to the InitWorkspaceManagerEx() call in CMainFrame::OnCreate(). For example:
InitWorkspaceMgrEx( _T("Software\\Stingray\\Samples\\Toolkit\\WMCust\\v1.0"), TRUE, RUNTIME_CLASS(CCustomWrkspcEx));
274 4. Create an override for the SaveWorkspaceCustomData() method.
// Override SaveWorkspaceCustomData to save data // on a per-workspace basis void CCustomWrkspcEx::SaveWorkspaceCustomData ( SECPTNFactory& nodeFactory, SECPersistentTreeNode* pRoot, const CString& strWorkspaceName) {
BOOL bCustomDataSetting = GetTheCustomDataSomehow(); // The pRoot PTN object passed in is the // appropriate parent for this custom data. // Now create a child node to store additional // information... SECPersistentTreeNode* pCustomNode = nodeFactory.CreateNode( _T("MyCustomDataNode"),pRoot);
ASSERT(pCustomNode);
// And add the custom data. This // will automatically // be saved by the recursive save // operation initiated // by the workspace mgr - no additional // coding required. pCustomNode->AddKeyValueBool( _T("MyUniqueCustomKeyName"), bCustomDataSetting);
// We could store more key-value pairs // here if we wanted. // The only restriction is // that each key must have a unique name. // Invoke the base... SECWorkspaceManagerEx::SaveWorkspaceCustomData( nodeFactory,pRoot,strWorkspaceName); }
5. Create an override for the OpenWorkspaceCustomData() method.
void CCustomWrkspcEx::OpenWorkspaceCustomData( SECPersistentTreeNode* pRoot, const CString& strWorkspaceName) {
// Locate the custom data PTN node // stored above... SECPersistentTreeNode* pCustomNode=pRoot-> FindChildNode(_T("MyCustomDataNode"));
// it must be there, unless the workspace // was corrupt or not versioned. ASSERT(pCustomNode);
Chapter 15 User Interface Extensions 275 // Now, load the custom data stored in this // object (again, we could load multiple // key-values here if they were stored...) BOOL bCustomDataSetting; pCustomNode->GetKeyValueBool( _T("MyUniqueCustomKeyName"), bCustomDataSetting);
// Got it, do something DoSomethingWithTheData(bCustomDataSetting);
// Invoke the base... SECWorkspaceManagerEx::OpenWorkspaceCustomData( pRoot,strWorkspaceName); }
6. To store workspace data at a finer level of granularity, you can override other SECWorkpsaceManagerEx functions. For example, by overriding OpenSpecificChildFrame() and SaveSpecificChildFrame(), you can store data on a per-view basis. This is useful if you have multiple views tied to a single document and you want to store presentation information for each of those additional views that does not log- ically fit into the document data stream.
15.11.2.4To store the WDI workbook state in the workspace state
1. Follow the steps described in Section 15.11.2.1 that pertain to the creation of the stub method for the SaveWorkspaceCustomData() and OpenWorkspaceCustomData() overrides.
2. In the SaveWorkspaceCustomData() override, query the workbook state and save it as one of the tree nodes in the workspace state. For example:
void CCustomWrkspcEx::SaveWorkspaceCustomData( SECPTNFactory& nodeFactory, SECPersistentTreeNode* pRoot, const CString& strWorkspaceName) {
// library should insure parameters are valid ASSERT(pRoot);
// Just for purposes of demonstration, // we are saving the current // workbook mode setting
// Get the workbook mode setting SECWorkbookWnd* pWB=(SECWorkbookWnd *)AfxGetMainWnd(); ASSERT(pWB); ASSERT_KINDOF(SECWorkbookWnd,pWB); BOOL bWorkbookMode=pWB->m_bWorkbookMode;
// Create a custom child node for data storage. // Note, all workspace data is organized in // a tree of these SECPersistentTreeNode // objects,so we can insert new nodes anywhere // in the tree, as long as we also override
276 // the corresponding "Open" function to act // upon this additional data on workspace load. SECPersistentTreeNode* pCustomNode = nodeFactory.CreateNode( szCustomWorkspaceDataNode,pRoot); ASSERT(pCustomNode);
// And add the custom data. This will // automatically be saved by the recursive save // operation initiated by the workspace mgr // – no additional coding required. pCustomNode-> AddKeyValueBool( szWorkbookModeKey,bWorkbookMode);
// As of Objective Toolkit 5.2, this is a no-op, but it's // still a good practice to get into... SECWorkspaceManagerEx::SaveWorkspaceCustomData( nodeFactory,pRoot,strWorkspaceName); }
3. In the OpenWorkspaceCustomData(), restore the saved workbook state from the data in the workspace state.
void CCustomWrkspcEx::OpenWorkspaceCustomData( SECPersistentTreeNode* pRoot, const CString& strWorkspaceName) {
// Get the workbook mode setting stored by // SaveWorkspaceCustomData
// First, locate the child custom data node SECPersistentTreeNode* pCustomNode = pRoot-> FindChildNode( szCustomWorkspaceDataNode);
// if not, corrupt workspace! ASSERT(pCustomNode);
// And load the data value in this node // (note that 1 PTN node can have an // arbitrary number of // key-value data pairs, much like how // the registry tree works. // In this example, there's only one key-value // pair). BOOL bWorkbookMode; pCustomNode-> GetKeyValueBool( szWorkbookModeKey,bWorkbookMode);
// Setting loaded. Now apply the setting to the // workbook SECWorkbookWnd* pWB=(SECWorkbookWnd *)AfxGetMainWnd(); ASSERT(pWB); ASSERT_KINDOF(SECWorkbookWnd,pWB); pWB->SetWorkbookMode(bWorkbookMode);
Chapter 15 User Interface Extensions 277
// As of Objective Toolkit 5.2, this is a no-op, but it's still // a good practice to get into... SECWorkspaceManagerEx::OpenWorkspaceCustomData( pRoot,strWorkspaceName); }
15.11.3Using SECWorkspaceManager
The SECWorkspaceManager class is provided only for backward compatibility. You are encour- aged to use SECWorkspaceManagerEx for all new development.
To add workspace management to your application:
1. Add an SECWorkspaceManager pointer (for example, m_pWorkspaceMgr) to your applica- tion class or create it as a global variable if you prefer.
2. In CMyApp::OnInitInstance(), instantiate and create the SECWorkspaceManager instance, storing a pointer to it in m_pWorkspaceMgr. For example:
BOOL CIDEApp::InitInstance() { LoadStdProfileSettings();
m_pDocTemplate = new CMultiDocTemplate( IDR_SOURCE_EDITOR, RUNTIME_CLASS(CSrcDoc), RUNTIME_CLASS(CSrcFrame), RUNTIME_CLASS(CSrcView)); AddDocTemplate(m_pDocTemplate);
// Instantiate the workspace manager m_pWorkspaceMgr = new SECWorkspaceManager(); m_pWorkspaceMgr->Create(AfxGetApp(), CString("Software\\YourApp\\Workspaces\\") // … }
3. Override OnCmdMsg() in your application class as follows:
BOOL CMyApp::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { if (CWinApp::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;
// otherwise check the workspace manager if (m_pWorkspaceMgr != NULL && m_pWorkspaceMgr->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;
return FALSE; }
278 4. Add the windows to the active workspace when they’re created and then remove them from the workspace when they’re destroyed. To do this, override the CFrameWnd::LoadFrame() and CFrameWnd::DestroyWindow() methods as follows:
BOOL CMyChildFrame::LoadFrame(UINT nIDResource, DWORD dwDefaultStyle, CWnd* pParentWnd, CCreateContext* pContext) { BOOL bRetval = CMDIChildWnd::LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext); theWorkspaceManager.AddWindow(this); return bRetval; }
BOOL CMyChildFrame::DestroyWindow() { theWorkspaceManager.RemoveWindow(this); return CMDIChildWnd::DestroyWindow(); }
5. Include the secres.h and secres.rc files in your application’s resource file. To do this, choose Resource Includes… from the Visual Studio View menu and add secres.h to the middle edit box and secres.rc to the bottom edit box. By doing this, you ensure that all resource IDs are defined for the workspace menu created in the next step.
6. Add the Workspace menu to your application’s menu. You can make the workspace menu a standalone menu or a popup from the File menu if you prefer. Regardless of where you choose to place the workspace menu, use the workspace resource IDs defined in secres.h. They are:
ID_WORKSPACE_NEW ID_WORKSPACE_SAVE ID_WORKSPACE_SAVEAS ID_WORKSPACE_OPEN ID_WORKSPACE_DELETE ID_WORKSPACE_CLOSE ID_WORKSPACE_1 through ID_WORKSPACE_8
15.11.4Workspace Manager Samples
The Objective Toolkit WrkSpcEx sample (
Also refer to the sample SdiMgr for an example of the workspace manager used programmatically (no dialogs or command handlers) for persistent state in a SDI application. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 15 User Interface Extensions 279 15.12Full-Screen View
SECFullScreenView is a utility component that allows you to integrate full-screen display into your MDI/SDI based applications. SECFullScreenView is designed to be used as a stand-alone compo- nent. It hooks into your application and manages the full-screen activation without any need for subclassing your existing frame window classes.
This plug-in design makes it simple to add the full-screen capability to existing applications. All you need to do is add an SECFullScreenView member to your main frame class and invoke the SECFullScreenView::SetFSMode() API to trigger the full-screen display. Once this mode is set, SECFullScreenView steps into your application’s activation mechanism and manages it until the user exits full-screen view mode, by pressing the ESCAPE key or clicking the full-screen toolbar.
The full-screen toolbar is a dynamically created toolbar that is instantiated as either an SECCustomToolBar or CToolBar/SECToolBar, depending on the run-time class of the frame. The SECCustomToolBar component provides the same cool-look full-screen user interface that is found in Microsoft VC++ and Microsoft Office. Both the standard bitmap toolbar and text toolbar are sup- ported. The default toolbar offers certain pre-set styles. However, you can change the default styles with the help of an application-defined callback. Figure 131 – Default Full-screen Toolbar
Another feature of SECFullScreenView is the drop-down menu style that allows the temporary dis- play of the application’s main window menu when the cursor is placed over the top portion of the screen like the Windows Taskbar. The default behavior is to hide all docking windows (control bars) except in the case of docking views when in the application is in full-screen mode. However, SECFullScreenView allows you to selectively include control bars you want to display in full- screen mode.
15.12.1The Full-Screen View Class
The SECFullScreenView class simply derives from CWnd. Figure 132 – Objective Toolkit Full-Screen View Class Hierarchy CWnd
SECFullScreenView
280 15.12.2SECFullScreenView Styles
The SECFullScreenView has a number of styles that control its behavior. These styles are used with the SetFSMode() method.
Style flag Description
SEC_FS_DROPDOWNMENU The application’s main window menu is displayed when the cursor hovers over the top section of the screen. Moving the cursor hides the menu.
SEC_FS_TEXTTOOLBAR The full-screen toolbar is a text-only toolbar. The label can be set while invoking the full-screen mode.
SEC_FS_TASKBARHIDE Forcibly hides the Windows task bar when full-screen mode is triggered. Exiting full-screen mode retrieves the task bar. Default is false.
SEC_FS_NOCUSTTOOLBAR SECFullScreenView defaults to using SECCustomToolBar when the Objective Toolkit frame window classes are used. Setting this style cre- ates the toolbar as an SECToolBar.
15.12.3Using the SECFullScreenView Class
The following topics describe how to utilize the full-screen view in your applications.
15.12.3.1To incorporate the SECFullScreenView class into your application
Add an SECFullScreenView member to your CFrameWnd-derived main frame class. From a com- mand handler, call the SetFSMode() function with the required parameters. For example:
// m_FSView is the SECFullScreenView object m_FSView.SetFSMode();
// The following call triggers the full-screen view with // drop-down // menus enabled and a text-only toolbar. The second // parameter // specifies the toolbar text. m_FSView.SetFSMode(SEC_FS_TEXTTOOLBAR|SEC_FS_DROPDOWNMENU, "Close Full Screen");
// A bitmap toolbar with the IDR_FSBITMAP resource is set m_FSView.SetFSMode( SEC_FS_DEFAULT, IDR_FSBITMAP );
Chapter 15 User Interface Extensions 281 15.12.3.2To set or retrieve the full-screen view mode styles
1. Use the SECFullScreenView::SetFSStyle() and GetFSStyle() methods.
2. SECFullScreenView::GetFSMode() returns a BOOL that specifies whether the full-screen mode is currently set.
15.12.3.3To terminate full-screen view mode
Use the CloseFSMode() method to terminate the full-screen display.
15.12.3.4To use full-screen view mode with docking windows
Use the SECFSBarState structure and the SetBarStateArray() method to specify the control bars to be displayed during full-screen view mode. The following excerpt from the SCREENVIEW sam- ple demonstrates the usage:
// Setting the second member of SECFSBarState to TRUE indicates // the control bar is visible only during the full-screen mode. // The ‘full screen only’ bars will be displayed when the FS mode // is set and will automatically be hidden when FS mode exits. SECFSBarState barState[2] = { { &m_wndCloudToolBar, FALSE }, { &m_wndPalette, TRUE } }; m_FSView.SetBarStateArray(barState, 2); m_FSView.SetFSMode(SEC_FS_DROPDOWNMENU);
SECFullScreenView only performs show/hide operations on the respective control bars. It is your responsibility to ensure that the control bars have been created and that they remain in scope throughout the time the application is in full-screen view mode.
15.12.3.5To change the default full-screen view toolbar styles
The full-screen view toolbar class is instantiated dynamically based on the application’s frame classes. So changing the default styles involves defining a callback function within your applica- tion and specifying this function pointer to the SECFullScreenView object. When the callback is invoked, you can examine the existing styles and change them as required.
Declare the callback.
// Callback definition within your main frame class static void CALLBACK SetToolBarStyles(UINT& dwStyle, UINT& dwStyleEx);
Define the callback function.
// Callback implementation. // This example creates the toolbar without the “cool-look” // double gripper and with a visible border
282 void CALLBACK CMainFrame::SetToolBarStyles(UINT& dwStyle, UINT& dwStyleEx) { dwStyle |= CBRS_BORDER_ANY; dwStyleEx &= ~CBRS_EX_GRIPPER; }
Before invoking the full-screen view mode, call the SetFSToolBarStylesCB() method, providing the address of the callback function.
// Specifying the callback to SECFullScreenView m_FSView.SetFSToolBarStylesCB(SetToolBarStyles); m_FSView.SetFSMode(SEC_FS_DROPDOWNMENU, "Close Full Screen");
15.12.4SECFullScreenView Sample
The Objective Toolkit sample screenview demonstrates usage of this class. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 15 User Interface Extensions 283 284 Chapter 16 Utility Classes
16.1 Overview
The classes in this section solve non-user interface problems.
16.2 Compressed File I/O
The compressed file class provides compression and decompression services for data written to and from a file. The class supports two modes: a compression mode that supports a subset of access methods and a regular mode that supports ordinary CFile method calls.
Because the compression file class compresses its data as a whole, you cannot see the middle of a compressed data block to perform partial decompression. However, by switching back and forth between compressed mode and nor- mal mode, you can write compressed data to a file in a different location. In addition, you can place a jump table at the beginning of the file to store seek locations of the different compressed blocks.
16.2.1 SECCompressFile
SECCompressFile is a CFile derivative that provides compression and decompression services for data written to and read from a file. SECCompressFile has no logic to determine where compressed blocks begin and end. You need to treat an entire file as a single compressed block or be able to seek to the beginning block of compressed data and read in the correct number of compressed bytes. Figure 133 – Objective Toolkit’s Compressed File Class Hierarchy
CFile
SECCompressedFile
Chapter 16 Utility Classes 285 SECCompressFile provides a SetCompressedMode() method to treat the file as a compressed file type or as a normal CFile type. The user can treat the entire file as a single compressed block of data or jump to known locations and decompress a smaller portion.
16.2.2 Using SECCompressFile
The following sections describe how you can write and read compressed data.
To write to a file in compressed file format:
1. Create an instance of SECCompressFile.
2. Call the WriteHuge() method to write out data in a compressed file format.
3. Close SECCompressFile.
To read a compressed file:
1. Create an instance of SECCompressFile.
2. Call the ReadHuge() method to read data from the compressed file format.
3. Close SECCompressFile.
To compress CDocument data:
Override the CDocument::GetFile() method as follows:
CFile* CMyDoc::GetFile(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError) {
SECCompressFile* pFile = new SECCompressFile(lpszFileName, nOpenFlags); return pFile; }
16.2.3 SECCompressFile Sample
See the Objective Toolkit CFiles sample in the Samples\Toolkit\MFC\Utility\CFiles directory for an example of how to use SECCompressFile. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
286 16.3 Encrypted File I/O
Objective Toolkit provides a class to support encryption and decryption services for data written to and from a file.
Objective Toolkit provides the following modes:
Electronic Codebook (ECB)
Output Feedback Mode (OFB)— also known as Cipher Feedback (CFB).
The following sections describe the features and limitations of this encryption capability.
16.3.1 Electronic Codebook (ECB)
Electronic Codebook is moderately secure and allows random access reads and writes. The appli- cation of sophisticated cryptographic methods allows easier recovery of the contents of each of two or more files encrypted with the same password. Encourage your users to change their passwords frequently or implement another layer of key management.
16.3.2 Output Feedback Mode (OFB)
Output Feedback is more secure than ECB, but file access is unidirectional and sequential only. Therefore, an SECCryptoFile secured with OFB may be opened in either CFile::modeRead or CFile::modeWrite modes, but not both. Seek functions are not available in Output Feedback mode.
16.3.3 The SECCryptoFile Classes
Objective Toolkit provides file encryption services through the SECCryptoFile class and its helper SECBlackBox. Figure 134 – The Objective Toolkit Encryption Class Hierarchy
CFile
SECCryptoFile
16.3.3.1SECCryptoFile
SECCryptoFile, a CFile derivative, provides encryption and decryption for data written to and read from a file. You need to assign a password to your user and he, in turn, must choose an encryption method. The encryption algorithms are described in detail in the following sections.
This class provides only medium-grade encryption. In other words, it is only intended to stop novice to intermediate hackers from accessing your data. If you require higher levels of security, patent and export laws come into play.
Chapter 16 Utility Classes 287 16.3.3.2SECBlackBox
The SECBlackBox class is a helper class that encapsulates the encryption algorithm itself.
16.3.4 The Encryption Algorithm
The algorithm involves two or three phases:
Password transformation,
Stream cipher, and
Output Feedback (OFB mode only).
First, SECBlackBox transforms or hashes the password you selected into an array of 72 seemingly random characters that bear no resemblance to the original password. Then SECBlackBox uses this 72-byte passphrase to generate three keys – 23, 24, and 25 bytes in length.
During read or write operations, the SECBlackBox class subjects the data stream to what is known as a triple-key Vigenere cipher. The Vigenere cipher is called a symmetrical cipher, because you can use the same algorithm and key to encrypt and to decrypt.
16.3.4.1Password Transformation
The password provided by the user is subjected to a hashing function to transform it into a 72-byte apparently scrambled character string, regardless of its initial size. The hashing function is as follows:
void SECBlackBox::HashString( char *from, int fromSize, char *to, int toSize ) { unsigned char p=0;
for (int i = 0;i < toSize;i++) { p += ( 17 * ( from[i%fromSize] + i ) ); to[i] = (from[i%fromSize] * p ) + from[(i+1)%fromSize]; } }
In the preceding function, the string in from, fromSize characters long, is hashed into a buffer at to, toSize bytes long.
16.3.4.2The Stream Cipher
The SECBlackBox uses a triple-ranked Vigenere cipher. In this implementation, the circular buffer or mask consists of three separate submasks that are combined to produce a final mask value with which the plain text is enciphered. In other words, given buffers B1, B2, and B3, with lengths l1, l2, th and l3, respectively, the mask value M[i] for the i character of the message would be:
M[i] = B1[i%l1]^B2[i%l2]^B3[i%l3];
288 The three buffers are filled as follows: the 72-byte hashed key is split into three subkeys – 23, 24, and 25 bytes long. Each key is loaded into a circular buffer, an instance of the class CCryptoRotor. Each rotor is then set with position zero selected. To encrypt (or decrypt at the lowest, or Vigenere level, this is a symmetrical cipher) a character, the mask character for each byte of the plaintext is generated as above. The mask character used to encrypt/decrypt the next character of plaintext, and then each rotor is advanced one position (the pointer is incremented and wrapped, if necessary). The rotor sizes are relatively prime, so the three wheels do not align the same way (and produce the same mask key) until 23 x 24 x 25 encryptions or decryptions have been performed. So, the effective key length is 13,800 bytes.
16.3.4.3The Cipher Modes
The stream cipher operates in either electronic codebook mode (ECB) or output feedback mode (OFB). Output feedback mode is also known as cipher feedback mode (CFB).
ECB mode is the simplest and each character is treated independently. It is potentially less secure, but more tolerant of media errors in the file. You can use ECB to access data randomly. After the first XORing stage, the ciphertext byte is output, and the next plaintext byte is read. Because no information is carried from one byte to the next, any (1 byte) error in the stored file results in only one character being decrypted incorrectly. Figure 135 – Electronic Codebook (ECB) Ciphering Topology
OFB adds an additional XOR to the three-step key XORing. The last character encrypted becomes part of the key for the next character. This has the effect of making the keystream at any point dependent on the message that preceded it. OFB is more secure than ECB, but if any errors are introduced into the encrypted file by an attacker or media failure, the remainder of the file becomes corrupted. This technique makes the cipher harder to crack, but as soon as a byte is read in incor- rectly, the remainder of the message becomes indecipherable. Additionally, the sequential nature of the cipher limits the use to sequential access to a file. To this end, the seek-related functions are dis- abled in OFB mode, and they fire an ASSERT when used.
Chapter 16 Utility Classes 289 Figure 136 – Cipher Feedback (OFB) Ciphering Topology
16.3.5 Limitations
Most stream ciphers, particularly the Vigenere cipher, are technically less secure. The triple-ranked Vigenere cipher in ECB mode is harder to break than a short single-rank Vigenere. The triple- ranked Vigenere in OFB mode is more secure than an ECB mode cipher. Be aware, though, that this algorithm does not provide a great deal of security against governments and well-funded or highly skilled cryptographers.
Decryption of data files is easier for the sophisticated attacker if he or she is given two or more dif- ferent files encrypted with the same key or password. However, this advantage is diminished greatly if the files are encrypted using OFB mode. This weakness might become apparent to a sophisticated attacker, but it will probably elude the average hacker.
16.3.6 Using SECCryptoFile
An SECCryptoFile is used almost the same way as a CFile is used, with a few exceptions. For example, you can open an SECCryptoFile without a password.
You can open an SECCryptoFile in either ECB or OFB modes. This is specified in the eModeCipherMode argument. If the SECCryptoFile is opened in OFB mode, it cannot be opened for random access or for Read and Write capability at the same time. An ASSERT fires if this mistake is made. To open a file called SECRET.DAT in read mode with cipher feedback and with password ABRACADABRA, you would create your CFile as shown in the following examples.
16.3.6.1To encrypt data to a file
1. Instantiate an SECCryptoFile object. For example:
SECCryptoFile fEncrypted;
2. Open the file for writing using the Open() method, supplying a password and encryption mode. For example:
290 fEncrypted.Open(“secret.dat”, “abracadabra”, Cfile::modeRead, SECCryptoFile::OFB);
3. Call the Write() or WriteHuge() methods to write data to the file.
FEncrypted.WriteHuge(pBuffer, nCount);
CFile::modeReadWrite and the Seek methods are only available in ECB mode.
16.3.6.2To read an encrypted file
1. Instantiate an SECCryptoFile object. For example:
SECCryptoFile fEncrypted;
2. Open the file for writing using the Open() method, supplying a password and encryption mode.
fEncrypted.Open(“secret.dat”, “abracadabra”, Cfile::modeWrite, SECCryptoFile::OFB);
3. Call the Read() or ReadHuge() methods to read data from the file.
NBytesRead = FEncrypted.ReadHuge(pBuffer, nCount);
CFile::modeReadWrite and the Seek methods are only available in ECB mode.
16.3.7 SECCryptoFile Sample
See the Objective Toolkit CFiles sample (Samples\Toolkit\MFC\Utility\CFiles) for an exam- ple of how to use SECCryptoFile. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Get- ting Started Guide.
Chapter 16 Utility Classes 291 16.4 Safe Multi-Threaded Trace Output
Objective Toolkit now includes support for safe, synchronized logging of trace-type output from within multi-threaded code. Using objects derived and instantiated from the base template class MultiTrace, developers of multithreaded applications can implement synchronized output from multiple threads to a common text file. Features of this class include:
Optional synchronization. The base MultiTrace class is a template that takes as one of its parameters a trait or behavior class into which the synchronization behavior has been factored. Implementations of this trait have been provided for both single and multi-threaded behaviors; so, for example, if you instantiate from base class MultiTrace using trait class SingleThreadLogTraits as a parameter, synchronization is disabled. However, if you instantiate using trait class MultiThreadLogTraits as a parameter, synchronization is enabled. In the header file, we have provided simple typedefs for each of these choices. If some other type of behavior is desired, the user has the option of deriving and using a custom trait class.
Printf-type syntax. Client code invokes methods on the multithreaded logging object using familiar syntax (i.e. format string followed by a variable list).
Optional and configurable tags for log output. Users have the option of specifying tags that appear before and after each piece of log output. A default tag style is provided that includes thread ID and the time (hour:minute:second:millisecond) of the output.
Optional file size threshold. A size (character count) can be specified for the logging object, which represents a count after which file output restarts back at the top. This will be convenient for applications that run unattended, as it will prevent the output file from growing indefinitely.
Optional base64 conversion of binary data. Binary data may be base64 converted into printable text before being written to the output stream.
Optional exception handling. By default, exceptions arising from trace log operations are NOT thrown back to client code. This will probably be the preferred mode for production applications. However, exception handling can be turned on so that exceptions within the logging code are thrown back to the client.
16.4.1 Use of the Multi-Threaded Logging Class
Using the logging class is straightforward.
1. Include these two files:
MultiTrace.h
MultiTraceException.h
2. Declare an instance of the MultiTrace class:
multithreadedlogger mt;
This should have file scope. Note that this declaration uses one of the typedefs from MultiTrace.h, which is synonymous with:
292 MultiTrace
As mentioned above, a non-synchronizing, single-threaded version is provided also, typedefed as singlethreadedlogger.
3. Set the desired properties of the logger, and call initialize():
mt.fname=_T(“c:\logfile.txt”); mt.initialize();
4. In your thread procedure where you desire to log output, invoke an output method:
mt.LogWrite(_T(“At this point, the value of x is %i”),x);
By default, this output will be bracketed in the output file by HTML-like tags, which incor- porate the thread ID and the time (to the millisecond):
<25c 15:24:10.0024> At this point, the value of x is 4
The MultiTrace object will perform the file I/O operations in a critical section so that I/O from multiple threads in your application will be properly sequenced in the output stream.
Binary data can be logged as well (converted to text via base64 conversion) through method LogBinary(). Arguments for this method are a pointer to the item and its length. For example, assume oStructure is a data structure in memory. The following code will convert the contents of the structure via base64 conversion and output them to the log file:
Mt.LogBinary((void*)&oStructure,sizeof(oStructure));
This will produce output resembling the following:
<16c 15:24:09.0703>UAAZAAAAAAAHAAAAAABPABgAUAAZAA==
When your MultiTrace object falls out of scope, its destructor will be called, which in turn will close the output file and free up any buffers allocated for the purpose of base64 conversion of binary data.
See the MultiThreadLog sample console application (sample\toolkit\MFC\utility) included with the product for an example of the setup and use of the multithreaded logging class.
This class has no dependencies on MFC.
Chapter 16 Utility Classes 293 16.5 File System Access
The Objective Toolkit file system class provides access to common file system functions, such as reading a directory or copying a file. The class also encapsulates parsing and CStringList methods.
16.5.1 SECFileSystem
SECFileSystem is a class that allows you to access common file system functions such as retrieving general information about files and directories, reading directories, copying files, and more. Figure 137 – The Objective Toolkit File System Class Hierarchy
CObject
SECFileSystem
16.5.2 Using SECFileSystem
SECFileSystem can help create code for the following tasks. Please see the Objective Toolkit Class Reference or online help for a full list of methods for this class.
16.5.2.1To copy a file
Call the CopyFile() method. For example:
SECFileSystem fs; BOOL bRetVal = fs.CopyFile("foo.txt", "a:\\bar.txt");
16.5.2.2To copy multiple files
Call the CopyFiles() method. For example:
SECFileSystem fs; BOOL bRetVal = fs.CopyFiles("c:\\foo\\bar\\*.txt", "c:\\foo2");
16.5.2.3To compare two files
Call the CompareFiles() method. For example:
SECFileSystem fs; BOOL bRetVal = fs.CompareFiles("foo.txt", "bar.txt", 20480);
294 16.5.2.4To delete a file
Call the DeleteFile() method. For example:
SECFileSystem fs; BOOL bRetVal = fs.DeleteFile("c:\\foo.txt");
16.5.2.5To delete multiple files
Call the DeleteFiles() method. For example:
SECFileSystem fs; BOOL bRetVal = fs.DeleteFiles("c:\\foo\\bar\\*.txt");
16.5.2.6To get information about a file
Call one of the following methods:
GetFileAttribute()
GetFileStatus()
GetFileModifyTime()
GetFileAccessTime()
GetFileSize()
For example:
SECFileSystem fs; BOOL bRetVal = fs.GetFileAttribute("c:\\test.txt", bAttr);
16.5.2.7To parse filename information on a file
Call one of the following methods:
GetFullPathName()
GetBaseFileName()
GetExtension()
GetFileName()
GetFileSystem()
GetPath()
For example:
SECFileSystem fs; CString strPath; strPath = fs. GetFullPathName("c:\\test\\.\\..\\foo\\bar\\what.txt"); ASSERT(Path == "c:\\foo\\bar\\what.txt");
Chapter 16 Utility Classes 295 16.5.2.8To get a list of files in a directory
Call the GetDirectory() method. For example:
SECFileSystem fs; CStringList *pDir = fs.GetDirectory("*.txt", SECFileSystem::normal, TRUE); fs.GetDirectory("*.doc", normal, TRUE, pDir);
16.5.2.9To create a directory
Call the MakeDirectory() method. For example:
BOOL bRetVal = fs.MakeDirectory("c:\\foo\\bar");
16.5.2.10To change the working directory
Call the ChangeDirectory() method. For example:
BOOL bRetVal = fs.ChangeDirectory("c:\\foo\\bar");
16.5.3 SECFileSystem Sample
The Objective Toolkit filedemo sample (Samples\Toolkit\MFC\Utility\filedemo) demon- strates the use of the SECFileSystem class. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
296 16.6 Random Number Generation
SECRandom is a utility class for generating random numbers.
An instance of SECRandom is initialized with an integer seed value from which random numbers are derived. If a seed of zero (0) is provided, a seed based on the current system time is used.
SECRandom can provide a random value within a range by specifying an upper and lower bound for the range. SECRandom can also generate a skewed random result based on an array of weights specified by the user.
Each entry of the array of weights specifies an unsigned integer value (the weight) that specifies the probability that a random number will fall in that position. A higher number increase the prob- ability that a random number will be generated for that position. For example, consider a weighted array of 4 weights with the following values.
Position Weight
01
17
20
32
The sum of the weights is 10. So there is a 10 percent chance that a random number of 0 will be gen- erated, a 70 percent chance for a random number of 1, no chance for a number of 2, and a 20 percent chance that a value of 3 will be generated. These weights can be obtained using the GetRandomWeighted() method.
16.6.1 The SECRandom Class
The SECRandom class provides a method for generating a random number based on a seed value. To skew the results of the random number generation, SECRandom also supports weighted vectors. Figure 138 – The Objective Toolkit Random Number Generator Class Hierarchy CObject
SECRandom
SECRandom acts as a front end to the srand() run-time function. With SECRandom, you can set the effective range for the random integer you want to generate. You can also establish a weighted vector array to specify the distribution of the generated values.
Chapter 16 Utility Classes 297 16.6.2 Using SECRandom
The following sections show how to generate random numbers from uniform and weighted distributions.
16.6.2.1To generate an unsigned random number (0 to 32767)
Create an instance of SECRandom. If you want, you can also set a seed value. Call GetRandom() to return an unsigned integer (0 to 32767). For example:
SECRandom rnd(m_nSeed); UINT result = rnd.GetRandom();
If no seed value or a seed value of zero (0) is entered (default), SECRandom generates a seed based on the current time. This is useful if you don’t want to duplicate the sequence of random numbers for different trials.
16.6.2.2To set the range of the random numbers generated
Call the SetUBound() and SetLBound() methods. The upper bound must always be greater than the current lower bound and the lower bound must be less than the current upper bound. An example of initializing an instance of SECRandom and setting the desired result range from 100 to 500 is shown below:
void GenerateRandom() { // Initialize with seed value of 50 SECRandom *pRandom = new SECRandom(50);
// Set a range of 100 to 500. pRandom->SetLBound(100); pRandom->SetUBound(500);
// retrieve a random value in the desired range UINT result = pRandom->GetRange(); delete pRandom; }
You can use an overload of GetRange() to set the range and return a value in one step.
16.6.2.3To generate weighted random values
You can assign a weighted set of vectors to an SECRandom instance to change the distribution of the random values. For example, in a given range of 0 to 9, you might want to place a 70 percent chance of generating a result of 5, a 20 percent chance of generating a result of 2, and a 10 percent chance of generating a 1.
1. Instantiate an object of the SECRandom class. For example:
SECRandom rnd(nSeed);
298 2. Initialize a weighted vector array in SECRandom with the InitWeights() method.
// Initialize 10 entries in the weighted vector list pRandom->InitWeights(10);
3. Assign the desired percentages with the AddWeight() method.
// Assign the weights for the probabilities: // 10% to generate a 1 // 20% to generate a 2 // 70% to generate a 5. pRandom->AddWeight(1,10); pRandom->AddWeight(2, 20); pRandom->AddWeight(5, 70);
4. To retrieve a weighted vector result, call the GetRandomWeighted() method.
// Retrieve the result pRandom->GetRandomWeighted();
16.6.2.4Key SECRandom Methods
Here is an overview of some of the key SECRandom methods:
SetBounds(). Sets the range of the random number to be generated.
AddWeight(). Adds an entry to the weighted vector array.
InitWeights(). Initializes the weighted vector array. (Specifies the number of weights to use.)
GetRandom(). Returns a random number between 0 and 32767, inclusive.
GetRandomWeighted(). Returns a weighted random number based on the current weight vector.
GetRange(). Returns a random number within the current range.
GetSeed(). Retrieves the current seed value from which random numbers are generated.
16.6.3 SECRandom Sample
The Objective Toolkit randemo sample (Samples\Toolkit\MFC\Utility\randemo) illustrates how to use SECRandom. This sample does not ship with the product. For information on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 16 Utility Classes 299 16.7 Formula Engine
Objective Toolkit now includes a Lex (Flex)-based formula evaluation engine. By instantiating objects of the toolkit-defined class SRFormulaScanner, developers can easily add formula evalua- tion functionality to their applications.
16.7.1 Features of the Formula Scanner
The formula scanner:
Supports decimal and hexadecimal representations of numeric input.
Supports all common arithmetic, trigonometric, and bitwise logical functions.
Supports common string operations (e.g., LEFT, MID).
Tests for formula validity and error explanations.
Is usable in Unicode and single-byte character mode applications.
Parsing is driven by a Flex-generated, finite state, machine type, regular expression parser.
16.7.2 Use of the Formula Engine Class
Use of the formula engine class is straightforward.
1. In any source file in which you wish to incorporate formula evaluation functionality, include the following toolkit-supplied header files, as follows:
#include
2. Declare an instance of the formula engine class, as follows:
SRFormulaScanner scan;
3. Set the formula, tell the formula engine to evaluate it, and extract the answer (or an error message), as follows:
scan.lex(_T("SUM(3,4,(6 * (4+SQRT(9))))")); if (scan.IsValid()) { _TCHAR *cb = NULL; scan.GetResult(&cb); //cb now points to the answer, formatted as a string if(cb) free(cb); //since the answer string is dynamically allocated //within the formula engine, you must free it to avoid a //memory leak }
300 else { _TCHAR * errdesc = NULL; scan.GetErrDescription(&errdesc); //errdesc points to an error message string. //this string is not dynamically allocated, and //therefore does not have to be freed. }
See the sample included with the product for an example of how the formula engine can be used.
Chapter 16 Utility Classes 301 16.8 Win32 Registry Access
Objective Toolkit provides an encapsulation of the Win32 registry APIs. Using Objective Toolkit’s registry abstraction, you can modify the registry through a common interface consistent under all supported platforms.
SECRegistry encapsulates the APIs used to access and modify the Windows registry in a single class. The bulk of the SECRegistry methods are wrappers for the Win32 API. One advantage of using the class instead of the Win32 API is that you can recursively delete keys in a 32-bit environment.
16.8.1 The SECRegistry Class
The SECRegistry class encapsulates the Win32 registry API. An SECRegistry instance contains a member handle to a registry key. This same key is then used as a parameter to some of the Win- dows registry APIs (SECRegistry shields the user from having to keep track of the handle). Figure 139 – Objective Toolkit’s Registry Class Hierarchy
CObject
SECRegistry
16.8.2 Using SECRegistry
The following terms are used in the following descriptions:
Keys. Nodes that can contain one or more keys or values. A key is like a folder that can contain other folders (keys) or items (values).
Values. An item that is contained by a key that has two attributes: a name and an associated evalu- ation. For example:
Name Value
“Path” “C:\Program Files\WordView\WordView.exe”
“Password” “GX325PF”
Version 5.1
The following section show you how to use SECRegistry to modify registry settings.
302 16.8.2.1To open the registry
Call the Connect() method. If a computer name is specified, the application attempts to open the registry remotely. There must be sufficient permissions for remote registry connections to work. For example:
// connect to the local registry m_registry.Connect(HKEY_CURRENT_USER);
// connect to a remote registry m_registry.Connect(HKEY_LOCAL_MACHINE, _T(“\\\\TARZAN”));
16.8.2.2To open a subkey
1. Connect() to the registry.
m_registry.Connect(HKEY_CURRENT_USER);
2. Open the subkey with the Open() method.
m_registry.Open(_T(“Software”));
16.8.2.3To enumerate registry keys
1. Connect() to the registry.
m_registry.Connect(HKEY_CURRENT_USER);
2. You can also open a subkey.
m_registry.Open(_T(“Environment”));
3. Call the EnumerateKeys() method.
// Enumerate all the subkeys // and add them to the listbox DWORD dwCount = 0; CString strKey; CString strClass; while (m_registry.EnumerateKeys(dwCount++, strKey, strClass)) pListBox->InsertString(-1, (LPCTSTR)strKey);
16.8.2.4To enumerate values within a key
1. Connect() to the registry.
m_registry.Connect(HKEY_CURRENT_USER);
2. You can also open a subkey.
m_registry.Open(_T(“Environment”));
Chapter 16 Utility Classes 303 3. Call the EnumerateValues() method.
DWORD dwCount = 0; Cstring strName; SECRegistry::KeyValueTypes typeCode; while (m_registry.EnumerateValues(dwCount++, strName, typeCode)) pListBox->InsertString(-1, (LPCTSTR)strName);
16.8.2.5To read a value
1. Connect() to the registry.
m_registry.Connect(HKEY_CURRENT_USER);
2. You can also open a subkey.
m_registry.Open(_T(“Environment”));
3. Call one of the following methods to retrieve the value. These methods assume you know the type of the value. See Section 16.8.2.4.
GetBinaryValue() GetDoubleWordValue() GetStringArrayValue() GetStringValue()
4. You can also call one of the overloaded GetValue() methods or the QueryValue() method.
16.8.2.6To create a key
1. Connect() to the registry.
m_registry.Connect(HKEY_CURRENT_USER);
2. You can also open a subkey.
m_registry.Open(_T(“Software”));
3. Call the Create() method to create the new key.
m_registry.Create(_T(“MyKey”));
16.8.2.7To delete a key
1. Connect() to the registry and open the parent of the key about to be deleted.
m_registry.Connect(HKEY_CURRENT_USER); m_registry.Open(_T(“Software”));
2. Call the DeleteKey() method to delete a particular subkey.
m_registry.DeleteKey(_T(“MyKey”));
304 DeleteKey() fails if the key being deleted contains subkeys. To delete subkeys, you need to specify a recursive delete operation. See Section 16.8.2.8.
16.8.2.8To recursively delete keys
1. Connect() to the registry, and open the parent of the key about to be deleted.
m_registry.Connect(HKEY_CURRENT_USER); m_registry.Open(_T(“Software”));
2. Call the DeleteKey() method to delete a particular subkey and specify a recursive delete.
m_registry.DeleteKey(_T(“MyKey”), TRUE); // TRUE = recursive delete
Be careful when recursively deleting registry keys!
16.8.2.9To close a registry connection
Call the Close() method. m_registry.Close();
If this method is not called explicitly, it is called implicitly by the SECRegistry destructor.
16.8.3 SECRegistry Sample
The Objective Toolkit regdemo sample (Samples\Toolkit\MFC\Utility\regdemo) illustrates how to use SECRegistry in a 32-bit environment. This sample does not ship with the product. For infor- mation on how to obtain this sample, see Section 3.6.1, “Location of Sample Code,” in the Stingray Studio Getting Started Guide.
Chapter 16 Utility Classes 305 306 Chapter 17 Data Extraction Classes
17.1 Overview
17.1.1 Building the Libraries
Developers can use Objective Toolkit’s data extraction classes to extract data from text streams. These classes depend on an underlying third-party regular expression library, Regex++1. The Regex++ v.2.2.4 library is distributed and installed with Objective Toolkit. The URL for the Regex++ Web site (as of the publication date of this manual) is http://www.boost.org/doc/libs/1_40_0/libs/regex/doc/html/index.html
Read the regex.htm document (located at
1Regex++ is distributed under the following copyright, which is reproduced here as required.
Regex++ Copyright © 1998-9 Dr. John Maddock Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documenta- tion. Dr. John Maddock makes no representations about the suitability of this software for any purpose. It is provided “as is” without express or implied warranty.
To build the Objective Toolkit data extraction classes:
1. Run the Objective Toolkit Build Wizard.
2. Select HTML data extractor under the Utility Classes section in Objective Toolkit.
Chapter 17 Data Extraction Classes 307 Figure 140 – Select HTML data extractor when running the Objective Toolkit Build Wizard.
3. Build the Objective Toolkit libraries with the new make files generated.
Regex++ is used to facilitate the new HTML export functionality. The HTML data extractor compo- nent requires the Regex library, which makes powerful regular expression matching functionality available to projects incorporating Objective Toolkit.
Objective Toolkit has an optional dependency on the Regex++ library, which in turn has other dependencies. As a result, additional files (other than the Objective Toolkit DLLs themselves) may need to be distributed with your application.
The Toolkit build wizard now contains a checkbox to enable or disable the requirement for Regex. This checkbox is unchecked by default. Regex library solution files have also been updated to output the Regex libraries to the appropriate MFC product library directory by platform. For example, Win32 VC++ 8.0 Regex libraries are now output to
308 17.1.2 Using Regular Expression Libraries
PERL and other such languages are commonly used to solve the frequently encountered program- ming problem of extracting and manipulating text stream data. We can also use tools such as lex and yacc to create custom scanners.
C++ has several regular expression libraries that can provide similar functionality. It is possible to extract information from text streams quite easily using regular expression libraries. Consider the following text:
City of Raleigh, NC, temp at 7 P.M. 52 degrees
Using a regular expression like the one shown below, it is easy to extract—as data elements—the city name, state, and the temperature at a certain time.
City of ([a-z]*), ([a-z]{1,2}), temp at ([0-9]{1,2}) (P.M|A.M). ([0- 9]{1,3}) degrees
Chapter 17 Data Extraction Classes 309 17.2 Data Extraction Framework
Since the Web has become a huge virtual database of sorts, more and more often these days we find ourselves wanting to scrape data from Web sites (although this tactic may not be legal or allowed on some sites).
However, most data commonly available on the Web is in HTML format, which cannot be easily processed by software systems that do not understand HTML presentation. Most systems that extract and process data from the Web (including shopping agents, personal news bots, etc.) fall into this category.
When you extract only the required data from HTML streams, software systems designed to pro- cess that data can easily consume it — without regard to its formatting. With simple HTML streams (such as the one listed above) this is not a very difficult process. Any regular expression scanner will do nicely. With more complex files though, this quickly becomes quite difficult. The following issues are the biggest stumbling blocks.
An entire HTML file cannot be scanned with a single expression. To get meaningful results, several expressions need to be written and need to work in tandem—with precise control over which expression gets evaluated when. In lex this would typically be done using states.
HTML data available on the Web is volatile. One reason that a scanner built using lex would be difficult to maintain is that changes will break the scanner. Each time the HTML data changes, the scanner code will have to be regenerated using lex and binary updates will need to be made to the software system.
Stingray developers considered these two issues carefully when designing the Objective Toolkit library. With reference to the first issue, the system that we have in place does not provide much of an advantage over lex (or other such systems). We offer the same functionality in terms of states. However, we believe that we have a more object oriented, easily extensible solution for the follow- ing reasons:
The underlying library (Regex++ by Dr. John Maddock) is very well written and maintainable.
The wrapper that we have around Regex++ is also very extensible.
We support Unicode.
We provide easy macros that can be used to add states.
Listeners can be plugged into the data scanning process as required.
The library takes advantage of other C++ niceties, such as exceptions.
With reference to the issue of HTML data volatility, our approach has an important advantage. With lex, a binary generation is required each time there is a change in the Web information. With our approach this is not strictly needed.
310 17.3 Example: Setting Up a Scanner
With this bit of background information under our belt, let us now look at how we setup a scanner.
It would help to compile the Deals sample at this point. This sample does not ship with the product. If you need this sample, please submit a request to Stingray customer support.
17.3.1 Introduction to the Deals Sample
The Deals sample retrieves the main page from http://www.thedailydeals.com (a Web site that has information on Web deals). It parses the information available at the site and populates a list control. Clicking on a link in the list control will take you directly to that link. This sample can auto- matically run every few minutes to gather this data, parse it, and populate the list control.
17.3.2 Declaring the Processor
When using the data extraction framework, you will usually need to concern yourself with only two major classes—the data processor class (CRgProcessor), which contains and drives the data extraction process, and the listener class (CRgDefListener), which acts as a stub for any feedback generated from the scanning process.
In the Deals sample, Class CDealProcessor (derived from CRgProcessor) is declared as shown below:
class CDealProcessor : public CRgProcessor { public: enum states { estateNormal, estateDeals, };
enum tokens { etokenDealName, etokenExpired, etokenNotExpired, etokenRef, };
// required override // put all your initialization code here using the // provided macros for easy maintenance void Initialize(); };
Chapter 17 Data Extraction Classes 311 Typically, this is how we recommend that you declare your own processors. There should be an enum declaration for tokens that will be recognized by the scanner. There should be an enum declaration for states that the scanner will traverse.
The steps for writing code to scan a text stream are:
1. Identify the tokens that you want to read from the stream.
2. Define an enum and add a value for each of these tokens.
3. Consider how you will extract the information, thinking ahead about the states and sub states to use to facilitate implementation.
For example, if you are looking at stock information from www.Yahoo.com you may be looking at data much like the listing below. (A series of three dots indicates where code has been deleted for brevity.)
. . .
N/A
Small: [1d | 5d | 1y | none]
Big: [1d | 5d | 3m | 1y | 2y | 5y]
5 3/4 - 6 3/16
5 3/4
5 7/8
6 1/8
49,818
N/A
3 - 12 7/8
-0.06
N/A
63.3M
N/A
N/A
. . .
312
. . .
In the HTML above, we have highlighted (in bold) the portions of interest—the stock quote area and the news area. To scan these areas you need different regular expressions. This usually implies that you should have these two areas denoted by different states.
Within each state, you may need to extract each needed token in a different manner. On the Yahoo! page, for example, you have to extract the title heading of the news link in a different manner than you will extract the article reference. Each of these would be sub states within the encompassing state. Sub states are not important when you define the token enum values; however, thinking about the sub states ahead of time makes implementing the scanner easier.
17.3.3 Implementation Details
Now that you understand the rationale for the two enum definitions, consider the data that we scan when interacting with http://www.thedailydeals.com. If you make a request to http://www.thedailydeals.com and click View|Source (or the equivalent command in your browser) you will see the entire HTML stream that returns from the server. The sample makes an HTTP request for the default page using the Microsoft Wininet library.
Chapter 17 Data Extraction Classes 313 17.3.3.1Token Definitions
Based on the data available at the Web site, we determined the information to extract (shown in Table 42). This should lead us to the token definitions. Therefore, the following tokens correspond to the three pieces of information we want.
Table 42 – Information and token definitions
Information Required Token Definition
The description of the deal. etokenDealName
The link to it on the Daily Deals Web site. etokenRef
Whether the deal has expired or not. etokenExpired
To make the interpretation of the feedback data a little easier in the sample, we have a separate token for the expired state and the not expired state. We could have passed the token as it is and then looked at the string to see if it was expired or not expired. However, because we have two dif- ferent tokens, the regular expression engine will do the work for us.
This leads us to define the following four tokens:
enum tokens { etokenDealName, etokenExpired, etokenNotExpired, etokenRef, };
17.3.3.2States
The next part is kind of heuristic in nature; each person may come up with a different solution. Looking at the chunk of data returned from the site, we came up with the following states:
{ estateNormal, estateDeals, };
estateNormal is the state that we start with. When we see the start of the deal listings we go into estateDeals. If we find another deal, we continue in estateDeals. If not, we exit the scanner.
The next step is to decide how we go about shifting between the states and what data we collect in each state. The conclusions of this exercise are translated into code using macros provided in the body of the Initialize() function (in the processor).
Each individual state is started with the macro rg_start_state(). This macro takes two parame- ters—the name of the state variable and the name of the state identifier token (one of the possible values of the state enum that we defined earlier). Inside the state declaration we can add sub states as desired. Each sub state is defined by an rg_sub_state()macro. This takes a token ID (from the enum that we defined earlier for this purpose) and the regular expression that extracts the data.
314 17.3.3.3Sub Expressions
Be sure to place any data that you wish to collect inside parentheses so that a sub expression is defined. See Table 43 for an example.
Table 43 – Defining a sub expression
General sample form... Regular expression should be...
My name is John. My name is (.*)
Any token that is scanned will have the sub expressions available. These can be used to initialize our data easily.
You can add any number of sub states within each state. Each of these sub states will be OR’d (com- bined) with the others to create a composite expression for that state. This implies that you should not try to gather data using separate regular expressions (defining two sub states) when there is overlap. Instead, combine these into the same expression. For example, consider:
Table 44 – Using separate regular expressions
For example... Don’t do this... Do this...
My name is happyface; my My name is ([a-z]*); my My name is ([a-z]*); my e-mail address is e-mail address is happy- e-mail address is (.*) happy- [email protected] [email protected]. dmy e-mail address is (.*)
Each sub state also takes a third parameter that specifies the action that should be taken when a scan is complete. This can be one of three possible values.
CRgSubState::stateContinueImplies that no change in state will take place if that expression is matched. The next scan will also be with the same effective state.
CRgSubState::stateNoNextImplies that as soon as this sub state is matched the scanning process will terminate.
Custom Tokens—These can be any of the state tokens that have been defined earlier. After a match is made, processing will shift to the state that is denoted by this state identifier.
End the state with rg_end_state(). You can have any number of states within the processor.
The Deals sample implements the required Initialize() function as shown below: void CDealProcessor::Initialize() { rg_start_processor(this)
rg_start_state(stateNormal, estateNormal) rg_sub_state(CRgSubState::tokenNone, _T("(class=\"show\">This Month)"), estateDeals) rg_end_state()
rg_start_state(stateDeals, estateDeals) rg_match(match_any)
Chapter 17 Data Extraction Classes 315
rg_sub_state(etokenRef, _T("(href=\"(.*)\")"), CRgSubState::stateContinue)
rg_sub_state(etokenDealName, ,_T("(class=\"newsquick\">([^<>]*))"), CRgSubState::stateContinue)
// ignore the date
rg_sub_state(CRgSubState::tokenNone, ,_T("(class=\"newsquick\">([0-9/]*)
rg_sub_state(etokenExpired, _T("( Expired
rg_sub_state(etokenNotExpired, _T("()"), CRgSubState::stateContinue)
rg_sub_state(CRgSubState::tokenNone, _T("(View Deals From