MORE MFC DIALOG BOXES AND CONTROLS, DIALOG-BASED APPLICATIONS
MFC Dialog Box with a Combo Box Control
Sketch Application Color selection:
Menu choices==>many handler functions
Dialog Box w/ Edit control==>ambiguity
Better to use a listbox or combo box
Put color choices inside the box
Need:
CColorDlg class with member variables:
m_Combo (control derived from CComboBox)
Use AddString() member function to fill Combo box list
m_drawColor (string derived from CString)
Will contain the user selection
SktchComboColor Example <Show the program in action>
Start out with Basic Sketch MFC application (no color menu choices)
(Or remove Red/Green/Blue Drawing Color menu items from sketch)
Add "Drawing Color" menu item (IDM_DRAWINGCOLOR)
(Or remove Red/Green/Blue Drawing Color menu items from sketch)
"Drawing Color" Dialog Box--
Insert/Resource/Dialog/New
Label: "Drawing Colors", IDD_COLORDLG
Controls:
Static label ("Drawing Color", default ID)
Dropdown Combo Box control (IDC_DCOLOR)
Use ClassWizard to add--
New Class: CColorDlg
(1) Add IDC_DCOLOR member variables:
m_Combo (Category Control, type CComboBox)
m_drawColor (Category Value, type CString)
(2) Add a New Message Map for WM_INITDIALOG
Member Function: OnInitDialog()
Edit the code by adding the following:
// TODO: Add extra initialization here
m_Combo.AddString("Red");
m_Combo.AddString("Green");
m_Combo.AddString("Blue");
m_Combo.AddString("Black");
Add OnDrawingColor() Menu Command Message Map handler
Class: CSketchView,
ObjectID: IDM_DRAWINGCOLOR
Messages: Command
Edit the code by adding the following:
// TODO: Add your command handler code here
CColorDlg colDlg;
if(colDlg.DoModal()==IDOK)
{
if (colDlg.m_drawColor=="Red")
nColor=RGB(255,0,0);
if (colDlg.m_drawColor=="Green")
nColor=RGB(0,255,0);
if (colDlg.m_drawColor=="Blue")
nColor=RGB(0,0,255);
if (colDlg.m_drawColor=="Black")
nColor=RGB(0,0,0);
}
#include "ColorDlg.h" in the SketchView.cpp file
Build and run the application
Using the Common Color Dialog Box
CColorDialog--a class derived from CDialog
Encapsulates the "Common Color" dialog box
Allows user to select colors
Construct a CColorDialog object
Call its DoModal() function to start the dialog box
Invoke its GetColor() member function-->RGB value chosen
Use this in the sketching application
(Combo box above is limited to small number of colors)
SketchComColor Example <Show program in action>
Start out with Basic Sketch MFC application (no color menu choices)
Add "Drawing Color" menu item (IDM_DRAWINGCOLOR)
Use ClassWizard to Add OnDrawingColor() Menu command handler
Class: CSketchView,
ObjectID: IDM_DRAWINGCOLOR
Messages: Command
Edit the code by adding the following:
// TODO: Add your command handler code here
CColorDialog dlgColor;
if (dlgColor.DoModal()==IDOK)
nColor=dlgColor.GetColor();
Build and run the application
Text Fonts and the Common Font Dialog Box
FONT: Typeface, style, size of characters in a character set
Under Windows Fonts are "drawing objects"--
Must be selected into a Device Context to be used
There are three basic kinds of fonts-
Stock fonts-
Built into Windows
Always available
Logical or GDI fonts-
Defined in separate font resource files on disk-
.fon (stroke or raster) file
.fot/.ttf (TrueType) file
Stroke fonts-
Consist of line/curve segments
Continuously scalable
Slow to draw
Legibility not good
Raster fonts-
Bitmaps
Scaling by non-integer scaling factors difficult
Fast to display
Legibility very good
TrueType fonts-
Rasterized stroke fonts
Stored as strokes with hints to convert to bitmap
Continuously scalable
Fast to display
Legibility very good
Combine best of both stroke and raster fonts
Device fonts-
Native to output device (e.g., built-in printer fonts).
Using stock fonts--
Access with GetStockObject();
Returns a handle to a font
Select into DC with SelectObject();
Using Logical Fonts-
Can specify and create your own "Custom" font from available font files
In MFC, Font specification/creation is encapsulated in the CFont class
Two ways of using it:
(1) Call CFont::CreateFont(), passing 14 font description parameters
(2) Describe the font with a LOGFONT sturcture & pass ptr to
that structure in a call to CFont::CreateFontIndirect()
In each case, use SelectObject(&fnt) to select new font into the DC
CreateFont() can make new fonts by interpolating data in a font file
New sizes, bold/underlined, rotated/distorted characters
Called logical since generated by program logic
CFont fnt;
fnt.CreateFont(Ht, Width, Escapement, Orientation, Weight, Italic,
Underline, StrikeOut, CharSet, OutputPrecision,
ClipPrecision, Quality, PitchAndFamily, Facename);
Heights and average Widths--measured in logical units
Default logical unit of a screen DC: pixels
Escapement--Angle, in tenths of a degree, between line through the origins of first
and last characters on a line and the x-axis of the screen surface
Orientation--how much a character should be rotated, in tenths of degree
(900 == character is lying on its back)
Weight--How thickly to print character strokes
(FW_NORMAL=400, FW_BOLD=700, others)
Italic--TRUE/FALSE
Underline--TRUE/FALSE
StrikeOut--TRUE/FALSE
Characters with line through the center
CharSet--ANSI_CHARSET, SYMBOL_CHARSET, OEM_CHARSET, SHIFTJIS_CHARSET
OutputPrecision--How close output must match requested font height/width
orientation/escapement/pitch
Several possibilities
ClipPrecision--How to clip characters partially outside clipping region
Quality--DRAFT_QUALITY, PROOF_QUALITY , DEFAULT_QUALITY
PitchAndFamily-2 bitwise OR values
First (low order 2 bits): font pitch-
(DEFAULT_PITCH, FIXED_PITCH, VARIABLE_PITCH)
Second (high order 4 bits): font family-
(FF_DECORATIVE, FF_DONTCARE, FF_MODERN, FF_ROMAN,
FF_SCRIPT, FF_SWISS)
e.g., DEFAULT_PITCH | FF_ROMAN
Facename--String that specifies typeface name (style) of font data
Identifies font resource data file, e.g.:
Courier, MS Serif, MS Sans Serif, Symbol, Small, Modern, Roman,
Script Courier New, Courier New Bold, Courier New Italic, Courier
New Bold, etc.
Takes precedence over several other parameters
Example call to CreateFont()--
font.CreateFont(36, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,VARIABLE_PITCH|FF_ROMAN,"Roman");
Using CFont::CreateFontIndirect()--
1. Construct a CFont object
CFont font;
2. Set up a LOGFONT structure with desired font characteristics
LOGFONT lf;
typedef struct tagLOGFONT { /* lf */
LONG lfHeight;
LONG lfWidth;
LONG lfEscapement;
LONG lfOrientation;
LONG lfWeight;
BYTE lfItalic;
BYTE lfUnderline;
BYTE lfStrikeOut;
BYTE lfCharSet;
BYTE lfOutPrecision;
BYTE lfClipPrecision;
BYTE lfQuality;
BYTE lfPitchAndFamily;
CHAR lfFaceName[LF_FACESIZE];
} LOGFONT;
3. Call member function CreateFontIndirect(&lf)
font.CreateFontIndirect(&lf);
Common Font Dialog Box-
Allows user to choose a logical font from all available on system
An easily-used dialog box
Encapsulated in the CFontDialog class
Construct a CFontDialog object
Pass it a pointer to a LOGFONT structure
Call its DoModal() function to start the dialog box
After User chooses a font, the LOGFONT structure will have the data
LOGFONT m_logFont;
CFontDialog dlgFont(&m_logFont);
dlgFont.DoModal();
TextComFont Example <Show program in action>
Use AppWizard to create the TextComFont SDI application template
Add menu items:
"Text" (IDM_TEXT)
"Font" (IDM_FONT)
Insert a new "Text Entry Dialog Box" resource (IDD_TEXTDLG)
Controls (most as in sketch3: the last Session-9 Example):
"Text:" static control
Single-line edit control (IDC_TEXTEDIT)
"x:" and "y:" static controls
Single-line edit controls for each (IDC_X and IDC_Y)
"Angle" static control
Single-line edit control for text angle (IDC_ANGLE)
Use ClassWizard to:
Create the CTextDlg class (derived from CDialog)
Attach member Value variables to the CTestDlg class controls:
IDC_TEXTEDIT: m_text, type CString
IDC_ANGLE: m_angle, type UINT
IDC_X: m_x, type UINT
IDC_Y: m_y, type UINT
Add private member variables to the CTextComFontView class:
(i.e., right click on the CTextComFontView class in ClassView):
m_angle: type UINT
m_logFont: type LOGFONT
m_string: type CString
m_x: type UINT
m_y: type UINT
Add initialization construction code to the CTextComFontView class:
// TODO: add construction code here
m_x=m_y=m_angle=0;
m_string="";
ZeroMemory(&m_logFont,sizeof(LOGFONT));
lstrcpy(m_logFont.lfFaceName,"Times New Roman"); //Initial font
Add OnDraw() handler code to the CTextComFontView class:
// TODO: add draw code for native data here
CFont fnt; //Create and select the chosen font/angle
m_logFont.lfEscapement = m_angle*10;
fnt.CreateFontIndirect(&m_logFont);
CFont* pOldFont = pDC->SelectObject(&fnt);
pDC->TextOut(m_x,m_y,m_string);
pDC->SelectObject(pOldFont);
fnt.DeleteObject();
Use ClassWizard to Add Message Map Command handler functions
to the CTextComFontView class menu items:
(IDM_TEXT and IDM_FONT)
Edit the code of the resulting OnText() handler function:
// TODO: Add your command handler code here
CTextDlg dlg;
if (dlg.DoModal()==IDOK) //invoke the "Text" dialog box
{
m_x=dlg.m_x; //get text dialog box control values
m_y=dlg.m_y;
m_string=dlg.m_text;
m_angle=dlg.m_angle;
Invalidate(); //force a window repaint
}
Edit the code of the resulting OnFont() handler function:
// TODO: Add your command handler code here
CFontDialog dlgFont(&m_logFont);
dlgFont.DoModal(); //invoke the common font dialog box
Invalidate(); //force a window repaint
Use ClassWizard to Add a Message Map handler function for
the CTextComView class's WM_LBUTTONDOWN message:
Edit the resulting OnLButtondown handler function:
// TODO: Add your message handler code here and/or call default
m_x=point.x;
m_y=point.y;
#include "TextDlg.h" in the TextComFontView.cpp file
Build and run the application
Note that if you choose a really big font, and select File/Print Preview--
You're actually able to print the text in the window
That's because when OnDraw() is called, the DC that's sent to it will
be the appropriate one--
OnPrint() and OnPaint() both call OnDraw()
Correct DC is sent (screen or printer)
But the text is probably too small--
Printer dots are usually much smaller than screen pixels
Check into Windows Mapping Modes!!!
FILES
Standard C Library File Functions--
fopen(); fread(); fwrite(); fseek(); ftell(); fclose();
Opening a File--
FILE *fp;
fp = fopen("filename_string", "mode_string");
"mode_string":
"r"--open file for reading; fails if file not found
"w"--open empty file for writing; contents destroyed if file exists
"a"--open or create file for appending (writing at the end)
"r+"--open existing file for update (reading and writing); file must exist
"w+"--open empty file for reading/writing; if file exists, contents are lost
"a+"--open or create a file for reading and appending
Can be used with "b" suffix, meaning binary file; e.g., "rb", "wb"
If successful, returns a "file pointer"
Used to identify file in subsequent accesses
If not successful, returns a NULL pointer
Reading a File--
fread (buffer, size, number, fp);
buffer--address of memory block where file data will be stored
size--size in bytes of elements to be read (for char*, size is 1)
number--number of elements to be read (for char*, use lstrlen())
fp--file pointer identifying file
Reads from file starting with element at "file position pointer" location
File system (OS) keeps track of the "file position pointer location"
When file is first opened ("r" or "w"), positioned at start of file
When opened with "a" or "a+", positioned at end of file
Returns number of elements actually read.
Writing a File--
fwrite (buffer, size, number, fp);
buffer--address of memory block containing data to be written
size--size in bytes of elements to be written
number--number of elements to be written
fp--file pointer identifying file
Writes elements to file starting at location of the "file position pointer"
Returns number of elements actually written
Moving to a Place in a File--
fseek(fp, offset, whence);
fp--file pointer identifying file
offset--number of bytes to move "file position pointer"
whence--moved relative to what origin
SEEK_SET(0): seek from beginning of file
SEEK_CUR(1): seek from current position
SEEK_END(2): seek from end of file
Moves "file position pointer" to a new position in file
Indicates byte position in file where next element is to be read/written
Returns 0 if successful
Returns an error code if not successful
Obtaining the Current File Position--
cur_posn = ftell(fp);
fp--file pointer identifying file
Returns current position of "file position pointer"
Closing a File--
fclose(fp);
fp--file pointer identifying file to be closed
Closes specified file (makes permanent)
Example Fragment 1--Create EX1.TXT & Copy a String to it:
FILE *fp;
char szData[] = "Text to copy to file"
fp = fopen ("EX1.TXT", "w");
if (fp != NULL)
{
fwrite (szData, 1, lstrlen(szData), fp);
fclose (fp);
}
Example Fragment 2--Read First 10 Characters from EX1.TXT into a Buffer:
FILE *fp;
char cBuf[128];
fp = fopen ("EX1.TXT", "r");
if (fp != NULL)
{
fread (cBuf, 1, 10, fp);
fclose (fp);
}
Example Fragment 3--Move 10 Bytes from start of EX1.TXT, Read next 5 Bytes:
FILE *fp;
char cBuf[128];
fp = fopen ("EX1.TXT", "r");
if (fp != NULL)
{
fseek (fp, 10, SEEK_SET);
fread (cBuf, 1, 5, fp);
fclose (fp);
}
Use of Common File Dialog Boxes
Among the most useful of Windows common dialog boxes
Allows user to specify file to be opened or saved
Very familiar to Windows users
Common File Dialog Box encapsulated in the CFileDialog
Works with an OPENFILENAME member data structure
typedef struct tagOFN
{
DWORD lStructSize;
HWND hwndOwner;
HINSTANCE hInstance;
LPCTSTR lpstrFilter;
LPTSTR lpstrCustomFilter;
DWORD nMaxCustFilter;
DWORD nFilterIndex;
LPTSTR lpstrFile;
DWORD nMaxFile;
LPTSTR lpstrFileTitle;
DWORD nMaxFileTitle;
LPCTSTR lpstrInitialDir;
LPCTSTR lpstrTitle;
DWORD Flags;
WORD nFileOffset;
WORD nFileExtension;
LPCTSTR lpstrDefExt;
DWORD lCustData;
LPOFNHOOKPROC lpfnHook;
LPCTSTR lpTemplateName; }
OPENFILENAME;
Steps to follow:
Construct a CFileDialog object
param=TRUE==>Open (read file)
param==FALSE==>Save (write file)
Call its DoModal() function to start the dialog box
After User chooses a file name/path,
m_ofn member structure will have the data
Use "Get" member functions to retrieve the data, e.g.:
CFileDialog m_ldFile(TRUE);
m_ldFile.DoModal();
CString fn=m_ldFile.GetPathName();
Dialog-Box Based Applications
Dialog-Based Projects use a dialog box as the main window
Nice for simple applications with no complex menus
Fewer classes--most action occurs in a single CDialog-based class
The FileComDlg Application <Show program in action>
Use AppWizard to create a Dialog-based application template:
File/New/MFC AppWizard(exe), name it FileComDlg
Step 1: choose "Dialog based "
Step 2 of 4: deselect "ActiveX Controls"
Step 3 of 4: accept defaults
Step 4 of 4: accept defaults
Finish/OK
Delete the "TODO" static control in the dialog box template
Add the following Controls to the dialog box template:
"Open File" Button (IDC_OPEN)
"Save File" Button (IDC_SAVE)
"Text:" Static Control
A Large multiline Edit control (IDC_EDIT, style: multiline)
Add private variable m_sFileName to the CFileComDlgDlg class
Type: CString
(Right click on CFileComDlgDlg class)
Use ClassWizard to attach m_string variable to the Edit Control:
In CFlilComDlgDlg class, Control ID: IDC_EDIT:
Variable name: m_string, Category: Value, Type: CString
Use ClassWizard to add button-clicked Message Map handler functions
to each button for the CFileComDlgDlg class:
IDC_OPEN: BN_CLICKED -- OnOpen()
IDC_SAVE: BN_CLICKED -- OnSave()
Add following code to the OnOpen() function:
// TODO: Add your control notification handler code here
FILE *fp;
int nFileLong;
CFileDialog m_ldFile(TRUE); //Construct for reading
if (m_ldFile.DoModal() == IDOK) //Start File dlg box
{
m_sFileName=m_ldFile.GetPathName(); //Get file name
fp=fopen(m_sFileName,"rb"); //Open file for reading
fseek(fp,0,SEEK_END); //Go to file end
nFileLong=ftell(fp); //Get length
char* sText = new char[nFileLong+1]; //reserve string space
fseek(fp,0,SEEK_SET); //Go to file start
int i=fread(sText,1,nFileLong,fp); //Read the characters
sText[i]=0; //Set string terminating null
m_string=sText; //Put text in Edit box's variable
fclose(fp); //Close file
UpdateData(FALSE); //Force data to go to Edit control
}
Add following code to the OnSave() function:
// TODO: Add your control notification handler code here
FILE *fp;
int nFileLong;
UpdateData(TRUE); //Force data from Edit box to variable
CFileDialog m_ldFile(FALSE); //Construct for writing
if (m_ldFile.DoModal() == IDOK) //Start file dlg box
{
m_sFileName=m_ldFile.GetPathName(); //Get file name
nFileLong = m_string.GetLength(); //Length of text in Edit box
fp=fopen(m_sFileName,"wb"); //Open file for writing
fwrite(LPCTSTR(m_string),1,nFileLong,fp); //Write text to file
fclose(fp); //Close file
}
Build and Run the Application
Try opening (reading) arbitray text file on system
Try saving resulting text to a new file
Try typing in text
Note: To get a carriage control, use <Ctrl> <Enter>
Try deleting/cutting/pasting
Part of built-in Edit control functionality