📄 delsec06.txt
字号:
rslt := DbiSetProp(hDBIObj(oTable.Handle), curSOFTDELETEON,
LongInt(Value));
if rslt <> DBIERR_NONE then
begin
DbiGetErrorString(rslt, szErrMsg);
raise Exception.Create(StrPas(szErrMsg));
end;
except
on E: EDBEngineError do ShowMessage(E.Message);
on E: Exception do ShowMessage(E.Message);
end;
finally
oTable.Refresh;
oTable.EnableControls;
end;
end;
--------------------------------------------------------------------------------
Q: "How can I create a column in the grid to which records in a dBASE table
are marked for deletion?"
A: Create a calculated field, then for the OnCalcField event of the table
replace the calculated field you've created like so:
procedure TForm1.Table1CalcFields(DataSet: TDataset);
var
RCProps : RecProps;
Result : DBIResult;
begin
Result := DbiGetRecord(Table1.Handle, dbiNoLock, Nil, @RCProps);
If RCProps.bDeleteFlag then Table1Del.Value := 'X' else
Table1Del.Value := '';
end;
Note: You must first call the SetDelete(TTable,TRUE) function from the
previous FAQ:
--------------------------------------------------------------------------------
Q: "How can I determine the actual size of a blob field as stored in
the table?"
A: Here is a function GetBlobSize that returns the size of a given blob, memo,
or graphic field. An example of calling it follows.
Function GetBlobSize(Field: TBlobField): Longint;
begin
with TBlobStream.Create(Field, bmRead) do
try
Result := Seek(0, 2);
finally
Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
{ This sets the Edit1 edit box to display the size of }
{ a memo field named Notes. }
Edit1.Text := IntToStr(GetBlobSize(Notes));
end;
--------------------------------------------------------------------------------
Q: "How do I show the contents of a memo field in a DBGrid?"
A: Use the following code for the OnDrawDataCell event of the DBGrid. Note:
before running create a TMemoField object for the memo field by double
clicking on the TTable component and adding the memo field.
procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
Field: TField; State: TGridDrawState);
var
P : array [0..50] of char; {array size is number of characters needed}
BS : tBlobStream; {from the memo field}
S : String;
begin
If Field is TMemoField then begin
with (Sender as TDBGrid).Canvas do
begin
{Table1Notes is the TMemoField}
BS := tBlobStream.Create(Table1Notes, bmRead);
FillChar(P,SizeOf(P),#0); {terminate the null string}
BS.Read(P, 50); {read 50 chars from memo into blobStream}
BS.Free;
S := StrPas(P);
while Pos(#13, S) > 0 do {remove carriage returns and}
S[Pos(#13, S)] := ' '; {line feeds}
While Pos(#10, S) > 0 do
S[Pos(#10, S)] := ' ';
FillRect(Rect); {clear the cell}
TextOut(Rect.Left, Rect.Top, S); {fill cell with memo data}
end;
end;
end;
--------------------------------------------------------------------------------
Q: "Is there a way to use the return key for data entry, instead of tab or the
mouse?"
A: Use this code for an Edit's OnKeyPress event.
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
If Key = #13 Then
Begin
SelectNext(Sender as tWinControl, True, True );
Key := #0;
end;
end;
This causes Enter to behave like tab. Now, select all controls on the form
you'd like to exhibit this behavior (not Buttons) and go to the Object
Inspector and set their OnKeyPress handler to EditKeyPress. Now, each
control you selected will process Enter as Tab. If you'd like to handle
this at the form (as opposed to control) level, reset all the controls
OnKeyPress properties to blank, and set the _form_'s OnKeyPress property to
EditKeyPress. Then, change Sender to ActiveControl and set the form's
KeyPreview property to true:
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
If Key = #13 Then
begin
SelectNext(ActiveControl as tWinControl, True, True );
Key := #0;
end;
end;
This will cause each control on the form (that can) to process Enter as Tab.
--------------------------------------------------------------------------------
Q: "How do I do a locate on a non-indexed field?"
A: The following function can be added to your to your unit and called as
follows:
Locate(Table1, Table1LName, 'Beman');
Table1 is your table component, Table1LName is TField you've add with the
fields editor (double click on the table component) and 'Beman' is the name
you want to find.
(* Locate will find SValue in a non-indexed table *)
Function Locate( const oTable: TTable; const oField: TField;
const sValue: String): Boolean;
var
bmPos : TBookMark;
bFound : Boolean;
begin
Locate := False;
bFound := False;
If not oTable.Active then Exit;
If oTable.FieldDefs.IndexOf( oField.FieldName ) < 0 then Exit;
bmPos := oTable.GetBookMark;
With oTable do
begin
DisableControls;
First;
While not EOF do
if oField.AsString = sValue then
begin
Locate := True;
bFound := True;
Break;
end
else Next;
end ;
If (Not bFound) then oTable.GotoBookMark( bmPos);
oTable.FreeBookMark( bmPos );
oTable.EnableControls;
end;
--------------------------------------------------------------------------------
Q: "Why can't I use the ixUnique option when creating indexes for Paradox
tables with the AddIndex method of the TTable component?"
A: The index options used in the AddIndex method of the TTable component are
table specific. For example, the ixUnique option works with dBASE tables
but not Paradox. The following table shows how these options apply to dBASE
and Paradox tables.
Index Options dBASE Paradox
---------------------------------------
ixUnique *
ixDescending * *
ixNonMaintained * *
ixPrimary *
ixCaseInsensitive *
--------------------------------------------------------------------------------
Q: "How can I determine the current record number for a dataset?"
A: If the dataset is based upon a Paradox or dBASE table then the record number
can be determined with a couple of calls to the BDE (as shown below). The
BDE doesn't support record numbering for datasets based upon SQL tables, so
if your server supports record numbering you will need to refer to its
documentation.
The following function takes as its parameter any component derived from
TDataset (i.e. TTable, TQuery, TStoredProc) and returns the current record
number (greater than zero) if it is a Paradox or dBASE table. Otherwise,
the function returns zero.
NOTE: for dBASE tables the record number returned is always the physical
record number. So, if your dataset is a TQuery or you have a range set
on your dataset then the number returned won't necessarily be relative to
the dataset being viewed, rather it will be based on the record's physical
position in the underlying dBASE table.
uses DbiProcs, DbiTypes, DBConsts;
function RecordNumber(Dataset: TDataset): Longint;
var
CursorProps: CurProps;
RecordProps: RECProps;
begin
{ Return 0 if dataset is not Paradox or dBASE }
Result := 0;
with Dataset do
begin
{ Is the dataset active? }
if State = dsInactive then DBError(SDataSetClosed);
{ We need to make this call to grab the cursor's iSeqNums }
Check(DbiGetCursorProps(Handle, CursorProps));
{ Synchronize the BDE cursor with the Dataset's cursor }
UpdateCursorPos;
{ Fill RecordProps with the current record's properties }
Check(DbiGetRecord(Handle, dbiNOLOCK, nil, @RecordProps));
{ What kind of dataset are we looking at? }
case CursorProps.iSeqNums of
0: Result := RecordProps.iPhyRecNum; { dBASE }
1: Result := RecordProps.iSeqNum; { Paradox }
end;
end;
end;
--------------------------------------------------------------------------------
Q: "I am getting a DBEngine message when editing a record that says "Multiple
records found but only one expected". What does this mean?
A: You may need to create a unique index on the table so that each row can be
uniquely identified. That *may* first require altering the table and adding
a column to be populated with unique values.
--------------------------------------------------------------------------------
Q: "I have had no success getting at Microsoft Access data using Delphi other
than a simple TTable view. Using TQuery I can get a read-only view to work,
but I cannot a read/write view to work. After the login screen I am
presented with an exception message like 'Passthrough SQL connection must
be shared'."
A: Use the Database Engine Configuration to change the 'SQLPASSTHRU MODE'
option in the alias associated with your Access database from its default
blank value to 'SHARED AUTOCOMMIT' (without the quotes).
--------------------------------------------------------------------------------
Q: "How can I determine when the current record in a dataset has changed?"
A: Check the DataSource's State property in the OnDataChanged event. The State
property will be set to dsBrowse if the record position has changed. The
following example will display a message box every time the record position
has changed in MyDataSource:
procedure TMyForm.MyDataSourceDataChange(Sender: TObject; Field: TField);
begin
if (Sender as TDataSource).State = dsBrowse then
ShowMessage('Record Position Changed');
end;
--------------------------------------------------------------------------------
Q: Why is it that when I create a table using the TTable component's
CreateTable method it creates the fields correctly but does not create
the indexes even though I do a
NewTable.IndexDefs.Assign(Table1.IndexDefs)?
A: This is the correct way to transfer the index definition to NewTable,
however, the IndexDefs property of Table1 may not be up-to-date so
you need to call the Update method of Table1's IndexDefs property prior
to its assignment to NewTable like this example shows:
with NewTable do begin
Active := False;
DatabaseName := 'DBDEMOS';
TableName := 'Temp';
TableType := ttParadox;
FieldDefs.Assign(Table1.FieldDefs);
Table1.IndexDefs.Update; { Do an update first }
IndexDefs.Assign(Table1.IndexDefs);
CreateTable;
end;
--------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -