You are not logged in.
Pages: 1
SI there anyone of you have been using SQLite3UIEdit?
Parameters of the procedure SetRecord FieldNamesWidth make all the same size field. While I like different size of the fields.
I tried adding a variable AnsiChar on SetRecord procedure by taking the value of the parameter RibbonParams.
...
fFieldCaption [i]: = aCaption;
if RibbonParams <> nil then begin
ac: = RibbonParams ^. FieldWidth [i 1];
if ac in ['a' .. 'z'] then
dec (ac, 32);
fFieldLengthMean [i]: = (Ord (ac)) 200;
/ / FieldNamesWidth: = fFieldLengthMean [i];
end;
...
if C.InheritsFrom (TCheckBox) then / / trick to avoid black box around
CC.SetBounds (FieldNamesWidth, Y, CW, CC.Height) else
if C.InheritsFrom (TDateTimePicker) then begin
...
end else
/ / C.SetBounds (FieldNamesWidth, Y, 200.22);
C.SetBounds (FieldNamesWidth, Y, fFieldLengthMean [i], 22);
fFieldComponents [i]: = C;
Field length but not as expected (maybe i put it in the wrong place).
I also do not understand, why aClient always Nil?
so that this code was never executed
sftID:
if aClient <> nil then begin
/ / ID field (TSQLRecord descendant) is handled by a component TComboBox
/ / With all possible values of the corresponding descendant TSQLRecord
IDClass: = TSQLRecordClass (P ^. PropType ^ ^. Classtype ^. Classtype);
CB: = TComboBox.Create (Scroll);
CB.Parent: = Scroll; / / need parent now for access CB.Items
CB.Style: = csDropDownList;
AID: = P ^. GetOrdValue (aRecord);
with IDClass.RecordProps do
if MainField [true]> = 0 then begin
aClient.OneFieldValues (IDClass, FieldsName [MainField [true]],'', CB.Items, @ AID);
CB.ItemIndex: = Aid; / / @ AID now contains the found index of AID
end;
end;
one another, how to use events TOnComponentCreated, TOnComponentCreate, TOnComponentValidate?
also, I do not understand the usefulness and how to use SQLite3UIOptions.
I'm very grateful if anyone willing to help.
Thank you.
Offline
FieldWidth parameter is used for Grid display, and result into proportional computation of fFieldLengthMean[] values.
So you should not use these values for field display on edit screen.
As stated by the documentation, you have to call TRecordEditForm.SetRecord() to set the parameters of the window.
This is where the Client property is defined.
About event handlers:
/// this event is used to customize screen text of property names
OnCaptionName: TOnCaptionName;
/// this event is used to customize the input components creation
// - this event is also triggerred once at the creation of the Option window,
// with Obj=Prop=nil and Parent=TOptionsForm: the event must
// call method Parent.AddEditors() / Parent.SetRecord() to add fields to the
// Option (this is not mandatory to the Record Edit window)
// - this event is triggered once for every object, with Prop=nil,
// and should return nil if the object is to be added to the dialog,
// and something not nil if the object is to be ignored
// (same as a runtime-level _Name object)
// - this is the only mandatory event of this component, for TOptionsForm
// - this event is not mandatory for TRecordEditForm (you can call
// its SetRecord method directly)
OnComponentCreate: TOnComponentCreate;
/// this event is used to customize the input components after creation
// - triggered when the component has been created
// - can be used to disabled the component if user don't have the right
// to modify its value; but he/she will still be able to view it
OnComponentCreated: TOnComponentCreated;
Offline
i'm sorry, but with
TRecordEditForm.SetRecord()
call, have error message
This form of method call only alowed for class method'
.
i'd read the documentation many times, but still don't understand.
I learned a lot about RTTI and Object Oriented Programming from this framework, prior my knowledge about it is very weak. Now it's getting better. but still not enough to understand the existing documentation on SQLite3UIEdit and SQLite3UIOption.
before, i call the RecordEditForm like this:
RecordEditForm:= TRecordEditForm.Create(Self);
with RecordEditForm do try
RecordEditForm.SetRecord(Client,aRec,nil,Ribbon);
Result := ShowModal= mrOk;
finally
Free;
end;
could you give me a small piece of code?
thank you.
Offline
Of course, TRecordEditForm.SetRecord() is not to be called as this: this is not a class method.
I referred to this method as TRecordEditForm.SetRecord, since it is defined as such in the source code implementation.
The way you are using TRecordEditForm with a temporary RecordEditForm variable is perfectly correct.
Offline
thank you. but with this way the aClient is still always nil.
Offline
no. i'd toggled breakpoint (F5) at
RecordEditForm.SetRecord(Client,aRec,nil,Ribbon);
in this breakpoint, Client not nil.
i also toggled breakpoint in the SQLite3UIEdit.pas at this line:
..
fRec := aRecord;
fClient := aClient; //here aClient is nil.
CW := Scroll.ClientWidth;
...
thank you.
Offline
that is what i don't understand.
at this time
RecordEditForm.SetRecord(Client,aRec,nil,Ribbon);
debuger show me hint something like
Client=(fCache:nil;fTransactionActive:0;fTransactionCriticalSession:(DebugInfo:$1F4CD8;.............
but, in the SQLite3UIEdit
..
fRec := aRecord;
fClient := aClient; //here debuger shown hint aClient = nil.
CW := Scroll.ClientWidth;
...
Offline
I'm not able to reproduce the issue here.
Step into the SetRecord method, adding a watchpoint about aClient.
Use step by step debugging (F8) to guess where aClient is set to nil.
There may be a stack buffer overflow issue somewhere.
Offline
ok, thank you. i'll try to debug more carefully.
Offline
hi. i solved the problem. should be
RecordEditForm.SetRecord(frmMain.Client,aRec,nil,Ribbon);
because Client variable exists in the RecordEditForm and frmMain form.
But, i have another issue with RecordEditForm.
How is the best way to implement the following scenario:
1. When RecordEditForm in mode to be Create, and everything is Ok to add a Record, I wish the form is still showing, and ready to receive new input from the user (all editor is blank).
- For that, I did it by adding a parameter CRUDAction: (caCreate, caRead, caUpdate, caDelete) on Procedure SetRecord(..)
if CRUDAction = caCreate then begin
if Client.Add (Rec, True)> 0 then begin
Rec.ClearProperties; //sometimes i get AV in this.
Self.Hide;
SetRecord (Client, Rec, caCreate, nil, fRibbon);
Self.Show;
end;
end else
ModalResult: = mrOK;// Update Mode (CRUDAction = caUpdate)
2. When user click the Cancel button, and if there are field(s) had changed, firstly, I want ask to user, whether the changes they made to the save or not.
- For this purpose, I've tried doing a litle test as follows:
...
sftID: begin
SetIndex if <0 then
AID: = 0 else
begin
AID: = PtrInt (CB.Items.Objects [SetIndex]);
if AID <> StrToInt (Rec.GetFieldValue (S2U (P ^. Name))) then / / this value is changed
MessageBox (0, PAnsiChar (Rec.GetFieldValue (S2U (P ^. Name))), PAnsiChar (IntToStr (AID)), 0);
end;
P ^. SetOrdValue (Rec, AID);
Include (ModifiedFields, FieldIndex);
end;
...
but, likely I need to split BtnSaveClick procedure;
I need your advice.
Offline
ok. i'll try it. thank you.
Offline
I tried to use the event OnComponentCreated on RecordEditForm to create two buttons on the right control for the sftid field type.
procedure TBPBaseEditForm.DOOnComponentCreated(Obj: TObject; Prop: PPropInfo; Comp: TWinControl);
var
SQLFieldType: TSQLFieldType;
P: PPropInfo;
ButtonAdd, ButtonEdit: TSynButton;
begin
P:= Prop;
SQLFieldType:= P^.PropType^^.SQLFieldType;
case SQLFieldType of
sftID: begin
ButtonAdd := TSynButton.Create(Comp.Parent);
with ButtonAdd do begin
Parent := Comp.Parent;
SetBounds(Comp.Left + Comp.Width + 1,Comp.Top - 1,50,Comp.Height + 2);
Caption := 'Add';
// B.OnClick := BClick;
SetBitmap(BitmapArrow);
Anchors := [akLeft, akTop];
end;
ButtonEdit:= TSynButton.Create(Comp.Parent);
with ButtonEdit do begin
Parent := Comp.Parent;
SetBounds(ButtonAdd.Left + ButtonAdd.Width + 1,ButtonAdd.Top,50,ButtonAdd.Height);
Caption := 'Edit';
// B.OnClick := BClick;
SetBitmap(BitmapArrow);
Anchors := [akLeft, akTop];
end;
end;
end;
end;
but, I had trouble in adjusting the position of the buttons.
unless I move the trigger event, to the bottom.
....
fFieldComponents[i] := C;
//i move it to here
if Assigned(OnComponentCreated) then // allow component customization
OnComponentCreated(aRecord,P,C); // e.g. set C.Enabled := false
inc(Y,aHeight);
...
one more, can you add BitmapAdd and BitmapEdit to the SynTaskDialog.res?
thank you
Offline
You should better use a resourcestring for the captions (e.g. sAdd and sEdit).
I've moved OnComponentCreated event call after all component initialization, to allow adding paired components on purpose, as you wanted to.
See http://synopse.info/fossil/info/8d2b799f3f
The sftID kind of field should better handle "Add" and "Edit" buttons by the unit, you are right.
A more generic implementation is needed. But perhaps the new form add or edit should also be calling an automated created form like SQLite3UIEdit.
In this case, generic bitmaps for those actions do make sense.
Offline
thank you.
I tried to call the form automatically, by creating an instance of TSynButton.
TSQLRecordButtonClass = class of TSQLRecordButton;
TSQLRecordButton = class(TSynButton)
private
fProp: PPropInfo;
fRecordClass: TSQLRecordClass;
fAssociateComponent: TWinControl;
protected
public
property Prop: PPropInfo read fProp write fProp;
property RecordClass: TSQLRecordClass read fRecordClass;
property AssociateComponent: TWinControl read fAssociateComponent;
constructor Create(aOwner: TComponent; P: PPropInfo; Comp: TWinControl); reintroduce;
class function CreateButton(aOwner: TComponent; P: PPropInfo;
Comp: TWinControl; RecordButtonClass: TSQLRecordButtonClass): TSQLRecordButton;
end;
TSQLRecordAddButton = class(TSQLRecordButton);
TSQLRecordEditButton = class(TSQLRecordButton);
I'm not sure, if this is a good idea or not. but so far it's working fine,
except I can not get RibbonTabParameters, because not all of RecordClass listed on the ribbon.
I'm hoping to get suggestions for a better way.
The following is a complete unit of BPBaseEditForm.
unit BPBaseEdit;
interface
uses
Windows,
Messages,
SysUtils,
Variants,
Classes,
Graphics,
Controls,
Forms,
Dialogs,
StdCtrls,
ExtCtrls,
ComCtrls,
SynCommons,
SQLite3Commons,
SQLite3i18n,
SQLite3ToolBar,
SQLite3UIEdit,
SQLite3UILogin,
SQLBaseModel,
BPFrame,
ImgList,
SynTaskDialog;
type
TSQLRecordButtonClass = class of TSQLRecordButton;
TSQLRecordButton = class(TSynButton)
private
fProp: PPropInfo;
fRecordClass: TSQLRecordClass;
fAssociateComponent: TWinControl;
protected
public
property Prop: PPropInfo read fProp write fProp;
property RecordClass: TSQLRecordClass read fRecordClass;
property AssociateComponent: TWinControl read fAssociateComponent;
constructor Create(aOwner: TComponent; P: PPropInfo; Comp: TWinControl); reintroduce;
class function CreateButton(aOwner: TComponent; P: PPropInfo;
Comp: TWinControl; RecordButtonClass: TSQLRecordButtonClass): TSQLRecordButton;
end;
TSQLRecordAddButton = class(TSQLRecordButton);
TSQLRecordEditButton = class(TSQLRecordButton);
TBPBaseEditForm = class(TRecordEditForm)
pnlFrame: TPanel;
il16: TImageList;
il32: TImageList;
procedure BtnSaveClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
fModified: Boolean;
fPagerTop: TSynPager;
fTB: TSQLCustomToolBar;
fDetail: TFrameDetail;
protected
procedure CRUDActionClick(Sender: TObject);
procedure CRUDManyActionClick(Sender: TObject);
procedure DOOnChange(Sender: TObject);
procedure SetDetail(aDetail:TFrameDetail);
public
{ Public declarations }
function DOOnComponentCreate(Obj: TObject; Prop: PPropInfo; Parent: TWinControl): TWinControl;
procedure DOOnComponentCreated(Obj: TObject; Prop: PPropInfo; Comp: TWinControl);
property Modified: Boolean read fModified write fModified;
property Detail: TFrameDetail read fDetail write SetDetail;
end;
//var BPBaseEditForm: TBPBaseEditForm;
implementation
uses Contnrs;
{$R *.dfm}
{TSQLRecordButton}
constructor TSQLRecordButton.Create(aOwner: TComponent; P: PPropInfo; Comp: TWinControl);
begin
fProp:= P;
fRecordClass:= TSQLRecordClass(fProp^.Proptype^^.ClassType^.Classtype);
fAssociateComponent:= Comp;
Inherited Create(aOwner);
end;
class function TSQLRecordButton.CreateButton(aOwner: TComponent; P: PPropInfo;
Comp: TWinControl; RecordButtonClass: TSQLRecordButtonClass): TSQLRecordButton;
begin
if (aOwner = nil) or (P = nil) then
Result:= nil
else Result:= RecordButtonClass.Create(aOwner,P,Comp);
end;
{TBPBaseEditForm}
procedure TBPBaseEditForm.CRUDActionClick(Sender: TObject);
var
aRec: TSQLRecord;
BaseEditForm: TBPBaseEditForm;
aID, SetIndex: Integer;
CB: TComboBox;
IsOK: Boolean;
function CRUD(aRec: TSQLRecord): Boolean;
begin
BaseEditForm.SetRecord(Client,aRec);
Result := BaseEditForm.ShowModal= mrOk;
end;
procedure RefreshComboBox(aClient: TSQLRestClient; P: PPropInfo);
var
IDClass: TSQLRecordClass;
SourceID,OldIndex: Integer;
begin
if aClient <> nil then begin
OldIndex:= CB.ItemIndex;
IDClass := TSQLRecordClass(P^.PropType^^.ClassType^.ClassType);
SourceID := P^.GetOrdValue(Rec);
with IDClass.RecordProps do
if MainField[True] >= 0 then begin
aClient.OneFieldValues(IDClass,FieldsName[MainField[True]],'',CB.Items,@SourceID);
CB.ItemIndex:= OldIndex;
end;
end;
end;
begin
with TSQLRecordButton(Sender) do
begin
aRec:= RecordClass.Create;
CB:= TComboBox(AssociateComponent);
SetIndex:= CB.ItemIndex;
if SetIndex < 0 then
aID := 0
else aID := PtrInt(CB.Items.Objects[SetIndex]);
end;
if aRec = nil then
Exit;
BaseEditForm:= TBPBaseEditForm.Create(Application);
try
if Sender.InheritsFrom(TSQLRecordAddButton) then
while CRUD(aRec) do
try
aID:= Client.Add(aRec,True);
if aID > 0 then begin
aRec.ClearProperties;
end;
finally
Client.UnLock(aRec);
end else
if Sender.InheritsFrom(TSQLRecordEditButton) then
try
if Client.Retrieve(aID,aRec,False) then
try
IsOK:= CRUD(aRec);
if IsOK then
Client.Update(aRec);
finally
Client.UnLock(aRec);
end;
finally
end;
RefreshComboBox(Client, TSQLRecordButton(Sender).Prop);
finally
aRec.Free;
BaseEditForm.Free;
end;
end;
procedure TBPBaseEditForm.CRUDManyActionClick(Sender: TObject);
var
aRec: TSQLRecord;
aMany: TSQLRecordMany;
BaseEditForm: TBPBaseEditForm;
aID,aTag: Integer;
function CRUD(aRec: TSQLRecord): Boolean;
begin
BaseEditForm.SetRecord(Client,aRec);
Result := BaseEditForm.ShowModal= mrOk;
end;
begin
aTag:= TSynToolButton(Sender).Tag;
case aTag of
Ord(caCreate)..Ord(caUpdate):begin
BaseEditForm:= TBPBaseEditForm.Create(Application);
try
aRec:= Detail.CurrentPage.Dest;
if aRec = nil then
Exit;
aMany:= Detail.CurrentPage.Many;
if aTag = Ord(caCreate) then
while CRUD(aRec) do
try
aID:= Client.Add(aRec,True);
if aID > 0 then begin
aMany.ManyAdd(Client,Rec.ID,aID,True);
aRec.ClearProperties;
Detail.RefreshCurrentPage;
end;
finally
Client.UnLock(aRec);
end else
if aTag = Ord(caUpdate) then
try
finally
end;
finally
end;
end;
end;
end;
procedure TBPBaseEditForm.DOOnChange(Sender: TObject);
begin
Modified:= True;
end;
procedure TBPBaseEditForm.SetDetail(aDetail: TFrameDetail);
begin
if aDetail <> nil then
fDetail:= aDetail
else
fDetail:= TFrameDetail.Create(Self,Client,Rec);
end;
function TBPBaseEditForm.DOOnComponentCreate(Obj: TObject; Prop: PPropInfo; Parent: TWinControl): TWinControl;
var
SQLFieldType: TSQLFieldType;
P: PPropInfo;
begin
Result:= nil;
P:= Prop;
SQLFieldType:= P^.PropType^^.SQLFieldType;
case SQLFieldType of
sftMany: begin
Result := TComboBox.Create(Parent);
end;
end;
end;
procedure TBPBaseEditForm.DOOnComponentCreated(Obj: TObject; Prop: PPropInfo; Comp: TWinControl);
const
W = 50;
var
P: PPropInfo;
SQLFieldType: TSQLFieldType;
L: Integer;
begin
P:= Prop;
SQLFieldType:= P^.PropType^^.SQLFieldType;
case SQLFieldType of
sftID: begin
with TSQLRecordButton.CreateButton(Comp.Parent,Prop,Comp,TSQLRecordAddButton) do begin
Tag:= 0;
Parent := Comp.Parent;
L:= Comp.Left + Comp.Width + 1;
SetBounds(L,Comp.Top - 1,W,Comp.Height + 2);
Caption := 'Add';
OnClick := CRUDActionClick;
SetBitmap(BitmapArrow);
Anchors := [akLeft, akTop];
end;
with TSQLRecordButton.CreateButton(Comp.Parent,Prop,Comp,TSQLRecordEditButton) do begin
Tag:= 1;
Parent := Comp.Parent;
L:= L + W + 1;
SetBounds(L,Comp.Top - 1,W,Comp.Height + 2);
Caption := 'Edit';
OnClick := CRUDActionClick;
SetBitmap(BitmapArrow);
Anchors := [akLeft, akTop];
end;
end;
end;
if Comp.InheritsFrom(TLabeledEdit) then begin
if P^.Name = 'Name' then
Comp.Width:= Comp.Width + 100;
TLabeledEdit(Comp).OnChange:= DOOnChange;
end else
if Comp is TDateTimePicker then begin
TDateTimePicker(Comp).OnChange:= DOOnChange;
end else
if Comp is TComboBox then begin
TComboBox(Comp).OnChange:= DOOnChange;
end;
end;
procedure TBPBaseEditForm.BtnSaveClick(Sender: TObject);
begin
Modified:= False;
inherited BtnSaveClick(Sender);
end;
resourcestring
sSave= 'Save Changes ?';
procedure TBPBaseEditForm.FormClose(Sender: TObject;
var Action: TCloseAction);
var
aAnswer: Integer;
begin
inherited;
if Modified then begin
aAnswer:= MessageDlg(sSave,mtConfirmation,mbYesNoCancel,0);
case aAnswer of
mrYes: BtnSaveClick(Sender);
mrNo:;
mrCancel:Action:= caNone;
end;
end;
end;
procedure TBPBaseEditForm.FormCreate(Sender: TObject);
begin
inherited;
// OnComponentCreate:= DOOnComponentCreate;
OnComponentCreated:= DOOnComponentCreated;
BottomPanel.BevelOuter:= bvNone;
BottomPanel.Height:= 40;
BtnSave.SetBounds(BtnSave.Parent.Width - 220,5,100,27);
BtnCancel.SetBounds(BtnSave.Left + BtnSave.Width,5,100,27);
BtnSave.OnClick:= BtnSaveClick;
end;
[b]
procedure TBPBaseEditForm.FormShow(Sender: TObject);
begin
with Rec.RecordProps do
if Pointer(ManyFields) <> nil then try
Detail:= TFrameDetail.Create(pnlFrame,Client,Rec);
Detail.Parent:= pnlFrame;
fPagerTop:= TSynPager.Create(Detail);
fPagerTop.Parent:= Detail;
fPagerTop.Align:= alTop;
fPagerTop.Height:= 40;
fTB.Init(fPagerTop,TypeInfo(TCRUDAction),CRUDManyActionClick,nil,'');
fTB.AddToolBar('');
fTB.Toolbars[0].Align:= alClient;
except
end;
pnlFrame.Visible:= Detail <> nil;
if pnlFrame.Visible then begin
ClientHeight:= ClientHeight + pnlFrame.Height;
end;
SetStyle(Self);
inherited;
end;
[/b]
procedure TBPBaseEditForm.FormDestroy(Sender: TObject);
begin
if fPagerTop <> nil then
fPagerTop.Free;
if fDetail <> nil then
fDetail.Free;
inherited;
end;
end.
I also tried to handle sftMany SQLFieldType.
please note the FormShow () and CRUDManyActionClick ().
It also works pretty well, but I'm still not satisfied with the results.
I feel this way is not true.
The following is what I am trying to do on the unit FrameDetai
unit BPFrame;
interface
uses
Windows,
Messages,
SysUtils,
Variants,
Classes,
Graphics,
Controls,
ComCtrls,
Forms,
Dialogs,
SynCommons,
SQLite3Commons,
SQLite3UI,
SQLite3ToolBar,
SQLite3UILogin,
{$IFDEF USENEXTPACK}
NxColumnClasses,
NxColumns,
NxScrollControl,
NxCustomGridControl,
NxCustomGrid,
NxGrid,
{$ELSE}
Grids,
{$ENDIF}
ExtCtrls;
type
TPagerMany= class;
TPageMany= class(TSynPage)
private
fDest: TSQLRecord;
fMany: TSQLRecordMany;
fTable: TSQLTable;
{$IFDEF USENEXTPACK}
fGrid: TNextGrid;
{$ELSE}
fTableToGrid: TSQLTableToGrid;
fGrid: TDrawGrid;
{$ENDIF}
fSourceCSVFieldNames: PUTF8Char;
fDestCSVFieldNames: PUTF8Char;
protected
function CreateGrid:{$IFDEF USENEXTPACK}TNextGrid{$ELSE}TDrawGrid{$ENDIF};
public
class function CreatePageMany(aPager: TPagerMany; aMany: TSQLRecordMany;
SourceCSVFieldNames: PUTF8Char=nil; DestCSVFieldNames: PUTF8Char=nil): TPageMany;
property Dest: TSQLRecord read fDest write fDest;
property Many: TSQLRecordMany read fMany;
property Table: TSQLTable read fTable write fTable;
property SourceCSVFieldNames: PUTF8Char read fSourceCSVFieldNames;
property DestCSVFieldNames: PUTF8Char read fDestCSVFieldNames;
{$IFDEF USENEXTPACK}
property Grid: TNextGrid read fGrid write fGrid;
{$ELSE}
property TableToGrid: TSQLTableToGrid read fTableToGrid write fTableToGrid;
property Grid: TDrawGrid read fGrid write fGrid;
{$ENDIF}
destructor Destroy; override;
end;
TPagerMany= class(TSynPager)
private
fClient: TSQLRestClient;
fSource: TSQLRecord;
function GetActivePageIndex: integer;
procedure SetActivePageIndex(const Value: integer);
protected
procedure Change; override;
function GetPageMany(aIndex: integer): TPageMany; {$ifdef HASINLINE}inline;{$endif}
function GetSQLMany(aIndex: integer): TSQLRecordMany; {$ifdef HASINLINE}inline;{$endif}
public
class function CreatePagerMany(aOwner: TComponent; aClient: TSQLRestClient; aSource: TSQLRecord): TPagerMany;
/// add a page instance
function AddPage(aPage: TPageMany): integer; overload;
/// create a new page with the specified caption
function AddPage: integer; overload;
/// mimic TTabSheet.Pages property
property Pages[aIndex: Integer]: TPageMany read GetPageMany;
/// force OnChange event to be triggered
property ActivePageIndex: integer read GetActivePageIndex write SetActivePageIndex;
property Client: TSQLRestClient read fClient;
property Source: TSQLRecord read fSource;
published
property OnChange;
end;
TFrameDetail = class(TFrame)
private
{ Private declarations }
fClient: TSQLRestClient;
fSource: TSQLRecord;
fCurrentPage: TPageMany;
protected
function GetActivePage: TPageMany;
procedure DoPageChange(Sender: TObject);
public
{ Public declarations }
PagerMany: TPagerMany;
property Client: TSQLRestClient read fClient;
property Source: TSQLRecord read fSource;
property CurrentPage: TPageMany read GetActivePage write fCurrentPage;
procedure RefreshCurrentPage;
constructor Create(aOwner: TComponent; aClient: TSQLRestClient; aSource: TSQLRecord); reintroduce;
destructor Destroy; override;
end;
implementation
{$R *.dfm}
{TPageMany}
function TPageMany.CreateGrid:{$IFDEF USENEXTPACK}TNextGrid{$ELSE}TDrawGrid{$ENDIF};
var
{$IFDEF USENEXTPACK}
CC: TNxColumnClass;
{$ENDIF}
C,R,aID: Integer;
S: String;
aClient: TSQLRestClient;
aSource: TSQLRecord;
FieldTableClass, IDClass: TSQLRecordClass;
aRecord: TSQLRecord;
P: PPropInfo;
NeedCreation: Boolean;
begin
with TPagerMany(Self.PageControl) do begin
aClient:= fClient;
aSource:= fSource;
end;
NeedCreation:= Self.Grid = nil;
if NeedCreation then begin
Grid:= {$IFDEF USENEXTPACK}TNextGrid.Create(Self){$ELSE}TDrawGrid.Create(Self){$ENDIF};
end;
with Grid do try
if NeedCreation then begin
Parent:= Self;
Align:= alClient;
end;
Table:= Many.DestGetJoinedTable(aClient,'',aSource.ID,jkDestFields);
if Table <> nil then try
{$IFDEF USENEXTPACK}
if NeedCreation then begin
for C := 0 to Table.FieldCount - 1 do begin
case Table.FieldType(C,nil) of
sftAnsiText,sftUTF8Text: CC:= TNxTextColumn;
sftEnumerate,sftSet: CC:= TNxCheckBoxColumn;
sftInteger: CC:= TNxIncrementColumn;
sftID: CC:= TNxComboBoxColumn;
sftDateTime,sftTimeLog,sftCreateTime,sftModTime: CC:= TNxDateColumn;
end;
with Columns.Add(CC, Table.GetCaption(0,C)) do begin
Options:= [coCanInput];
end;
end;
AppearanceOptions:= [aoBoldTextSelection,aoIndicateSortedColumn];
Options:= [goDisableColumnMoving,goFooter,goGrid,goHeader,goInplaceEditEvents,goLockFixedCols,goIndicator,goInput];
end;
ClearRows;
AddRow(Table.RowCount);
for R := 1 to Table.RowCount do
for C := 0 to Table.FieldCount - 1 do begin
case Table.ExpandAsString(R,C,aClient,S) of
sftID:
if aClient <> nil then try
FieldTableClass:= TSQLRecordClass(Table.FieldTable(C));
aRecord:= FieldTableClass.Create(aClient,StrToInt(S));
P:= FieldTableClass.RecordProps.Fields[C+1];
// S:= FieldTableClass.RecordProps.Fields[C+1].Name;
IDClass := TSQLRecordClass(P^.PropType^^.ClassType^.ClassType);
aID := P^.GetOrdValue(aRecord);
with IDClass.RecordProps do
if MainField[true]>=0 then begin
aClient.OneFieldValues(IDClass,FieldsName[MainField[True]],'',
TNxComboBoxColumn(Grid.Columns[C]).Items,@aID);
TNxComboBoxColumn(Grid.Columns[C]).Index:= aID;
if aID > 0 then
S:= TNxComboBoxColumn(Grid.Columns[C]).Items[aID];
end;
finally
aRecord.Free;
end;
end;
Cell[C,R-1].AsString:= S;
end;
{$ELSE}
RowCount:= 1;
ColCount:= 1;
TableToGrid:= TSQLTableToGrid.Create(Grid,Table,TSQLRestClientURI(aClient));
{$ENDIF};
finally
end;
finally
end;
Result:= Grid;
end;
class function TPageMany.CreatePageMany(aPager: TPagerMany; aMany: TSQLRecordMany;
SourceCSVFieldNames: PUTF8Char=nil; DestCSVFieldNames: PUTF8Char=nil): TPageMany;
var
PM: TPageMany;
DestClass: TSQLRecordClass;
begin
PM:= TPageMany.Create(aPager);
PM.Caption:= FormatUTF8('[%]',[aMany.SQLTableName]);
aPager.AddPage(PM);
PM.Name := 'P'+IntToStr(Random(GetTickCount));
PM.Tag := PtrInt(PM);
PM.fMany:= aMany;
DestClass:= PM.fMany.RecordProps.RecordManyDestClass;
PM.Dest:= DestClass.Create;
PM.PageControl := aPager;
PM.Grid:= PM.CreateGrid;
SetStyle(PM);
Result:= PM;
end;
destructor TPageMany.Destroy;
begin
fDest.Free;
fMany.Free;
fTableToGrid.Free;
fGrid.Free;
inherited Destroy;
end;
{ TPagerMany }
function TPagerMany.AddPage(aPage: TPageMany): Integer;
begin
aPage.PageControl := Self;
Result := PageCount-1;
end;
function TPagerMany.AddPage: Integer;
var aPage: TPageMany;
begin
aPage := TPageMany.Create(Self);
aPage.Parent := Self;
Result := AddPage(aPage);
end;
function TPagerMany.GetPageMany(aIndex: integer): TPageMany;
begin
result := inherited Pages[aIndex] as TPageMany;
end;
function TPagerMany.GetSQLMany(aIndex: integer): TSQLRecordMany;
begin
Result:= Pages[aIndex].Many;
end;
function TPagerMany.GetActivePageIndex: integer;
begin
Result := inherited ActivePageIndex;
end;
procedure TPagerMany.SetActivePageIndex(const Value: integer);
begin
inherited ActivePageIndex := Value;
Change;
if Assigned(OnChange) then
OnChange(Self);
end;
procedure TPagerMany.Change;
begin
inherited Change;
end;
class function TPagerMany.CreatePagerMany(aOwner: TComponent; aClient: TSQLRestClient; aSource: TSQLRecord): TPagerMany;
begin
Result:= TPagerMany.Create(aOwner);
if aOwner is TWinControl then
Result.Parent := TWinControl(aOwner);
Result.fClient:= aClient;
Result.fSource:= aSource;
Result.HotTrack := True;
Result.ControlStyle := Result.ControlStyle+[csClickEvents]; // enable OnDblClick
Result.Align := alClient;
Result.Font.Style:= Result.Font.Style + [fsBold];
Result.MultiLine:= True;
Result.TabWidth:= 75;
Result.OwnerDraw:= True;
SetStyle(Result);
end;
{TFrameDetail}
function TFrameDetail.GetActivePage: TPageMany;
begin
with PagerMany do
Result:= Pages[GetActivePageIndex];
end;
procedure TFrameDetail.DoPageChange(Sender: TObject);
begin
if not(Sender.InheritsFrom(TPageControl)) then
Exit;
CurrentPage:= GetActivePage;
CurrentPage.CreateGrid;
end;
procedure TFrameDetail.RefreshCurrentPage;
begin
CurrentPage.CreateGrid; //will do all the magiq
end;
constructor TFrameDetail.Create(aOwner: TComponent; aClient: TSQLRestClient; aSource: TSQLRecord);
var
i: Integer;
P: PPropInfo;
aMany: TSQLRecordMany;
IDClass: TSQLRecordClass;
begin
inherited Create(aOwner);
fClient:= aClient;
fSource:= aSource;
with Source.RecordProps do
if PagerMany = nil then begin
PagerMany:= TPagerMany.CreatePagerMany(Self,Client,Source);
PagerMany.OnChange:= DoPageChange;
for i := 0 to High(ManyFields) do begin
aMany := TSQLRecordManyClass(ManyFields[i]^.PropType^^.ClassType^.ClassType).Create;
TPageMany.CreatePageMany(PagerMany,aMany);
end;
end;
if aOwner is TWinControl then
Self.Parent:= TWinControl(aOwner);
Self.Align:= alClient;
SetStyle(Self);
end;
destructor TFrameDetail.Destroy;
begin
// PagerTop.Free;
// PagerMany.Free;
// fSource.Free;
// fClient.Free;
inherited Destroy;
end;
end.
Offline
yes please, i need it, and thanks.
a also plan to add Browse Button, to show Browse form that containing TSQLRecordClass data related to sftID.
in this form (browse form) i plan to use facility of SQLite3UIQuery.
but with filtering (not marking) the match row.
i mean, only the matches rows will be displayed on the grid.
is it possible?
Offline
Yes, this is feasible, of course.
And adding a Browse button does make sense, in case of a huge list.
In fact, using a TComboBox (like in the default implementation) would lead into something slow and difficult to use, in case of a huge number of rows.
In this case, a popup grid window, with UIQuery optionally, could be more handy.
Offline
Pages: 1