📄 uwizard.pas
字号:
{ JADD - Just Another DelphiDoc: Documentation from Delphi Source Code
Copyright (C) 2005-2008 Gerold Veith
This file is part of JADD - Just Another DelphiDoc.
DelphiDoc is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3 as
published by the Free Software Foundation.
DelphiDoc is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
}
unit UWizard;
{Contains the base class, ~[link TWizardPage], of all pages to be used in a
wizard and a simple form to show the wizard, ~[link TFormWizard].~[br]
I'm not really happy with this layout, because it means an inflation of
classes, but I can't think of a much better way. Perhaps it could be made to
include several pages inside one class, but still allow to use several classes
for several threads of pages, to keep the dynamic connectivity. But up to now
it's like it's here defined. }
interface
uses
Windows, Classes,
{$IFNDEF LINUX}
Messages, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons,
{$ELSE}
QControls, QStdCtrls, QForms, QButtons, QDialogs,
{$ENDIF}
SysUtils;
type
{ * * * *** * * * *** TFormWizard *** * * * *** * * * }
//a base class of classes describing pages of a wizard
TWizardPage = class;
//a class describing a page of a wizard
TWizardPageClass = class of TWizardPage;
//buttons to be used in the wizard
TWizardButton = (
wbBack, //the button to go back to the previous page
wbNext, //the button to go the next page
wbClose); //the button to close the wizard
//a set of the buttons to be used in the wizard
TWizardButtons = set of TWizardButton;
{A simple window serving as the host for a set of pages of a wizard to serve
the wizard to the user. Contains a group box, on which the pages of the
wizard can create components etc., and three buttons to go to the next page,
to the previous page or to close the wizard. }
TFormWizard = class(TForm)
GroupBox: TGroupBox;
BitBtnBack: TBitBtn;
BitBtnNext: TBitBtn;
BitBtnClose: TBitBtn;
procedure BitBtnBackClick(Sender: TObject);
procedure BitBtnNextClick(Sender: TObject);
procedure BitBtnCloseClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormDestroy(Sender: TObject);
private
//the first page of the wizard
FFirstPage: TWizardPage;
//the currently shown page of the wizard
FCurrentPage: TWizardPage;
//Called to show a new page of the wizard.
procedure InitWizardPage(NewPage: TWizardPage);
//Called to hide a page of the wizard and show a new one.
procedure DeInitWizardPage(NewPage: TWizardPage);
public
//Can be called to update the state of the three buttons according to the
//current page of the wizard.
procedure UpdateButtons;
//Can be called to change the current page of the wizard
//(actually can't be called without an error).
procedure ChangeCurrentWizardPage(NewPage: TWizardPage);
//Starts the wizard with the given page.
procedure StartWizard(StartPageClass: TWizardPageClass; Data: TObject);
end;
{$IFDEF LINUX}
//seems not to be defined in Kylix strangely
TControlClass = class of TControl;
{$ENDIF}
{ * * * *** * * * *** TWizardPage *** * * * *** * * * }
{The base class of all pages in a wizard. Each view, each page of a wizard is
implemented by creating a class descending from this one that will create
and handle all needed components. The pages are connected by references from
each page to its predecessor and successor (and maybe sub-pages). It should
always be possible to go back and then forward and also always to close the
wizard. }
TWizardPage = class
private
FData: TObject; //some data to the wizard
FForm: TForm; //the form to show the page on
FParent: TWinControl; //parent to create all components on
FComponents: TList; //list of created components by the page
//the preceding page, to which can be returned
FPreviousPage: TWizardPage;
//if it is a sub-thread of the wizard, the page that started the sub-thread
//to return to, when it ends
FSuperPage: TWizardPage;
//Gets a caption of one of the three buttons.
function GetButtonCaptions(Button: TWizardButton): String;
//Calculated the needed height of a text field to fit all text visible in
//it (Windows only).
function GetMemoHeight(Memo: TMemo; Lines: Integer): Integer;
protected
FNextPage: TWizardPage; //the succeeding page, if already created
FCaption: String; //caption of the page
//captions of the three buttons
FButtonCaptions: array[TWizardButton] of String;
//what of the three buttons are enabled
FButtonsEnabled: TWizardButtons;
FHelpContext: THelpContext; //help context of the page
//vertical position to create the next component of the page
FNewComponentTop: Integer;
//Creates a component of the page.
function CreateControl(Control: TControlClass): TControl;
//Creates a text field on the page.
function AddEditField(Text: String): TEdit;
//Creates a text field to show some text on the page.
function ShowText(Text: String;
ForceSingleLine: Boolean = False): TControl;
//Creates a check box on the page.
function AddCheckBox(Caption: String; Checked: Boolean = False;
Event: TNotifyEvent = nil): TCheckBox;
//Creates a button on the page.
function AddButton(Caption: String; Event: TNotifyEvent): TButton;
//Frees all components of the page.
procedure FreeComponents;
//Returns the next page to be shown.
function GetNextPage: TWizardPage; virtual;
//Called when the current page is no longer shown.
procedure ChangingPage(GoingBack: Boolean); virtual;
//Updates the state of the three buttons.
procedure RequestButtonUpdate;
//Changed the current page (does not work).
procedure RequestPageChange(NewPage: TWizardPage);
property Data: TObject read FData;
property Form: TForm read FForm;
property Parent: TWinControl read FParent;
property Components: TList read FComponents;
property PreviousPage: TWizardPage read FPreviousPage;
public
//Creates the page and initializes its attributes.
constructor Create(Form: TForm; Parent: TWinControl;
Data: TObject; PreviousPage: TWizardPage); virtual;
//Frees the page, all its components and following pages.
destructor Destroy; override;
//Returns the preceding page to show it again.
function Back: TWizardPage;
//Returns the next page to show.
function Next: TWizardPage;
//Called when the page should be shown.
procedure ShowPage(PreviousPage: TWizardPage); virtual;
//Called when the page should no longer be shown.
procedure HidePage(NewPage: TWizardPage); virtual;
//Called when the form of the wizard is about to be closed.
procedure EventCloseQuery(var Msg: String; var ShowQuery: Boolean);
virtual;
property SuperPage: TWizardPage read FSuperPage write FSuperPage;
property Caption: String read FCaption;
property ButtonCaptions[Button: TWizardButton]: String
read GetButtonCaptions;
property ButtonsEnabled: TWizardButtons read FButtonsEnabled;
end;
//Shows the wizard indicated by the class of the first page.
procedure ShowWizard(Owner: TComponent; StartPageClass: TWizardPageClass;
Data: TObject);
implementation
{$R *.dfm}
uses USettingsKeeper;
{Shows the wizard indicated by the class of the first page.
~param Owner the owner of the wizard
~param StartPageClass the class of the first page of the wizard to show
~param Data custom data for the wizard }
procedure ShowWizard(Owner: TComponent; StartPageClass: TWizardPageClass;
Data: TObject);
var i :Integer; //counter through all forms
begin
i := Screen.FormCount - 1; //check whether a wizard is already shown
while (i >= 0) and not (Screen.Forms[i] is TFormWizard) do
dec(i);
if i >= 0 then //wizard is already shown?
Screen.Forms[i].Show //just show it
else
with TFormWizard.Create(Owner) do //create a new wizard
begin
Show; //show the form
StartWizard(StartPageClass, Data); //start the wizard
end;
end;
{ * * * *** * * * *** TWizardPage *** * * * *** * * * }
{Creates the page and initializes its attributes.
~param Form the form to show the page of the wizard on
~param Parent the parent to show the components of the page on
~param Data custom data for the wizard
~param PreviousPage the previous page of this page (to go back to) }
constructor TWizardPage.Create(Form: TForm; Parent: TWinControl;
Data: TObject; PreviousPage: TWizardPage);
begin
inherited Create; //create the object
FForm := Form; //save the parameters
FParent := Parent;
FData := Data;
FPreviousPage := PreviousPage;
FComponents := TList.Create; //create list for components
// FCaption := '';
FButtonCaptions[wbBack] := '&Back'; //initialize state of buttons
FButtonCaptions[wbNext] := '&Next';
FButtonCaptions[wbClose] := '&Close';
FButtonsEnabled := [wbNext, wbClose];
if assigned(PreviousPage) then
Include(FButtonsEnabled, wbBack);
end;
{Frees the page, all its components and following pages. }
destructor TWizardPage.Destroy;
begin
if assigned(FComponents) then
begin
FreeComponents; //free all created components
FComponents.Free; //free the list
end;
FNextPage.Free; //free all following pages
inherited Destroy; //free this page
end;
{Gets a caption of one of the three buttons.
~param Button the button, whose caption should be returned
~result the caption of the button }
function TWizardPage.GetButtonCaptions(Button: TWizardButton): String;
begin
Result := FButtonCaptions[Button]; //just return the caption
end;
{Calculated the needed height of a text field to fit all text visible in it.
Works under Windows only.
~param Memo the memo to calculate the needed height of
~param Lines number of lines needed to be visible
~result needed height of the memo }
function TWizardPage.GetMemoHeight(Memo: TMemo; Lines: Integer): Integer;
{$IFNDEF LINUX}
var OldFont :HFont; //current font
DC :THandle; //handle on device context of the memo
TM :TTextMetric; //information about the current font
TheRect :TRect; //text rect of the memo
{$ENDIF}
begin
{$IFNDEF LINUX}
DC := GetDC(Memo.Handle); //get the device context of the memo
try
OldFont := SelectObject(DC, Memo.Font.Handle); //set current font
try
GetTextMetrics(DC, TM); //get height of one line
//get rectanlge of the text inside the memo
Memo.Perform(EM_GETRECT, 0, LPARAM(@TheRect));
//calculate needed height for the lines + height of decorations
//(assuming decoration is equal at top and bottom)
Result := 2 * TheRect.Top + (TM.tmHeight + TM.tmExternalLeading) * Lines;
// Result := Memo.Height - (TheRect.Bottom - TheRect.Top) +
// (TM.tmHeight + TM.tmExternalLeading) * Lines;
finally
SelectObject(DC, Oldfont); //restore the old font
end;
finally
ReleaseDC(Memo.Handle, DC); //release the device context
end;
{$ELSE}
//can't calculate needed height, so return the current height
Result := Memo.Height;
{$ENDIF}
end;
{Creates a component of the page.
~param Control the class of the control to create
~result the created control }
function TWizardPage.CreateControl(Control: TControlClass): TControl;
begin
Result := Control.Create(Form); //create the control on the form
try
Result.Parent := Parent; //put it on its parent (the groupbox)
Result.Top := FNewComponentTop; //put it on the current location
Result.Left := 10; //with a small margin to the left
{$IFNDEF LINUX}
if Result is TWinControl then
{$ENDIF}
//set help context of the page
TWinControl(Result).HelpContext := FHelpContext;
FComponents.Add(Result); //add it to the list, so it gets freed
except
Result.Free;
raise;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -