![]() Home |
9. Non-Modal Dialogs, DIALOGEX Resource Templetes and Scroll Bars |
![]() Home |
|
DIALOGEX Resource Templetes The DIALOGEX Resource Creation Templete has more Options to offer you for your Dialog templetes. The DIALOG Resource-Type that was used in Lesson eight was left over from windows 16-bit, this DIALOGEX is a more recent and more versital way to do templete dialogs. But most of the time the DIALOG resource templete will have enough to produce the dialog, since the EX additions may not be needed. The DIALOGEX allows the following additions to the DIALOG-
I could not see much of an advantage for using DIALOGEX instead of DIALOG in the resource templete, except if you want to add the helpID for the Caption Help button in the Dialog window. The EX Styles do not seem very useful for a dialog box window, so if you do not need the help or Ex styles, then you may as well use the DIALOG templete creation. The syntax and coding methods for the DIALOGEX is very much like the DIALOG Resource-Type creation code. And looks like this - nameID DIALOGEX [ load-mem] x, y, width, height [ , helpID] [ optional-statements] BEGIN control creation statement control creation statement ENDThe paramrters for the DIALOGEX are listed below - Parameters nameID - Identifies the dialog box. This is either a unique text character name or a unique 16-bit unsigned integer value in the range 1 to 65,535. load-mem - Optional, , Specifies loading and memory attributes for the resource. The only value that you can use here is DISCARDABLE. Most Dialogs use the DISCARDABLE, because it tells the system not to save the templete memory when it is not used. But most templetes use very little memory, so there is not much advantage to having DISCARDABLE. I will use it because you should always free memory that is not being used. x - Specifies the location on the screen of the left side of the dialog, in dialog units. y - Specifies the location on the screen of the top of the dialog, in dialog units. width - Specifies the width of the dialog, in dialog units. height - Specifies the height of the dialog, in dialog units. helpID - Optional, , Specifies a numeric expression indicating the ID used to identify the dialog during WM_HELP processing. optional-statements - Specifies options for the dialog box. Some of these Options are Not used by the windows system, and some are used for methods I will not cover in this lesson, The following Options are listed here but I will not use or talk about them - (CHARACTERISTICS, CLASS, LANGUAGE, MENU, VERSION). STYLE -Specifies the window creation styles of the dialog box.Here is some code for a DIALOGEX resource creation file - MyExDlg DIALOGEX DISCARDABLE 10, 10, 171, 120
STYLE WS_POPUP | WS_CAPTION
EXSTYLE WS_EX_DLGMODALFRAME
CAPTION " My Dialog Box"
FONT 11, "Arial", 0, 1
BEGIN
CTEXT "Title of My Dialog Box" 200, 41, 3, 109, 10
LTEXT "some Static control text" 202, 5, 15, 176, 8
CONTROL "", 600, "SCROLLBAR", SBS_HORZ, 4, 60, 160, 8
DEFPUSHBUTTON "OK" IDOK, 70, 104, 32, 12, WS_TABSTOP
ENDThis DIALOGEX is just about the same as the DIALOG creation we have used before, with a couple of differences. . You should notice that there is a EXSTYLE option and it has the window creation Ex-Style of WS_EX_DLGMODALFRAME, this EXSTYLE was Not availible in the DIALOG resource creation. Look at the FONT option, it has two additional parameters than the DIALOG FONT has, the first additional number is for the Font Weight, you can put 0 for normal font and 700 for Bold font, the next number sets the Italic,
a zero for normal and a One for Italic font. The Control creation is the same code methods that are used in the DIALOG. Wth both the DIALOG and the DIALOGEX, many dialog control "Style" and "ExStyle" options are ignored for templete control creation.
Different Measurements - The DIALOGEX still uses Dialog units and Not pixels for it's measurements, However, the Dialog units for the Horizontal measurements use a different Conversion factor than what was used for the DIALOG templete, the DIALOGEX does NOT use a conversion factor of Four for the horizontal measurements, it uses a conversion factor of about 3.57 for "Small Fonts" . So you will need to adjust your horizontal measurements (x and width) if you change a DIALOG to a DIALOGEX resource creation. Using the DIALOGEX in functions Once you have compiled the resource file (.RES) with the brcc32.exe compiler, you can call the EX templete Dialog in exactly the same way that you did the regular DIALOG, with the DialogBox( ) and CreateDialog( ) functions. It will also use the exact same DialogProc message handling that the regular DIALOG did. Non-Modal Dialogs To get a Non-Modal Dialog Box, you would create it with the CreateDialog( ) function. Which is defined in the windows.pas unit as - function CreateDialog(hInstance: HINST; lpTemplateName: PChar; hWndParent: HWND; lpDialogFunc: TFNDlgProc): HWND;The parameters are the same as the DialogBox( ) function, but the Result is different. The hInstance parameter is the program's hInstance, the lpTemplate is the text name for the DIALOG in the program's resources, , the hWndParent parameter is for the owner or parent window of the dialog box, ussually the main Window, the lpDialogFunc is a Pointer type where you put the address of the Function that will do the Message processing for the dialog box. And the function result is the Handle of the new dialog box window. (The TFNDlgProc type for the lpDialogFunc parameter, is NOT defined as a special type, it is just given a plain old "Pointer" type, I guess the name of TFNDlgProc type is suppose to be descriptive, but it can be confusing when you try to match types). The messages in the DialogProc are used much the same as with a DIALOG templete, except that you do NOT end a Non-Modal Dialog with the EndDialog( ) function. . you must Destroy the dialog window with the DestroyWindow( ) function. You should look at the code in the Dialogs Ex Program below to see examples of these methods. Scroll Bars The window's Scroll Bar Class offers you a control that can be adjusted to change the position of a small scroll bar (thumb box), which will set a scroll position number value in a Range of values (from a minimum to a maximum), it will also give visuall indication of the "Relative" position of this number's value. Since Scroll Bars can automatically be added to some standard controls (a Multi-Line Edit control), they are a familar control type to most users. A scroll bar is most often used to "Scroll" or move a window's visible content, to scroll what is out of view of the client area, , and to bring into view the portions of the content that extend beyond the borders of the window. Scroll Bars should be included in any window for which the content of the client area extends beyond the window's borders. Scroll Bars can also be used without scrolling the contents of a window. The programming methods for using a scroll bar are unlike any of the controls we have covered before. To place a scroll bar on a window (or control) during creation, you can include the WS_HSCROLL or WS_VSCROLL in the window's creation style for CtraeteWindow( ), and a Scroll Bar will be placed on that window. To Create a separate scroll bar control (window), you can use the CreateWindow( ) function with the SCROLLBAR window class. There are several scroll bar styles used for it's creation -
I will use only two Scroll Bar Creation styles in this program, the SBS_HORZ and the SBS_VERT styles. These 2 styles used without the "Align" styles, are for independent self contained scroll bars. The "Align" styles can be used used to set the position of a Scroll bar relative to a rectangle's dimentions given in the Left, Top, Width, Height parameters of CreateWindow function. These "Aligned" Scroll Bars will NOT have the dimentions of the CreateWindow function, but will always be the standard scroll bar size and be aligned to the "Side" of the rectangle given in that style. This is intended to be used to set a Scroll Bar as the scroll Bar for another window, you place the other window's dimentions in the Scroll Bars CreateWindow dimention parameters and the Scroll bar will be aligned on a side of that window. SBS_SIZEGRIP - This is a very unusuall Scroll Bar style, It does not look like a scroll bar, or function (in code or user interaction) like a scroll bar. A "Size Grip" scroll bar is a small square (about 16x16 pixels) that you will see on a "Status Bar" right hand side, with a raised edge and 3 diagonal lines. A SBS_SIZEGRIP scroll bar has the default system processing for a SizeGrip, the cursor will change to a "Sizing" cursor over this scroll bar, AND you can Drag this small Size Grip rectangle to resize the Scroll bar window. I guess that this may be useful somehow, but I did not see a way to use this type of scroll bar, so I will not use this style at all here. The SBS_SIZEBOX style is simalar but without the SizeGrip painting, and is a style from 16-Bit windows, so I will not talk about it here. A CreateWindow( ) function for a Scroll Bar might look like this - hScrollBar := CreateWindow('SCROLLBAR', nil, WS_CHILD or
SBS_VERT or WS_VISIBLE or WS_TABSTOP,
8, 8, 14, 240, hParent, 0, hInstance, nil);This uses the SBS_VERT style without any of the Align styles, so the Top (8), Left(8), Width (14) and Height (240) would be the dimentions for the scroll bar, just like the other controls we have made before. Please notice that the WS_TABSTOP window's style is included, if you want the user to have keyboard input to the scroll bar you must include this Tab Stop Style.
Setting up a Scroll Bar After Creation Scroll Bars have properties that you can use to have your code set numerical values when the user moves the scroll bar. There is the "Range" values, which is a Minimum and Maximum integer value, there is a Position integer value, which is the placement of the "Thumb bar" on the scroll bar. There is a "PageSize" value, which will change the amount of space the Thumb bar tales up in the scroll bar track. When a Scroll Bar is created it will have the system default settings for it's Position, Minimum, Maximum, and PageSize. Position will be Zero, minimum will be Zero, maximum will be 100, and Page Size will be Zero. To set your Scroll Bar values you will need to use several functions like SetScrollRange( ), SetScrollPos( ), and SetScrollInfo( ). You would set the scroll bar Range (minimum and maximum) with the SetScrollRange( ) function. Windows.pas defines this function as - function SetScrollRange(hWnd: HWND; // handle of window with scroll bar
nBar, // scroll bar flag
nMinPos, // Miminum Range
nMaxPos: Integer; // Maximum Range
bRedraw: BOOL // redraw flag
): BOOL; // Result is True if successfulThe hWnd parameter is the Handle of a control that has scroll bars (like an Edit) or the Handle of a scroll bar, the nBar parameter is used to tell the system which scroll bar on a control to change, you use the SB_HORZ for the horizontal bar and the SB_VERT for the vertical bar. If the Handle parameter is a Scroll Bar, then you set the nBar to SB_CTL. The nMinPos will set the Minimum value of the Range and the nMaxPos will set the Maximum for the scroll bar Range. If you want the scroll bar to be repainted, you would set the bRedraw parameter to True. If this function succeeds then the Result will be True.
You can set the thumb bar Position with the SetScrollPos( ) function, defined as - function SetScrollPos(hWnd: HWND; // handle of window with scroll bar
nBar, // scroll bar flag
nPos: Integer; // new position of scroll box
bRedraw: BOOL // redraw flag
): Integer; // Result is previous PositionAgain, you can have a Control with scroll bars OR a Scroll Bar for the Handle parameter. Just like the SetScrollRange function, the nBar can be set to SB_HORZ or SB_VERT for a Control with scroll bars, or for a Scroll Bar handle it should be SB_CTL. The nPos will set the position of the thumb bar, which must be within the scrolling range minimum and maximum. If you want the scroll bar to be redrawn, you set the bRedraw to True. The Result of this function is the previous Postion of the scroll bar.
You can set All of the scroll bar's properties with a single function, called SetScrollInfo( ) , this is a more versitle function and can set the Range, Position and Page Size. It is defined in windows.pas as - function SetScrollInfo(hWnd: HWND; // handle of window with scroll bar
BarFlag: Integer; // scroll bar flag
const ScrollInfo: TScrollInfo;
Redraw: BOOL // redraw flag
): Integer; // Result is the current position This uses the TScrollInfo record for the settings parameters, it is defined as -
tagSCROLLINFO = packed Record
cbSize: Cardinal; // set to SizeOf(TScrollInfo)
fMask: Cardinal; // Specifies the scroll bar parameters to set.
nMin: Integer; // Sets the Minimum scrolling position range.
nMax: Integer; // Sets the Maximum scrolling position range.
nPage: Cardinal; // Sets the Page Size, length of Thumb Bar.
nPos: Integer; // Sets the position of the Thumb Bar.
nTrackPos: Integer; // not used in the SetScrollInfo( ).
end;
PScrollInfo = ^TScrollInfo;
TScrollInfo = tagSCROLLINFO;
SCROLLINFO = tagSCROLLINFO;You must set the cbSize to the Size of this Record (28) with SizeOf(TScrollInfo). The fMask has the flags to tell the system which scroll bar settings (Range, Position, PageSize) to Change, this can be a combination of the following values -
Using the Scroll Bar Messages The System sends a WM_HSCROLL or a WM_VSCROLL message to the Scroll Bar's parent whenever the user interacts with a scroll bar with the mouse or keyboard. The WM_HSCROLL is sent for a Horizontal, and the WM_VSCROLL is sent for a Vertical scroll bar. The LParam of these messages has the Handle of the scroll bar, the WParam has two data sections in the HIWORD and LOWORD parts of that Integer. The HIWORD(WParam) has the nPos value, which is the Position of the thumb bar, , and the LOWORD(WParam) has a nScrollCode in it and it's values can be ONE of the following -
There is NO default system processing for these scroll bar messages (except with the SBS_SIZEGRIP style), the position of the thumb bar will never be changed by the system, even if the user drags it with the mouse, it will just go back to where it statred. You must process these scroll bar messages and use the SetScrollPos( ) or SetScrollInfo( ) function to change the position of the thumb bar. You will need to set the Minimum and Maximum values for the scroll range, before you show the scroll bar, you will also need to determine a value for a "Line" increase or decrease, and a value for a "Page" change amount. Then when the SB_LINELEFT is processed you will decrease the thumb bar position by a "Line" amount (often a value of One). When a SB_PAGELEFT is processed, you will decrease the thumb bar position by a "Page" amount. I find it better to have variables in my program that are used to store the Minimum, Maximum and thumb bar Position for a scroll bar, Otherwize you will need to use a function to get these valuse from the scroll bar. A TScrollInfo record which is used to Set and Get a scroll bar's parameters, can also be used to "Store" the values like position, minimum and maximum that are needed to process a scrroll bar message. The following code is an example for a typical scroll bar for a scroll message, WM_VSCROLL in this case. There are code examples of this in the Dialogs Ex Program code below. There are 5 integer variables in the following code, Position1, Minimum1, Maximum1, Line1, and Page1, ALL of these have been set to the values for this scroll bar BEFORE this message processing is done, usually these are set during the set up of the scroll bar. The Position1 variable is the current position of the thumb bar, the Minimum1 and Maximum1 would be the extents of the Range for the scroll bar. The Line1 and Page1 would be the values that you have determined to be used for the Line and Page amounts for scroll bar changes. These two get their name from "Text" scrolling operations, like in NotePad.exe, where a "Line" is a line of text, and a "Page" is a page of text. Many of the scroll bars that you will use, will Not be for text scrolling, so you will need to calculate your own sizes for Line and Page movement. For a general guideline, the Line size can be about 100th of the total range, and a Page size about a 10th or 20th of the range. The CanScroll is a Boolean variable, it is used here to Stop the movement done in the MoveIt procedure, Notice that the SB_THUMBTRACK sets CanScroll to False, and then CanScroll is tested for the MoveIt procedure. WM_VSCROLL:
begin
CanScroll := True;
case LOWORD(wParam) of
SB_LINEUP: if Position1 > Minimum1 + Line1 - 1 then
Dec(Position1, Line1) else Position1 := Minimum1;
SB_LINERIGHT: if Position1 < Maximum1 - Line1 + 1 then
Inc(Position1, Line1) else Position1 := Maximum1;
SB_PAGELEFT: if Position1 > Minimum1 + Page1 - 1 then
Dec(Position1, Page1) else Position1 := Minimum1;
SB_PAGERIGHT: if Position1 < Maximum1 - Page1 + 1 then
Inc(Position1, Page) else Position1 := Maximum1;
SB_THUMBTRACK:
begin
Position1 := SmallInt(HIWORD(WParam));
CanScroll := False;
end;
SB_THUMBPOSITION: Position1 := SmallInt(HIWORD(WParam));
SB_LEFT: Position1 := Minimum1;
SB_RIGHT: Position1 := Maximum1;
end;
SetScrollPos(lParam, SB_CTL, Position1, True);
if CanScroll then MoveIt;
end;
| ||||||||||||||||||||||||||
| This Dialogs Ex Program will use a DIALOGEX to create a resource templete, and there will be one scroll bar created on the Main Form, which will move the Dialog window Up and Down the screen, when you move the scroll thumb bar. The Dialog window will have three scroll bars, One for the Red color, one for the Green color and one for the Blue color, when you move these scroll bars the individual color component (Red, Green, Blue) will be changed for the brush color that does the bacground for the Main Form and the Dialog window. The dialog window will also process the WM_MOVE message, so that when you move the dialog window, the thumb bar on the main form's scroll bar will move with the vertical placement of the dialog. |
| Dialog Resource Creation Code You will need to create a Dialog Templete in a Resource file much like you did with the previous Dialogs program. The code for this Dlg2.RC file is below. Remember that the Units for control placement are NOT pixels but Dialog Units. In the "Second" dialog, I have added the EXSTYLE WS_EX_APPWINDOW just to show you that you can add the EX styles to the DIALOGEX resource creation, but the WS_EX_APPWINDOW is unnessary for this dialog and just here to show you where to add the EX styles. You should notice that the FONT has two additional parameters, I have set the last one to 1, so the font will be Italic. I have added the DISCARDABLE resource parameter to the code, this will tell the system not to keep this templete in memory when it is not used, for almost all Dialogs, you should add the DISCARDABLE parameter. Since there are three scroll bars in this dialog, I create each of them in a different way, the first is created with a SCROLLBAR control name, The second one is created with a CONTROL resource Name and the "SCROLLBAR" is added as the Class Type. The third one is created in the DialogProc WM_INITDIALOG message, using the CreateWindow message. . . all three scroll bars are about the same, even though they were created in different ways. For the "Child" dialog, I have used a number (55) instead of a Text name, to idenify this dialog, numbers are generally used more than text to identify resource data. But when you use the dialog creation functions like CreateDialog( ), you will need to "Translate" this Dialog ID number to a resource "name" by using the function MakeIntResource(55), you can see this in the code for DoChildDialog procedure below. Notice that in the DIALOGEX STYLE there is a WS_CHILD, this is nessary because this dialog will be on the main Form, much like a VCL TPanel. I have added the EX style of WS_EX_CLIENTEDGE so the dialog will have a sunken border. Child dialogs can be usefull to have a Container for several controls that are unlikely to change durring design time, but if you need to move or alter the controls while designing, it may be easier to create all of the windows in code, otherwise you will have to complile the resource and add it to your program to see how it looks. For this Dialogs Ex Program program here is the code for the "Dlg2.rc" file - |
Second DIALOGEX DISCARDABLE 8, 6, 171, 120
STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION " Second Dialog Box"
FONT 11, "Arial", 0, 1
BEGIN
CTEXT "Title of Second Dialog Box" 200, 41, 3, 109, 10
LTEXT "Move The Scroll Bars to change the Color" 202, 5, 15, 176, 8
SCROLLBAR 600, 4, 38, 160, 8, SBS_HORZ | WS_TABSTOP
CONTROL "", 601, "SCROLLBAR", SBS_HORZ | WS_TABSTOP, 4, 60, 160, 8
DEFPUSHBUTTON "OK" IDOK, 70, 104, 32, 12, WS_TABSTOP
END
55 DIALOGEX DISCARDABLE 80, 31, 90, 52
STYLE WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS
EXSTYLE WS_EX_CLIENTEDGE
FONT 11, "Times New Roman", 700, 0
BEGIN
CTEXT "This is the Child Dialog Box" 200, 2, 1, 86, 10
CTEXT "Center Text" 201, 8, 12, 74, 8
LTEXT "?" 202, 5, 21, 81, 8
AUTOCHECKBOX "Check Me", 300, 5, 30, 56, 8
AUTOCHECKBOX "a Check Box", 301, 5, 40, 56, 8
END
|
| Program Code This program shows how to create and use scroll bars and Non-Modal dialog boxes. You must have the Dlg2.RES file complied from the code above. You will use the CreateDialog( ) function for a Non-Modal dialog, and when you look at the DialogProc( ), you will see that it is used in the same way as the last Dialog's program, except the Dialog Window is not destroyed with the EndDialog( ) function, instead the DestroyWindow(hWnd) function is used. I have moved the Dialog closing code to the DoClose( ) function inside the DialogProc. In the WM_INITDIALOG message code, there are functions that set up the Range and position for the two Scroll Bars created in the dialog templete. See the SetScrollRange( ) and SetScrollPos( ) functions, since these scroll bars do Not change their Range or Page size I use constant values for the Range. The range for these three scroll bars corresponds to the color componenet "Byte' type, which is Zero to 255. The third Scroll Bar is created in the WM_INITDIALOG message, and not in the dilaog resource templete. I will set the "Page Size" for this third scroll bar, even though the range never changes, usually the Page size is a for proportional thumb bar that changes it's length with the relative area of window data that is being scrolled. You will see that the ScrollInfo2 record is filled with the settings for the Range, Position, and Page Size for this third scroll bar and its fMask is set to SIF_ALL so all the values will be used in the SetScrollInfo( ) function. You should look at the code below the CreateWindow( ) function for the Main form's Scroll Bar near the end of this code. A TScrollInfo record called SInfo1 filled with the data collected for the Screen's Work Rectangle's height, and the Dialog window height. This SInfo1 will contain all five of the values needed for the minimum, maximum, position, page amount and line amount, to set the Scroll Bar parameters with SetScrollInfo( ) and these values will be used again in the WM_VSCROLL message of the programs MessageProc function. Look at the code in the WM_VSCROLL message, this code can be used for many different scroll bars, without much change, because a TScrollInfo record can contain all of the values needed. This program will adjust all of the sizes for the Font and controls according to the computer's Display "Font Size", it uses the procedure SetPixelsPerInch to get the current Pixels Per Inch of the system screen DC, and then uses the DoSize( ) function to adjust all of the dimention sizes for the font and controls. See the comments in the code for more information - |
program Dialogs2;
{this program uses a Non-Modal Dialog Boxs in Dlg2.RES and
has Scroll Bars}
uses
Windows, Messages, SmallUtils;
{$R *.RES}
{$R Dlg2.RES}
// the Dlg2.RES has the dialog resource templetes
const
{because 0 and 1 are used so many times in a Program, I use
the Constant Values Zero, One and Two}
Zero = 0;
One = 1;
Two = 2;
tffive = 255;
ID_ExitBut = 10;
ID_DlgBut = 11;
ID_DlgChdBut = 12;
{I use three ID constants for the form's buttons}
var
wClass: TWndClass;
hForm1, Font1, Brush1, hDialog, hChild,
hScrollBar, DlgHPos, PixelPerInch: Integer;
mainMsg: TMSG;
Color1, InvColor: Cardinal;
Rect1, workRect: TRect;
SInfo1: TScrollInfo;
AryColorPos: Array[Zero..Two] of Cardinal;
ArySB_brush: Array[Zero..Two] of Integer;
procedure SetPixelsPerInch;
var
sDC: Integer;
begin
{this is a simple way to get a sizing mutiplier, by getting the
current Pixels Per Inch of the system screen DC, which will Change
with the users Settings for their Display Font Size}
sDC := GetDC(Zero);
PixelPerInch := GetDeviceCaps(sDC, LOGPIXELSY);
ReleaseDC(Zero, sDC);
end;
function DoSize(aSize: Integer): Integer;
begin
{You will need to multiply the dimention aSize in Pixels by the
Current PixelsPerInch and then divide that by the
PixelsPerInch that you are desingning this in, I was in the standard
Small Font 96 Pixels Per Inch at design time,
BE SURE to check and see what your Screen PixelPerInch as you are designing
and replace the value 96 with YOUR DISPLAY Pixels Per Inch}
Result := MulDiv(aSize, PixelPerInch, 96);
{the windows system function MulDiv( ) will Multiply the first two
integers and then divide that result by the third integer and Round
it off to the nearest integer value}
end;
function InverseColor(Color: Cardinal): Cardinal;
var
Red, Green, Blue: Byte;
begin
{this function will calculate the Inverse Color
by subtracting the Red, Green and Blue values from 255}
Red := abs(tffive - GetRValue(Color));
Green := abs(tffive - GetGValue(Color));
Blue := abs(tffive - GetBValue(Color));
{if the color is mid-Grey the Inverse will also be mid-Grey and will not
be readable, so I test for mid-Grey and set the Result to Black}
if (Red < 147) and (Red > 107) and (Blue < 147) and (Blue > 107) and
(Green < 147) and (Green > 107) then
Result := Zero else
Result := RGB(Red, Green, Blue);
end;
function DialogProc(hWnd, Msg, wParam, lParam: Integer): Integer; stdcall;
var
CtrlRect:TRect;
i, hScroll: Integer;
PaintS: TPaintStruct;
Size1: TSize;
ScrollInfo2: TScrollInfo;
procedure DoClose;
begin
SetDlgItemText(hForm1, ID_DlgBut,'Show Dialog');
InvalidateRect(hForm1, nil, True);
{I will Invalidate the Main Form Window to display the New
background Color}
if DestroyWindow(hWnd) then
begin
hDialog := Zero;
Result := One;
end;
{when a Dialog Box is NOT Modal, , use the DestroyWindow
instead of the EndDialog to Kill the Dialog Box}
end;
begin
Result := Zero;
case Msg of
WM_INITDIALOG:
begin
SendMessage(hWnd, WM_SETICON, One, LoadIcon(Zero,IDI_QUESTION));
SendDlgItemMessage(hWnd,200,WM_SETFONT,Font1, Zero);
GetWindowRect(hWnd, Rect1);
{I will save the dimentions of this Dialog in the gobal Rect1 variable
because I will use this Rect1 in the WM_MOVING message and the WM_VSCROLL
message of the Main Form Window}
MoveWindow(hWnd, DlgHPos, SInfo1.nPos, Rect1.Right - Rect1.Left,
Rect1.Bottom - Rect1.Top, False);
{I will move this Dialog Window to the DlgHPos and ScrollInfo1.nPos,
which are recorded if the user moves this dialog window,
OR changes the main form's Scroll Bar}
{In this Dialog Box there will be three Horizontal Scroll Bars, each
created in a Different way. Scroll Bar 600 is Created with the standard
Dialog RC file SCROLLBAR designation, see the code in the Dlg2.rc}
for i := Zero to One do
begin
hScroll := GetDlgItem(hWnd, i + 600);
SetScrollRange(hScroll,SB_CTL, Zero, tffive, False);
SetScrollPos(hScroll, SB_CTL, AryColorPos[i], False);
end;
{Scroll Bar 601 is created with the Dialog RC file CONTROL designation
and it's Class as SCROLLBAR}
{Scroll Bar 602 is created here in the WM_INITDIALOG, using the CreateWindow
function, NOTICE that I use the MapDialogRect function, to get the size
Rectangle for the new scroll bar, because a Dialog Box will be Resized
according to the "Font Size" for your System Display settings}
SetRect(CtrlRect,4,82,164,90);
MapDialogRect(hWnd, CtrlRect);
{the MapDialogRect is the only way to get correct dialog measurement
conversions using the DIALOGEX resource creation, the DialogBaseUnits
for horizontal measurements changes with the DIALOGEX-
For some reason, when you use the DIALOGEX resource creation, the
Horizontal DialogBaseUnits conversion changes from 4 to about 3.57
for "Small Fonts"}
hScroll := CreateWindow('SCROLLBAR', nil, WS_CHILD or SBS_HORZ or
WS_VISIBLE or WS_TABSTOP, CtrlRect.Left,
CtrlRect.Top, CtrlRect.Right - CtrlRect.Left,
CtrlRect.Bottom - CtrlRect.Top,
hWnd, 602, hInstance, nil);
{set the Scroll Bar's ID to 602 in the hMenu Parameter}
ScrollInfo2.cbSize := SizeOf(ScrollInfo);
ScrollInfo2.fMask := SIF_ALL;
{the fMask is set to SIF_ALL, so that all of the scroll bar's settings
will be read and set in the SetScrollInfo function}
ScrollInfo2.nMin := Zero;
ScrollInfo2.nMax := 282{255};
{you must include the (nPage - 1) in the nMax to get the correct nPos Maximum}
ScrollInfo2.nPage := 28{Zero};
{I do NOT need to set a nPage value here, I set this to show you how, The
nPage is normally used for Scroll Bars that will change their nMax settings
as the Size of what they are scrolling changes, the size of the nPage is
suppose to indicate to the user, what the relative scrolling range is}
ScrollInfo2.nPos := AryColorPos[Two];
ScrollInfo2.nTrackPos := Zero;
SetScrollInfo(hScroll, SB_CTL, ScrollInfo2, False);
end;
WM_HSCROLL:
begin
{the WM_HSCROLL message is sent to a Scroll Bar's Parent window, whenever
the scroll bar thumb is moved, A Scroll Bar does NOT automaticaly change it's
position when the user moves the scroll bar, you will need to get information
from the LOWORD(wParam) and then use the SetScrollPos or SetScrollInfo
functions to change the position of the scroll bar}
i := GetWindowLong(lParam, GWL_ID)-600;
{the LParam has the Handle of the Scroll Bar, since Dialogs do not generally
use "Handles" for reference, I will get the ID number with
GetWindowLong(lParam, GWL_ID) and subtract 600 to get an Index for the
AryColorPos Array}
case LOWORD(wParam) of
{the LOWORD(wParam) has the ScrollCode, which tells you what was done to
the Scroll Bar to generate this message, because a Scroll Bar operation
depends on it's settings and what the user does to it, there is no
"Default" operation for Scroll Positioning of the ScrollCodes}
SB_LINELEFT: if AryColorPos[i] > Zero then Dec(AryColorPos[i], One);
SB_LINERIGHT: if AryColorPos[i] < tffive then Inc(AryColorPos[i], One);
{the LineLeft and LineRight are sent for clicks on the arrow buttons}
SB_PAGELEFT: if AryColorPos[i] > 10 then Dec(AryColorPos[i], 10) else
AryColorPos[i] := 0;
SB_PAGERIGHT: if AryColorPos[i] < 245 then Inc(AryColorPos[i], 10) else
AryColorPos[i] := tffive;
{the PageLeft and PageRight are sent for clicks on the scroll track
and the user pressing the PageUp and PageDown keys}
SB_THUMBTRACK: AryColorPos[i] := HIWORD(WParam);
{the ThumbTrack is sent when the user moves the Thumb bar with the mouse}
SB_LEFT: AryColorPos[i] := Zero;
SB_RIGHT: AryColorPos[i] := tffive;
{SB_LEFT and SB_RIGHT are sent when the user presses the Home and End keys}
end;
SetScrollPos(lParam, SB_CTL, AryColorPos[i], True);
{you will need to call the SetScrollPos function, to set a new position for
the scroll bar thumb, it will NOT change it's postion for any user input
reason, (mouse, Keyboard), until you call a function that changes it's position}
Color1 := RGB(AryColorPos[Zero],AryColorPos[One], AryColorPos[Two]);
{Color1 is the current Color used for the background brushes}
InvColor := InverseColor(Color1);
PaintS.hdc := GetDC(hWnd);
wClass.hbrBackground := CreateSolidBrush(Color1);
{a new brush is created in the new Color1, it is set as the background
brush with a call to SetClassLong with the GCL_HBRBACKGROUND, the old brush
handle is returned and it's object is Deleted}
DeleteObject(SetClassLong(hForm1, GCL_HBRBACKGROUND, wClass.hbrBackground));
ArySB_brush[i] := CreateSolidBrush(AryColorPos[i] shl (i shl 3));
{the ArySB_brush contains the Brush used for the WM_CTLCOLORSCROLLBAR message,
the Color of this brush is calculated from the individual Red, Green, and Blue
color of the scroll bar Position, which is in the AryColorPos[i], I use the
shl to multiply the color value and "Shift" it into the correct color position
of the color's Cardinal value}
SelectObject(PaintS.hdc, wClass.hbrBackground);
{a rectangle is drawn on the Dialog Box with the New color in it,
so the user can see what the new color is}
Rectangle(PaintS.hdc, Zero, Zero, DoSize(40), DoSize(30));
GetTextExtentPoint32(PaintS.hdc, '888', One, Size1);
GetWindowRect(lParam, CtrlRect);
{when using Dialog Boxes, you should get the Position of a Control with
GetWindowRect( ), because the position can change according to the
settings for the size of the system text, so using a single pixel value
like 42 will be correct in systems where the system font is the same,
but WRONG in systems where the system display font is different}
ScreenToClient(hWnd, CtrlRect.TopLeft);
{with the change in a Scroll bar position, I will draw the new position
in the color text above the Scroll bar that is moved, the "case i of"
will get the Scroll Bar in use, zero for scrollbar 600}
case i of
0: begin
SetBkColor(PaintS.hdc,$FF);
SetTextColor(PaintS.hdc,$3380);
end;
1: begin
SetBkColor(PaintS.hdc,$FF00);
SetTextColor(PaintS.hdc,$8033);
end;
2: begin
SetBkColor(PaintS.hdc,$FF0000);
SetTextColor(PaintS.hdc,$FFFF00);
end;
end; // case i
hScroll := Length(Int2Str(AryColorPos[i]));
{I use the hScroll as the integer that holds the text length
so I will not need to have another variable}
TextOut(PaintS.hdc,CtrlRect.Left+80, CtrlRect.Top - (Size1.cy+Two),' ', 7);
{to make sure the previous text is erased, I draw the text for 7 spaces
you could use a PatBlt or Rectangle, but you would need to create a hBrush}
TextOut(PaintS.hdc,CtrlRect.Left+82+(12-(hScroll*4)),
CtrlRect.Top - (Size1.cy+Two), PChar(Int2Str(AryColorPos[i])),
hScroll);
{the CtrlRect.Left+82+(12-(hScroll*4)) will get a "Center" position
for the text in the 7 spaces Color block}
ReleaseDC(hWnd, PaintS.hdc);
end;
WM_COMMAND: if LOWORD(wParam) = IDOK then
DoClose;
WM_CLOSE: DoClose;
WM_PAINT:
begin
BeginPaint(hWnd, PaintS);
SelectObject(PaintS.hdc, wClass.hbrBackground);
{the wClass.hbrBackground Brush has the brush with the Color set
by the Color Scroll Bars on this dialog}
Rectangle(PaintS.hdc, Zero, Zero, DoSize(40), DoSize(30));
GetWindowRect(GetDlgItem(hWnd,600), CtrlRect);
{because the Dialog Box can be a different size according to the Display's
"Font Size" setting, I need to get each Scroll Bars Window Rectangle
in order to paint the Text in the correct position over the scroll bar}
ScreenToClient(hWnd, CtrlRect.TopLeft);
{the CtrlRect is in Screen coordinates so you need to convert the TopLeft
to the client coordinates for the dialog window with ScreenToClient}
GetTextExtentPoint32(PaintS.hdc, '888', One, Size1);
{because the size of the "System" font may change, I get the vetical
Height of the font with GetTextExtentPoint32 to use in the TextOut functions}
SetBkColor(PaintS.hdc,$FF);
SetTextColor(PaintS.hdc,$3380);
{I will Draw Colored Text over each Scroll Bar to tell the User the Color
that the scroll bar will change}
TextOut(PaintS.hdc,CtrlRect.Left+22, CtrlRect.Top -
(Size1.cy+Two),' Red ', 5);
i := length(Int2Str(AryColorPos[Zero]));
TextOut(PaintS.hdc,CtrlRect.Left+80, CtrlRect.Top -
(Size1.cy+Two),' ', 7);
{I will draw 7 text "Space" charaters to erase the previous Text Draw}
TextOut(PaintS.hdc,CtrlRect.Left+82+(12-(i*4)),
CtrlRect.Top - (Size1.cy+Two), PChar(Int2Str(AryColorPos[Zero])), i);
GetWindowRect(GetDlgItem(hWnd,601), CtrlRect);
ScreenToClient(hWnd, CtrlRect.TopLeft);
SetBkColor(PaintS.hdc,$FF00);
SetTextColor(PaintS.hdc,$8033);
TextOut(PaintS.hdc, CtrlRect.Left+22, CtrlRect.Top -
(Size1.cy+Two),' Green ',7);
i := length(Int2Str(AryColorPos[One]));
TextOut(PaintS.hdc,CtrlRect.Left+80, CtrlRect.Top -
(Size1.cy+Two),' ', 7);
TextOut(PaintS.hdc,CtrlRect.Left+82+(12-(i*4)),
CtrlRect.Top - (Size1.cy+Two), PChar(Int2Str(AryColorPos[One])), i);
GetWindowRect(GetDlgItem(hWnd,602), CtrlRect);
ScreenToClient(hWnd, CtrlRect.TopLeft);
SetBkColor(PaintS.hdc,$FF0000);
SetTextColor(PaintS.hdc,$FFFF00);
TextOut(PaintS.hdc, CtrlRect.Left+22, CtrlRect.Top -
(Size1.cy+Two),' Blue ',6);
i := length(Int2Str(AryColorPos[Two]));
TextOut(PaintS.hdc,CtrlRect.Left+80, CtrlRect.Top -
(Size1.cy+Two),' ', 7);
TextOut(PaintS.hdc,CtrlRect.Left+82+(12-(i*4)),
CtrlRect.Top - (Size1.cy+Two), PChar(Int2Str(AryColorPos[Two])), i);
ScreenToClient(hWnd, CtrlRect.BottomRight);
SetBkColor(PaintS.hdc, $FFFFFF);
SetTextColor(PaintS.hdc,Zero);
{I will Draw the Text below the bottom Scroll Bar to show the relative
values of the Scroll Positions from 0 to 127 to 255}
TextOut(PaintS.hdc, CtrlRect.Left+13, CtrlRect.Bottom+4,'0',One);
TextOut(PaintS.hdc, CtrlRect.Left+(( CtrlRect.Right-CtrlRect.Left) shr One)
-13, CtrlRect.Bottom+4,'127', 3);
TextOut(PaintS.hdc, CtrlRect.Right-28,CtrlRect.Bottom+4,'255',3);
EndPaint(hWnd,PaintS);
end;
WM_CTLCOLORDLG: Result := wClass.hbrBackground;
{The WM_CTLCOLORDLG Result will set the hBrush used for the Erase
Background of a Dialog box}
WM_CTLCOLORSCROLLBAR:
begin
{the WM_CTLCOLORSCROLLBAR will get the hBrush used to fill
the shaft area of a Scroll bar}
i := GetWindowLong(lParam, GWL_ID)-600;
Result := ArySB_brush[i];
end;
WM_CTLCOLORSTATIC:
begin
SetBkColor(wParam, $FFFFA0);
Result := wClass.hbrBackground;
end;
WM_MOVING:
begin
{when this Dialog box is moved the Screen Position will be recorded
in the DlgHPos and ScrollInfo1.nPos, the Scroll Bar Position on the
main Window will be changed to the new vertical Position of this Dialog}
if DlgHPos <> PRect(lParam).Left then
DlgHPos := PRect(lParam).Left;
if PRect(lParam).Top <> SInfo1.nPos then
begin
if PRect(lParam).Top < SInfo1.nMin then
begin
{to avoid this dialog from being draged past the Scroll Bar's Limits
I will test the PRect(lParam).Top with the ScrollInfo1.nMin and set the
PRect(lParam).Top to the Top of the Work Area, which is ScrollInfo1.nMin}
PRect(lParam).Top := SInfo1.nMin;
PRect(lParam).Bottom := SInfo1.nMin + Rect1.Bottom - Rect1.Top;
end;
if PRect(lParam).Top > SInfo1.nMax then
begin
PRect(lParam).Top := SInfo1.nMax;
PRect(lParam).Bottom := SInfo1.nMax + Rect1.Bottom - Rect1.Top;
end;
SInfo1.nPos := PRect(lParam).Top;
SetScrollPos(hScrollBar, SB_CTL, SInfo1.nPos, True);
{sometimes it is convient to record the position of a Non-Modal Dialog box,
in case the user moves it to a position that they like better, the
ScrollInfo1.nPos and DlgHPos record the moved position of this dialog,
so if it is shown again it will be in the same position}
end;
end;
end;
end;
procedure DoDialog;
begin
if hDialog <> Zero then
begin
SendMessage(hDialog, WM_CLOSE, Zero, Zero);
Exit;
end;
hDialog := CreateDialog(hInstance, 'Second', hForm1, @DialogProc);
{the CreateDialog function will make a NON-Modal Dialog Box and return
a Handle for that window (the dialog box)}
ShowWindow(hDialog, SW_SHOWNORMAL);
{the dialog is Not created with the WS_VISIBLE, so you will need to Show it}
if hDialog <> Zero then
SetDlgItemText(hForm1, ID_DlgBut,'Destroy Dialog');
end;
function ChildProc(hWnd, Msg, wParam, lParam: Integer): Integer; stdcall;
var
wRect: TRect;
begin
{this is the message process for the Child Dialog Box}
Result := Zero;
case Msg of
WM_INITDIALOG:
begin
{WM_INITDIALOG is where you set your Dlg Items properties. There are
special DlgItem functions (SendDlgItemMessage, SetDlgItemText) to help
with this.}
GetWindowRect(hWnd, wRect);
SetDlgItemText(hWnd, 201, PChar('This Dialog Width is '+
Int2Str(wRect.Right - wRect.Left)));
SetDlgItemText(hWnd, 202, 'Check the check Box');
end;
WM_COMMAND:
if LOWORD(wParam) = 300 then
if IsDlgButtonChecked(hWnd, 300) = BST_CHECKED then
SetDlgItemText(hWnd, 202,'Check Box is Checked') else
SetDlgItemText(hWnd, 202,'UnChecked the Check Box');
WM_CTLCOLORDLG: Result := Brush1;
WM_CTLCOLORSTATIC:
begin
SetBkColor(wParam, $FFFFA0);
Result := Brush1;
end;
end;
end;
procedure DoChildDialog;
begin
if hChild <> Zero then
begin
if DestroyWindow(hChild) then
begin
{I use DestroyWindow to kill the Child Dialog}
SetDlgItemText(hForm1, ID_DlgChdBut, 'Show Child Dialog');
hChild := Zero;
end;
Exit;
end;
hChild := CreateDialog(hInstance, MakeIntResource(55), hForm1, @ChildProc);
{unlike other Dialog Boxes I have done before, I use a Number instead
of a Text identifier for the DIALOGEX resource templete, so I need to
use the MakeIntResource( ) function to get the Number 55 to a PChar
used for resource identifiers}
if hChild <> Zero then
SetDlgItemText(hForm1, ID_DlgChdBut, 'Hide Child Dialog');
end;
function MessageProc(hWnd, Msg, wParam, lParam: Integer): Integer; stdcall;
var
PaintS: TPaintStruct;
i: Integer;
CanScroll: Boolean;
begin
case Msg of
WM_CLOSE: DestroyWindow(hDialog);
{The system will destroy the hDialog, but I have included this to be sure
there are no memory leaks}
WM_COMMAND: if LOWORD(wParam) = ID_ExitBut then
PostMessage(hForm1,WM_CLOSE, Zero, Zero)
else if LOWORD(wParam) = ID_DlgBut then DoDialog
else if LOWORD(wParam) = ID_DlgChdBut then DoChildDialog;
WM_PAINT: begin
BeginPaint(hWnd, PaintS);
SetTextColor(PaintS.hdc,InvColor);
SetBkMode(PaintS.hdc, TRANSPARENT);
TextOut(PaintS.hdc, DoSize(44), DoSize(39), 'Move Scroll Bar to Move Dialog Box', 34);
SelectObject(PaintS.hdc, Font1);
TextOut(PaintS.hdc, DoSize(140), DoSize(9), 'Dialog Demo 2', 13);
EndPaint(hWnd, PaintS);
end;
WM_DESTROY: begin
{you must DeleteObject for the BackGround Brush that you created}
for i := Zero to Two do
DeleteObject(ArySB_brush[i]);
DeleteObject(SetClassLong(hWnd, GCL_HBRBACKGROUND,
GetStockObject(GRAY_BRUSH)));
PostQuitMessage(Zero);
end;
WM_VSCROLL:
begin
{Like the WM_HSCROLL used in the DialogProc, you will need to get the
scroll bar nScrollCode in the LOWORD(wParam) and then set the Scroll
Position with the SetScrollPos. All of the Scroll Bar's numeric values
are in the SInfo1 variable}
CanScroll := True;
with SInfo1 do
case LOWORD(wParam) of
SB_LINEUP: if nPos > nMin+ nTrackPos - One then
Dec(nPos, nTrackPos) else nPos := nMin;
SB_LINEDOWN: if nPos < nMax - nTrackPos + One then
Inc(nPos, nTrackPos) else nPos := nMax;
SB_PAGEUP: if nPos > Integer(nPage) - One then
Dec(nPos, nPage) else nPos := nMin;
SB_PAGEDOWN: if nPos < nMax - Integer(nPage) + One then
Inc(nPos, nPage) else nPos := nMax;
SB_THUMBTRACK:
begin
nPos := SmallInt(HIWORD(WParam));
//CanScroll := False;
end;
{I have TypeCast the HIWORD(WParam) to a SmallInt so negative values
can be read correctly}
//SB_THUMBPOSITION: nPos := SmallInt(HIWORD(WParam));
{I have commented out the SB_THUMBPOSITION message and the CanScroll := False;
in the SB_THUMBTRACK, you can Un-Comment these and then the Dialog box will
not move untill you release the thumb bar with the mouse button}
SB_TOP: nPos := nMin;
SB_BOTTOM: nPos := nMax;
end; // case
SetScrollPos(lParam, SB_CTL, SInfo1.nPos, True);
{the code above for a WM_VSCROLL can be used for many different scroll bars,
because the SInfo1 record has all of the values needed for testing and
positioning the thumb bar}
if (hDialog <> Zero) and CanScroll then
MoveWindow(hDialog, DlgHPos, SInfo1.nPos, Rect1.Right -
Rect1.Left,Rect1.Bottom - Rect1.Top,True);
{when the user moves this scroll bar, the Dialog window will
move Up and Down on the Screen}
end; // WM_VSCROLL
end; // case Msg
Result := DefWindowProc(hWnd,Msg,wParam,lParam);
end;
procedure SetColors;
var i: Integer;
begin
{the AryColorPos is an Array that holds the Scroll Bar Positions
for the three Scroll bars on the Dialog box, the Range of these scroll bars
is zero to 255, corresponding to the range of a Byte variable. . . .
these values are also the Red, Green and Blue components
of the Color1 color value}
for i := Zero to Two do
begin
AryColorPos[i] := 127;
ArySB_brush[i] := CreateSolidBrush(AryColorPos[i] shl (i shl 3));
end;
//Color1 := RGB(AryColorPos[Zero],AryColorPos[One], AryColorPos[Two]);
{the code below is equivalent to the code above, I use the shl below to
change the byte values into the correct color value position of the Color1}
Color1 := AryColorPos[Zero] or (AryColorPos[One] shl 8) or (AryColorPos[Two] shl 16);
end;
begin // MAIN PROGRAM BEGIN / / / / / / / / / / / / / / /
hChild := Zero;
hDialog := Zero;
InvColor := Zero;
SetPixelsPerInch;
SetColors;
Brush1 := CreateSolidBrush($FFFFA0);
Font1 := CreateFont(DoSize(-16), Zero, Zero, Zero, FW_BOLD, Zero, Zero, Zero,
ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
VARIABLE_PITCH or FF_SWISS, 'Arial');
with wClass do
begin
style := CS_PARENTDC or CS_BYTEALIGNWINDOW;
hInstance := sysInit.hInstance;
hIcon := LoadIcon(hInstance,'MAINICON');
lpfnWndProc := @MessageProc;
hbrBackground := CreateSolidBrush(Color1);
lpszClassName := 'Form Class';
hCursor := LoadCursor(Zero,IDC_ARROW);
end;
RegisterClass(wClass);
{I will use the DoSize( ) function on ALL of the pixel dimention parameters
in the CreateWindow functions, This will make the Form and all of it's
controls resize according to the current Pixel Per Inch of the Display, ,
However, the main form should just Have Scroll bars added if the Pixels
Per Inch is increased, because the size of your Main Form may be larger
than the Screen's Work Rectangle}
SetRect(Rect1,Zero,Zero, DoSize(406), DoSize(260));
if not AdjustWindowRect(Rect1, WS_CAPTION or WS_MINIMIZEBOX or
WS_SYSMENU, False) then
SetRect(Rect1,Zero,Zero, DoSize(414), DoSize(288));
hForm1 := CreateWindow(wClass.lpszClassName, 'Doing Dialogs',
WS_CAPTION or WS_MINIMIZEBOX or WS_SYSMENU,
(GetSystemMetrics(SM_CXSCREEN) shr One)-DoSize(240),
(GetSystemMetrics(SM_CYSCREEN) shr One)-DoSize(160),
Rect1.Right-Rect1.Left, Rect1.Bottom-Rect1.Top,
Zero, Zero, hInstance, nil);
CreateWindow('Button','E x i t',
WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON or BS_TEXT or WS_TABSTOP,
DoSize(288), DoSize(214), DoSize(86), DoSize(25), hForm1, ID_ExitBut, hInstance, nil);
{All of the button controls will use the ID number for
reference, and not a Handle}
CreateWindow('Button','Show Dialog',
WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON or BS_TEXT or WS_TABSTOP,
DoSize(52), DoSize(176), DoSize(94), DoSize(25), hForm1, 11, hInstance, nil);
SendDlgItemMessage(hForm1, ID_DlgBut, WM_SETFONT,
GetStockObject(ANSI_VAR_FONT), Zero);
CreateWindow('Button','Show Child Dialog',
WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON or BS_TEXT or WS_TABSTOP,
DoSize(52), DoSize(214), DoSize(114), DoSize(25), hForm1, ID_DlgChdBut, hInstance, nil);
SendDlgItemMessage(hForm1, ID_DlgChdBut, WM_SETFONT,
GetStockObject(ANSI_VAR_FONT), Zero);
hScrollBar := CreateWindow('SCROLLBAR', 'sb', WS_CHILD or SBS_VERT or
WS_VISIBLE or WS_TABSTOP, DoSize(18), DoSize(8),
DoSize(14), DoSize(230), hForm1, Zero, hInstance, nil);
{this scroll bar is created with the SBS_VERT, so it will be a vertical
scroll bar, you need to set the WS_TABSTOP, so this will get keyboard input}
if not SystemParametersInfo(SPI_GETWORKAREA, Zero, @workRect,Zero) then
SetRect(workRect, Zero, Zero, GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN)-DoSize(32));
{the Scroll Bar on the main Form will move the Dialog box up and down
on the screen. I need to get the work Rectangle of the screen,
so I can set the ScrollInfo1 (scroll bar info, the scroll bar's range,
page, and positioning) with the work rectangle's
measurements which will set the scroll bar's range and position}
DlgHPos := (GetSystemMetrics(SM_CXSCREEN) shr One) - DoSize(130);
{the DlgHPos has the X position of the Dialog window}
SInfo1.cbSize := SizeOf(TScrollInfo);
{I will use the SInfo1 to set the scroll bar with the SetScrollInfo( )
function, The values in this SInfo1 will be used in the scroll bar
message processing to get the Minimum and Maximum values, page and Line sizes}
SInfo1.fMask := SIF_POS or SIF_RANGE;
SInfo1.nMin := workRect.Top;
{SInfo1.nMin will hold the minimum scroll bar range}
SInfo1.nPos := (GetSystemMetrics(SM_CYCAPTION) +
(Two * GetSystemMetrics(SM_CYDLGFRAME)));
{the GetSystemMetrics(SM_CYCAPTION) will get the height of a normal Caption
the GetSystemMetrics(SM_CYDLGFRAME) will get the frame width}
{SInfo1 is the Scroll Bar Info, the nMin is the Work
Rectangle Top. The nMax is the Height of the work rectangle
minus the height of the Dialog Box}
{I will use the GetDialogBaseUnits to get the height of the Dialog box window}
SInfo1.nMax := workRect.Bottom - workRect.Top -
(SInfo1.nPos+MulDiv(120+DoSize(7),HIWORD(GetDialogBaseUnits), 8));
{the SInfo1.nMax will hold the Scroll Bar Maximum, which is the
WorkRectangle Height minus the Dialog's height}
{MulDiv(120+DoSize(7),HIWORD(GetDialogBaseUnits), 8) will give you the Client Area
Height of the Dialog Box, the height in the templete is 120, which needs
to be mutiplied by the HIWORD(DialogUnits) and divided by eight. Then I add
SInfo1.nPos for the Caption and subtarct that fron the workRect height}
SInfo1.nTrackPos := SInfo1.nMax div 100;
{SInfo1.nTrackPos is NOT a Track position, it is the amount of pixels the
scroll bar will move for a "Line UP or DOWN" click or key input, since
the nTrackPos is Not used in the SetScrollInfo function, I will use it to
store the "Line" size for this scroll bar}
SInfo1.nPage := SInfo1.nMax div 14;
{SInfo1.nPage will NOT be used by the SetScrollInfo function, since the
SIF_PAGE flage is Not included, but I use it to store the amount of pixels the
scroll bar will move for a "Page UP or DOWN" click or key input}
SInfo1.nPos := SInfo1.nMax shr One;
{the ScrollInfo1.nPos variable will hold the Scroll Bar's Position which
is also the vertical Y position of the Dialog Box window,}
SetScrollInfo(hScrollBar, SB_CTL, SInfo1, False);
{the SetScrollInfo function will set the parameters of a scroll bar according
to the Flags set in the ScrollInfo1.fMask, so here it will set the Range and
Position}
ShowWindow(hForm1, SW_SHOWDEFAULT);
while GetMessage(mainMsg,Zero,Zero,Zero) do
if not IsDialogMessage(hForm1, mainMsg) then
begin
TranslateMessage(mainMsg);
DispatchMessage(mainMsg);
end;
DeleteObject(Font1);
DeleteObject(Brush1);
end.
|
| Be sure to move all of the scroll bars and see the effect that they have. You might move the position of the Dialog Window while it is visible, and see that the scroll bar on the main form move with it's position. Be sure to Un-Comment the SB_THUMBPOSITION and CanScroll in the WM_VSCROLL message, to see what this does to the Dialog window movement by draging the thumb bar with the mouse. |
![]()
Next
We have used a Dialog. It's time to learn how to create and use Menus and Listboxes in Lesson 10
10. Menus and List Boxes

H O M E 