unit NavBtn;
{ TDBNavigationButton: a data-aware TBitBtn
Delphi 1 + 2
The Beast
E-Mail: thebeast_first_666@yahoo.com
ICQ: 67756646
}interfaceuses
WinTypes, WinProcs, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Messages, StdCtrls, Buttons, dbconsts, DB, DBTables;
type
TNavigationButtonDataLink = class;
TDBNavigationButtonType = (
nbCustom,
nbFirst, nbPrior, nbNext, nbLast,
nbInsert, nbDelete,
nbEdit,
nbPost, nbCancel,
nbRefresh);
TBeforeActionEvent =
procedure (Sender: TObject; var ActionIsDone: Boolean) ofobject;
TDbNBDisableReason = (
drBOF, drEOF, drReadonly,
drNotEditing, drEditing, drEmpty);
TDbNBDisableReasons = setof TDbNBDisableReason;
{ TDBNavigationButton }
TDBNavigationButton = class (TBitBtn)
private
FDisableReasons: TDbNBDisableReasons;
FDataLink: TNavigationButtonDataLink;
FConfirmDelete: Boolean;
FButtonEnabled: Boolean;
FDBNavigationButtonType: TDBNavigationButtonType;
FOnBeforeAction: TBeforeActionEvent;
FOldOnGlyphChanged: TNotifyEvent;
FCustomGlyph: Boolean;
function GetDataSource: TDataSource;
procedure SetDataSource(Value: TDataSource);
procedure SetDBNavigationButtonType(Value: TDBNavigationButtonType);
procedure ReadButtonEnabled(Reader: TReader);
procedure WriteButtonEnabled(Writer: TWriter);
function NumberOfStandardComponentName: Integer;
function HasStandardComponentName: Boolean;
procedure LoadGlyph;
function StoreGlyph: Boolean;
procedure GlyphChanged(Sender: TObject);
procedure UpdateEnabled;
procedure CalcDisableReasons;
protectedprocedure DataChanged;
procedure EditingChanged;
procedure ActiveChanged;
procedure Loaded; override;
procedure DefineProperties(Filer: TFiler); override;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
procedure CMEnabledChanged(varMessage: TMessage);
message CM_ENABLEDCHANGED;
procedure Click; override;
procedure DoAction; virtual;
publicconstructor Create(AOwner: TComponent); override;
destructor Destroy; override;
publishedproperty ConfirmDelete: Boolean
read FConfirmDelete write FConfirmDelete default True;
property DataButtonType: TDBNavigationButtonType
read FDBNavigationButtonType write SetDBNavigationButtonType;
property DataSource: TDataSource read GetDataSource write SetDataSource;
property Glyph stored StoreGlyph;
{ Use BeforeAction instead of the Click-event if you want to cancel
the default-action by setting ActionIsDone to true.
The Click-event is called before the DoAction-event. }property OnBeforeAction: TBeforeActionEvent
read FOnBeforeAction write FOnBeforeAction;
{ Use DisableReasons to say on what case the button has to be disabled.
It is set automatic if you set DataButtonType <> nbCustom.
DisableReason | Disable if Dataset is...
---------------+-------------------------
drBOF | EOF
drEOF | BOF
drReadonly | Readonly
drNotEditing | Not in insert or edit-mode
drEditing | In insert or edit-mode
drEmpty | Both BOF and EOF }property DisableReasons: TDbNBDisableReasons
read FDisableReasons write FDisableReasons;
end;
{ TNavigationButtonDataLink }
TNavigationButtonDataLink = class(TDataLink)
private
FDBNavigationButton: TDBNavigationButton;
protectedprocedure EditingChanged; override;
procedure DataSetChanged; override;
procedure ActiveChanged; override;
publicconstructor Create(aDBNavigationButton: TDBNavigationButton);
destructor Destroy; override;
end;
procedureRegister;
implementation{ $R DBCTRLS}{ uses DBCTRLS.RES, but that is already linked by DB.PAS }const{ RegisterPanel = 'Datensteuerung'; { german }
RegisterPanel = 'Data Controls';
const
CtrlNamePrefix = 'dbNavBtn';
StandardComponentName = 'DBNavigationButton';
const
BtnTypeName: array[TDBNavigationButtonType] of PChar =
('', 'FIRST', 'PRIOR', 'NEXT', 'LAST', 'INSERT', 'DELETE',
'EDIT', 'POST', 'CANCEL', 'REFRESH');
BtnName: array[TDBNavigationButtonType] ofstring =
('', 'First', 'Prior', 'Next', 'Last', 'New', 'Delete',
'Edit', 'Save', 'Cancel', 'Refresh');
{ TNavigationButtonDataLink }constructor TNavigationButtonDataLink.Create(aDBNavigationButton: TDBNavigationButton);
begininherited Create;
FDBNavigationButton := aDBNavigationButton;
end;
destructor TNavigationButtonDataLink.Destroy;
begin
FDBNavigationButton := nil;
inherited Destroy;
end;
procedure TNavigationButtonDataLink.EditingChanged;
beginif FDBNavigationButton <> nilthen FDBNavigationButton.EditingChanged;
end;
procedure TNavigationButtonDataLink.DataSetChanged;
beginif FDBNavigationButton <> nilthen FDBNavigationButton.DataChanged;
end;
procedure TNavigationButtonDataLink.ActiveChanged;
beginif FDBNavigationButton <> nilthen FDBNavigationButton.ActiveChanged;
end;
{ TDBNavigationButton }constructor TDBNavigationButton.Create(AOwner: TComponent);
begininherited Create(AOwner);
FDataLink := TNavigationButtonDataLink.Create(Self);
DataButtonType := nbCustom;
FConfirmDelete := True;
FButtonEnabled := True;
FCustomGlyph := false;
FOldOnGlyphChanged := Glyph.OnChange;
Glyph.OnChange := GlyphChanged;
FDisableReasons := [];
end;
destructor TDBNavigationButton.Destroy;
begin
FDataLink.Free;
FDataLink := nil;
inherited Destroy;
end;
procedure TDBNavigationButton.GlyphChanged(Sender: TObject);
begin
FCustomGlyph := true;
if Assigned(FOldOnGlyphChanged) then FOldOnGlyphChanged(Sender);
end;
function TDBNavigationButton.StoreGlyph: Boolean;
begin{ store only user-defined glyph: }
result := (FDBNavigationButtonType = nbCustom) or FCustomGlyph;
end;
procedure TDBNavigationButton.LoadGlyph;
var{$IFNDEF WIN32}
Buffer: array[0..79] of Char;
{$ENDIF NDEF WIN32}
ResName: string;
beginif (FDBNavigationButtonType = nbCustom) then
exit;
try{ Load the Bitmap that DBNavigator would load: }
FmtStr(ResName, 'dbn_%s', [BtnTypeName[FDBNavigationButtonType]]);
{$IFDEF WIN32}
Glyph.Handle := LoadBitmap(HInstance, PChar(ResName));
{$ELSE DEF WIN32}{ Glyph.Assign(nil); { clear }
Glyph.Handle := LoadBitmap(HInstance, StrPCopy(Buffer, ResName));
{$ENDIF DEF WIN32}
NumGlyphs := 2;
FCustomGlyph := false;
except{ error: do nothing }end;
end;
procedure TDBNavigationButton.CalcDisableReasons;
begincase FDBNavigationButtonType of
nbPrior: FDisableReasons := [drBOF, drEditing, drEmpty];
nbNext: FDisableReasons := [drEOF, drEditing, drEmpty];
nbFirst: FDisableReasons := [drBOF, drEditing, drEmpty];
nbLast: FDisableReasons := [drEOF, drEditing, drEmpty];
nbInsert: FDisableReasons := [drReadonly, drEditing];
nbEdit: FDisableReasons := [drReadonly, drEditing, drEmpty];
nbCancel: FDisableReasons := [drNotEditing];
nbPost: FDisableReasons := [drNotEditing];
nbRefresh: FDisableReasons := [drEditing];
nbDelete: FDisableReasons := [drReadonly, drEditing, drEmpty];
end;
end;
function TDBNavigationButton.NumberOfStandardComponentName: Integer;
function NumberOfName(const TestName: String): Integer;
beginif (Length(Name) > Length(TestName)) and
(Copy(Name, 1, Length(TestName)) = TestName) thenbegintry
result := StrToInt(Copy(Name, Length(TestName) + 1, 255));
except
result := 0;
end;
endelse
result := 0;
end; { function NumberOfName }begin{ TDBNavigationButton.NumberOfStandardComponentName }
result := NumberOfName(StandardComponentName);
if (result = 0) then
result := NumberOfName(CtrlNamePrefix + BtnName[FDBNavigationButtonType]);
end;
function TDBNavigationButton.HasStandardComponentName: Boolean;
function HasName(const TestName: String): Boolean;
beginif (Length(Name) > Length(TestName)) and
(Copy(Name, 1, Length(TestName)) = TestName) thenbegintry
result := (StrToInt(Copy(Name, Length(TestName) + 1, 255)) > 0);
except
result := false;
end;
endelse
result := (Name = TestName);
end; { function HasName }begin
result :=
HasName(StandardComponentName) or
HasName(CtrlNamePrefix + BtnName[FDBNavigationButtonType]);
end;
procedure TDBNavigationButton.SetDBNavigationButtonType(
Value: TDBNavigationButtonType);
const
TooMuch_SomethingIsWrong = 33;
var
NewName: string;
Number: Integer;
beginif (Value = FDBNavigationButtonType) then
exit;
if (csLoading in ComponentState) thenbegin
FDBNavigationButtonType := Value;
CalcDisableReasons;
exit;
end;
Enabled := True;
Spacing := -1;
if (Value = nbCustom) then
FCustomGlyph := trueelseif (FDBNavigationButtonType = nbCustom) or
(Caption = BtnName[FDBNavigationButtonType]) then{ Change caption if it was created automatically: }
Caption := BtnName[Value];
try{ ... to change the name of the component: }if (csDesigning in ComponentState) and
HasStandardComponentName thenbeginif (Value = nbCustom) then
NewName := StandardComponentName
else
NewName := CtrlNamePrefix + BtnName[Value];
if (Owner <> nil) and (Owner.FindComponent(NewName) <> nil) thenbegin
Number := NumberOfStandardComponentName;
if (Number = 0) then
Number := 1;
repeatif (Value = nbCustom) then
NewName := StandardComponentName + IntToStr(Number)
else
NewName := CtrlNamePrefix + BtnName[Value] + IntToStr(Number);
Inc(Number);
until (Owner.FindComponent(NewName) = nil) or
(Number = TooMuch_SomethingIsWrong);
end;
Name := NewName;
end;
except{ don't change name if error occured }end;
Enabled := False;
Enabled := True;
FDBNavigationButtonType := Value;
LoadGlyph;
CalcDisableReasons;
end;
procedure TDBNavigationButton.Notification(AComponent: TComponent;
Operation: TOperation);
begininherited Notification(AComponent, Operation);
if (Operation = opRemove) and (FDataLink <> nil) and
(AComponent = DataSource) then DataSource := nil;
end;
procedure TDBNavigationButton.DoAction;
var
Cancel: Boolean;
beginif (not (csDesigning in ComponentState)) and
Assigned(FOnBeforeAction) thenbegin
Cancel := (FDBNavigationButtonType = nbCustom);
FOnBeforeAction(self, Cancel);
if Cancel then
exit;
end;
if (DataSource <> nil) and (DataSource.State <> dsInactive) thenbeginwith DataSource.DataSet dobegincase FDBNavigationButtonType of
nbPrior: Prior;
nbNext: Next;
nbFirst: First;
nbLast: Last;
nbInsert: Insert;
nbEdit: Edit;
nbCancel: Cancel;
nbPost: Post;
nbRefresh: Refresh;
nbDelete:
{if not FConfirmDelete or
(MessageDlg(LoadStr(SDeleteRecordQuestion), mtConfirmation,
mbOKCancel, 0) <> idCancel) then Delete;}end;
end;
end;
end;
procedure TDBNavigationButton.Click;
begininherited Click;
DoAction;
end;
procedure TDBNavigationButton.UpdateEnabled;
var
PossibleDisableReasons: TDbNBDisableReasons;
beginif (csDesigning in ComponentState) then
exit;
if (csDestroying in ComponentState) then
exit;
ifnot FButtonEnabled then
exit;
if FDataLink.Active thenbegin
PossibleDisableReasons := [];
if FDataLink.DataSet.BOF then
Include(PossibleDisableReasons, drBOF);
if FDataLink.DataSet.EOF then
Include(PossibleDisableReasons, drEOF);
ifnot FDataLink.DataSet.CanModify then
Include(PossibleDisableReasons, drReadonly);
if FDataLink.DataSet.BOF and FDataLink.DataSet.EOF then
Include(PossibleDisableReasons, drEmpty);
if FDataLink.Editing then
Include(PossibleDisableReasons, drEditing)
else
Include(PossibleDisableReasons, drNotEditing);
endelse
PossibleDisableReasons := [drBOF, drEOF, drReadonly, drNotEditing, drEmpty];
Enabled := (FDisableReasons * PossibleDisableReasons = []);
FButtonEnabled := true;
end;
procedure TDBNavigationButton.DataChanged;
begin
UpdateEnabled;
end;
procedure TDBNavigationButton.EditingChanged;
begin
UpdateEnabled;
end;
procedure TDBNavigationButton.ActiveChanged;
beginifnot (csDesigning in ComponentState) thenbegin
UpdateEnabled; { DataChanged; EditingChanged; }end;
end;
procedure TDBNavigationButton.CMEnabledChanged(varMessage: TMessage);
begininherited;
if (not (csLoading in ComponentState)) and
(not (csDestroying in ComponentState)) thenbegin
FButtonEnabled := Enabled;
ActiveChanged;
end;
end;
procedure TDBNavigationButton.SetDataSource(Value: TDataSource);
begin
FDataLink.DataSource := Value;
ifnot (csLoading in ComponentState) then
ActiveChanged;
{$IFDEF WIN32}if Value <> nilthen Value.FreeNotification(Self);
{$ENDIF DEF WIN32}end;
function TDBNavigationButton.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
procedure TDBNavigationButton.ReadButtonEnabled(Reader: TReader);
begin
FButtonEnabled := Reader.ReadBoolean;
end;
procedure TDBNavigationButton.WriteButtonEnabled(Writer: TWriter);
begin
Writer.WriteBoolean(FButtonEnabled);
end;
procedure TDBNavigationButton.DefineProperties(Filer: TFiler);
begininherited DefineProperties(Filer);
Filer.DefineProperty('RuntimeEnabled', ReadButtonEnabled, WriteButtonEnabled, true);
end;
procedure TDBNavigationButton.Loaded;
begininherited Loaded;
if Glyph.Empty then{ no user-defined glyph: }
LoadGlyph; { load standard glyph }
Enabled := FButtonEnabled; {}
ActiveChanged;
end;
procedureRegister;
begin
RegisterComponents(RegisterPanel, [TDBNavigationButton]);
end;
end.
Обзор кода компонента TDBNavigationButton на языке Delphi:
Обзор
Компонент TDBNavigationButton - это кнопка с данными, позволяющая навигировать по набору данных (например, таблице базы данных) в приложении Delphi. Он обеспечивает различные функции, такие как включение/отключение, загрузка иконки, обработку событий.
Свойства
DataSource: источник данных для кнопки.
DBNavigationButtonType: тип навигационной операции (например, первый, предыдущий, следующий, последний, вставка, удаление, редактирование).
ConfirmDelete: булевое свойство, определяющее, нужно ли запросить пользователя перед удалением записи.
Glyph: иконка кнопки.
Методы
Click(): обрабатывает событие клика кнопки и выполняет соответствующую навигационную операцию.
DoAction(): выполняет навигационную операцию при клике кнопки.
UpdateEnabled(): обновляет состояние включения/отключения кнопки в зависимости от состояния набора данных (активность, редактирование, только для чтения).
Имплементация
Единица содержит несколько деталей реализации:
1. Компонент зарегистрирован в процедуре Register().
2. Класс TNavigationButtonDataLink - это вспомогательный класс, связывающий кнопку с источником данных.
3. Метод CalcDisableReasons() рассчитывает причины, по которым кнопка должна быть отключена, основываясь на состоянии набора данных.
4. Метод UpdateEnabled() обновляет состояние включения/отключения кнопки в зависимости от состояния набора данных (активность, редактирование, только для чтения).
Обзор кода
В целом, код appears to be well-structured and follows Delphi's coding conventions. Однако, некоторые минимальные улучшения можно было бы сделать:
* Используйте более описательные имена переменных.
* Рассмотрите добавление комментариев для объяснения сложной логики или алгоритмов.
* Метод CalcDisableReasons() является quite long; рассмотрите разбиение его на более управляемые функции.
Пример создания компонента TDBNavigationButton - это классифицируемый контрол для работы с данными в приложении на языке Delphi.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.