I would like to add some simple database functionality to a D4 application
I have been developing for quite a while. I tried previously to use some of
the TDB* components and I had some success but I found that the application
worked differently on another computer, and I really don't think I need the
full database functionality and corresponding complexity that go along with
that.
Basically, what I would like to do is:
1. Create, edit, and use a database consisting of records with a unique
text ID, and several data points of real numbers.
2. Use the application to read test data and compare it to the expected
values as determined by standard values stored in the database.
3. Export the data and results of comparison to a file format that may be
used by Excel or MS Access.
4. Make simple reports based on this data and information from other
sources (databases).
The simple approach would be to use text records with fixed length fields
which would be stored in a text file. The file could be read into a
TStringList object which could be sorted and the desired record could be
found by searching on the text ID. But for convenient editing it may be
better to use a TStringGrid or a TDBGrid, but these add layers of
complexity. I expect to have several hundred records with total length of
about 200 characters per record.
For exporting the data, a simple approach would be a CSV format which is
directly usable by Excel and Access. The other approach is to use
Automation to access the OLE properties and methods of Excel. I have done
this sort of thing with other applications but it adds a lot of complexity.
In the Help for D4 there is information on Quick Reports components, but
this again adds complexity and it also probably limits the customer to a
specific format which is hard coded in the application. It may be better to
just export the data and allow the end users to design their own reports
using Excel or Access or perhaps other applications. This may be more
flexible as well as simpler.
I'm just in the conceptual stage of this at the moment, and I'd just like
to solicit some opinions and advice to avoid going down the wrong path. I'm
also not fully comfortable using D4 because it is a rather old version and
it seems to be the first to incorporate database functionality. Thus it is
more likely to have bugs and it may not play well with more modern
incarnations of MS Access. I have used Access 97 for a long time but I
recently purchased Access 2007 which seems to have major differences.
If anyone can offer their thoughts on how to proceed I'd greatly appreciate
it.
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
10/26/2009 10:48:22 PM |
|
Just to add a little information:
I used a TStringList object for storing, sorting, and accessing records,
but I found a problem with finding records with a unique ID field. I use
the first 15 characters of each string as an ID which must be unique, and
the remainder of the string is a sequence of data values. But now I realize
that the TStringList.Find function checks for an exact match. I had thought
that it might only check for equality of the number of characters in the
search string. So I had to create my own function.
I ran into a little unexpected problem when I used an integer variable
"Index" which I used in a for-next loop, and when I used it later as a
string index it was no longer defined. I suppose I could have used a
"while" loop with an increment of the "Index" variable. The compiler did
issue a warning.
Also I found that when I used the TStrings.SaveToStream (where stream is a
file), I had to use Seek(0,0) before calling or else the updated StringList
was appended to the file.
Something else I found difficult to do without writing a special procedure
was to copy a string into an array of characters where I wanted the initial
array to be kept as it was initialized with all spaces. This is what I did:
TReclIndex = record //All 15 characters comprise a unique
key
rType: Array[0..4] of Char;
rCoil: Array[0..6] of Char;
rCurve: Array[0..2] of Char;
end;
TReclCurveType = (Rec,Str);
TReclCurveRec = record
ReclIndex: TReclIndex; //This is the key
Time2x: Array[0..6] of Char; //These are fields for curve data
points
Time3x: Array[0..6] of Char;
Time4x: Array[0..6] of Char;
Time6x: Array[0..6] of Char;
Time8x: Array[0..6] of Char;
Time10x: Array[0..6] of Char;
TolMax: Array[0..3] of Char; //Additional information (tolerances)
TolMin: Array[0..3] of Char;
end;
TReclCurve = record
case TReclCurveType of
Rec: (R: TReclCurveRec);
Str: (S: Array[0..sizeof(TReclCurveRec)-1] of Char;) // should be );
?
end;
I found this construct rather confusing and now that I copied it here I see
an apparent error that seemed to work anyway. But I did not know just what
to call this in Delphi. In "C" it would be a union. So the help file didn't
find the proper information for this. It seems a bit strange. I refer to
the individual record fields as .R and the entire record as .S, for
instance:
S := StringOfChar(' ', sizeof(ReclCurve)); //Initialize
entire record with spaces
StrToArray( S, ReclCurve.S );
S := StringOfChar('_', sizeof(ReclCurve.R.ReclIndex)); //Initialize
index fields to underlines
StrToArray( S, ReclCurve.S );
StrToArray(cbReclType.Text, ReclCurve.R.ReclIndex.rType);
StrToArray(cbReclCoil.Text, ReclCurve.R.ReclIndex.rCoil);
StrToArray('A', ReclCurve.R.ReclIndex.rCurve);
My special function is:
procedure StrToArray( S: String; var A: Array of char );
var i: integer;
begin
for i := 1 to length(S) do begin
if (i > sizeof(A)-1) then
exit;
A[i-1] := S[i];
end;
end;
This would all probably be much easier using database functions, but I had
problems before and this seems like it will do the job. And maybe I just
need to get some sleep...
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
10/27/2009 10:51:27 AM
|
|
"Paul E. Schoen" <paul@peschoen.com> wrote in message
news:ZkAFm.15340$MZ1.6882@newsfe11.iad...
> I used a TStringList object for storing, sorting, and accessing records,
> but I found a problem with finding records with a unique ID field. I use
> the first 15 characters of each string as an ID which must be unique,
> and the remainder of the string is a sequence of data values. But now I
> realize that the TStringList.Find function checks for an exact match. I
> had thought that it might only check for equality of the number of
> characters in the search string. So I had to create my own function.
People really do make the oddest assumptions. What does the help say?
What would you think is reasonable for a 'list of strings'?
I looked over some old code that does essentially the same thing (use
a TStrings for an environment, a list of name-value pairs) and it
appears TStrings is (or was then) not sufficiently flexible to do it
properly - apart from plumbing to put integers and Booleans in the list,
there is a new IndexOfName method. No useful overrides.
> I ran into a little unexpected problem when I used an integer variable
> "Index" which I used in a for-next loop, and when I used it later as a
> string index it was no longer defined. I suppose I could have used a
> "while" loop with an increment of the "Index" variable. The compiler
> did issue a warning.
This is part of the documented semantics of for loops: the loop counter
is valid only within the loop, and is read-only to you. This allows the
compiler to use certain optimisations, and to correctly handle
'for i:=low(i) to high(i) do ...;' (think about it).
If you want a valid index after the loop, use a while loop.
If at all possible, fix warnings. Disable them only if you really must.
Never, never, NEVER ignore them.
> Also I found that when I used the TStrings.SaveToStream (where stream
> is a file), I had to use Seek(0,0) before calling or else the updated
> StringList was appended to the file.
It doesn't matter that the stream was a file; it could have happened
with any stream. Streams have a current position. It's a feature.
Seek takes a number as it second parameter but that's a mistake. It
should have been an enumeration (and in the 64-bit overload, it is).
Please use the named constants soFromBeginning/Current/End.
> Something else I found difficult to do without writing a special
> procedure was to copy a string into an array of characters where I
> wanted the initial array to be kept as it was initialized with all
> spaces.
There's nothing wrong with writing your own procedures for things.
It's what makes us programmers.
> This is what I did:
[...]
> TReclCurve = record
> case TReclCurveType of
> Rec: (R: TReclCurveRec);
> Str: (S: Array[0..sizeof(TReclCurveRec)-1] of Char;) // should be ); ?
I have no idea. Nor do I care much. If that's what the compiler wants,
that's what it gets.
> end;
>
> I found this construct rather confusing and now that I copied it here I
> see an apparent error that seemed to work anyway. But I did not know
> just what to call this in Delphi. In "C" it would be a union.
The Pascal term is a 'variant record'. No relation with Variants.
> So the help file didn't
> find the proper information for this. It seems a bit strange.
They're a historical feature and I don't like them much. They're mostly
useful in performing disk I/O, which isn't often done with fixed-size
records anymore.
> I refer to
> the individual record fields as .R and the entire record as .S, for
> instance:
>
> S := StringOfChar(' ', sizeof(ReclCurve));
> //Initialize entire record with spaces
You could just as easily use FillChar on .R. (In fact, you then wouldn't
even need .S, and could remove the .R indirection as well.)
> StrToArray( S, ReclCurve.S );
> S := StringOfChar('_', sizeof(ReclCurve.R.ReclIndex));
> //Initialize index fields to underlines
> StrToArray( S, ReclCurve.S );
> StrToArray(cbReclType.Text, ReclCurve.R.ReclIndex.rType);
> StrToArray(cbReclCoil.Text, ReclCurve.R.ReclIndex.rCoil);
> StrToArray('A', ReclCurve.R.ReclIndex.rCurve);
>
> My special function is:
>
> procedure StrToArray( S: String; var A: Array of char );
> var i: integer;
> begin
> for i := 1 to length(S) do begin
> if (i > sizeof(A)-1) then
> exit;
> A[i-1] := S[i];
> end;
> end;
I'm not sure SizeOf(A) will do what you want. Although it might; I just
don't trust it.
Anyway, this is what Move is for.
Were you never tempted to start your array indices at 1?
> This would all probably be much easier using database functions, but
> I had problems before and this seems like it will do the job. And
> maybe I just need to get some sleep...
And to read an old book on Pascal. Some things will be impressive for not
having changed in forty years, others for people ever having been forced
to actually use them at all. You'll come out with a new appreciation
for Strings and TStreams, and hopefully with an understanding of how
Pascal really works. From your questions over the last few years, I've
gotten an impression of you as a bit of the 'magic' type of programmer,
and that's really a pity. And quite unnecessary; it's all quite simple
once you know how (and why) it works underneath.
Groetjes,
Maarten Wiltink
|
|
0
|
|
|
|
Reply
|
Maarten
|
10/27/2009 12:02:52 PM
|
|
Paul
For a small database I would use descendants of TCollection /
TCollectionItem. These ancestors provide the skeleton & glue to do
what they say (with Add, Items methods etc). One adds functionality as
one needs it. I've used these many times.
Here's a quickie of your basic needs (I think). It uses a TStringList
to add your storage in each TDataItem (descended from TCollectionItem)
and a TData to hold all the TDataItems (descended from
TCollectionItem) together with SaveTo & LoadFrom methods.
Any there are any elements which are new to you, feel free to email me
for assistance.
unit DataU;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Add: TButton;
ListBox1: TListBox;
Label1: TLabel;
SaveBtn: TButton;
LoadBtn: TButton;
procedure FormCreate(Sender: TObject);
procedure AddClick(Sender: TObject);
procedure SaveBtnClick(Sender: TObject);
procedure LoadBtnClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TDataItem = class;
TData = class(TCollection)
private
function GetItem(Index : integer) : TDataItem;
public
constructor Create(ItemClass: TCollectionItemClass);
destructor Destroy; override;
function Add : TDataItem;
procedure SaveToFile(fPN : string);
procedure LoadFromFile(FPN : string);
procedure SaveToStream(Stream : TStream);
procedure LoadFromStream(Stream : TStream);
property Items[Index : integer] : TDataItem read GetItem; default;
end;
TDataItemIndex = (diiTime2x, diiTime3x, diiTime4x, diiTime6x,
diiTime8x,
diiTime10x, diiTolMax, diiTolMin);
TDataItem = class(TCollectionItem)
private
FDataSL : TStringList;
function GetValue(AIndex : integer) : string;
procedure SetValue(AIndex : integer; AValue : string);
public
constructor Create(Collection : TCollection); override;
destructor Destroy; override;
procedure SaveItemToStream(Stream : TStream);
procedure LoadItemFromStream(Stream : TStream);
property DataSL : TStringList read FDataSL;
property Time2x : string index integer(diiTime2x)
read GetValue write SetValue;
property Time3x : string index integer(diiTime3x)
read GetValue write SetValue;
property Time4x : string index integer(diiTime4x)
read GetValue write SetValue;
property Time6x : string index integer(diiTime6x)
read GetValue write SetValue;
property Time8x : string index integer(diiTime8x)
read GetValue write SetValue;
property Time10x : string index integer(diiTime10x)
read GetValue write SetValue;
property TolMax : string index integer(diiTolMax)
read GetValue write SetValue;
property TolMin : string index integer(diiTolMin)
read GetValue write SetValue;
end;
var
Form1: TForm1;
MyData : TData;
implementation
{$R *.DFM}
// = = = = = = = = = = = = = = = = = = = = = = = = =
// S t r e a m A c c e s s M e t h o d s
// = = = = = = = = = = = = = = = = = = = = = = = = =
function ReadStreamInt(Stream : TStream) : integer;
{returns an integer from stream}
begin
Stream.ReadBuffer(Result, SizeOf(Integer));
end;
function ReadStreamStr(Stream : TStream) : string;
{returns a string from the stream}
var
LenStr : integer;
begin
Result := '';
{get length of string}
LenStr := ReadStreamInt(Stream);
{set string to get memory}
SetLength(Result, LenStr);
{read characters}
Stream.Read(Result[1], LenStr);
end;
procedure WriteStreamInt(Stream : TStream; Num : integer);
{writes an integer to the stream}
begin
Stream.WriteBuffer(Num, SizeOf(Integer));
end;
procedure WriteStreamStr(Stream : TStream; Str : string);
{writes a string to the stream}
var
StrLen : integer;
begin
{get length of string}
StrLen := Length(Str);
{write length of string}
WriteStreamInt(Stream, StrLen);
if StrLen > 0 then
{write characters}
Stream.Write(Str[1], StrLen);
end;
// = = = = = = = = = = = = = = = = = = = = = = = = =
// T D a t a
// = = = = = = = = = = = = = = = = = = = = = = = = =
constructor TData.Create(ItemClass: TCollectionItemClass);
begin
inherited Create(ItemClass);
end;
function TData.Add : TDataItem;
begin
Result := TDataItem(inherited Add);
end;
function TData.GetItem(Index : integer) : TDataItem;
{this function saves having to typecast every access of the
collection item returned from inherited access to inherited Items}
begin
Result := TDataItem(inherited Items[Index]);
end;
procedure TData.SaveToFile(FPN : string);
var
FS : TFileStream;
begin
if FileExists(FPN) then
FS := TFileStream.Create(FPN, fmOpenReadWrite)
else
FS := TfileStream.Create(FPN, fmCreate);
SaveToStream(FS);
FS.Free;
end;
procedure TData.LoadFromFile(FPN : string);
var
FS : TFileStream;
begin
if FileExists(FPN) then begin
Self.Clear; // clear DataItems
FS := TFileStream.Create(FPN, fmOpenReadWrite);
FS.Seek(0, soFromBeginning);
LoadfromStream(FS);
FS.Free;
end;
end;
procedure TData.SaveToStream(Stream : TStream);
var
I : integer;
begin
Stream.Seek(0, soFromBeginning);
WriteStreamInt(Stream, Count);
for i := 0 to Count - 1 do
Items[i].SaveItemToStream(Stream);
end;
procedure TData.LoadFromStream(Stream : TStream);
var
ItemCount, i : integer;
DI : TDataItem;
begin
Stream.Seek(0, soFromBeginning);
ItemCount := ReadStreamInt(Stream);
for i := 0 to ItemCount - 1 do begin
DI := Self.Add;
DI.LoadItemFromStream(Stream);
end;
end;
destructor TData.Destroy;
var
i : integer;
begin
for i := 0 to Self.Count - 1 do
Self.Items[i].Free;
inherited Destroy;
end;
// = = = = = = = = = = = = = = = = = = = = = = = = =
// T D a t a I t e m
// = = = = = = = = = = = = = = = = = = = = = = = = =
constructor TDataItem.Create(Collection : TCollection);
var
i : integer;
begin
inherited Create(Collection);
FDataSL := TStringList.Create;
for i := 0 to 7 do
FDataSL.Add(' ');
end;
function TDataItem.GetValue(AIndex : integer) : string;
begin
Result := DataSL.Strings[AIndex];
end;
procedure TDataItem.SetValue(AIndex : integer; AValue : string);
begin
DataSL.Strings[AIndex] := AValue;
end;
procedure TDataItem.SaveItemToStream(Stream : TStream);
begin
WriteStreamStr(Stream, Self.FDataSL.Text);
end;
procedure TDataItem.LoadItemFromStream(Stream : TStream);
begin
Self.FDataSL.Text := ReadStreamStr(Stream);
end;
destructor TDataItem.Destroy;
begin
DataSL.Free;
inherited Destroy;
end;
// = = = = = = = = = = = = = = = = = = = = = = = = =
// T D a t a / T D a t a I t e m U s a g e
// = = = = = = = = = = = = = = = = = = = = = = = = =
procedure TForm1.FormCreate(Sender: TObject);
begin
MyData := TData.Create(TDataItem); // create collection
end;
procedure TForm1.AddClick(Sender: TObject);
var
DI : TDataItem;
begin
DI := MyData.Add;
with DI do begin
{any old test data - I don't know what yours is like}
Time2x := 'One' + IntToStr(MyData.Count);
Time3x := 'Two';
Time4x := 'Three';
Time6x := 'Four';
Time8x := 'Five';
Time10x := 'Six';
TolMax := 'Max';
TolMin := 'Min';
end;
end;
procedure TForm1.SaveBtnClick(Sender: TObject);
begin
MyData.SaveToFile('E:\AProject\Collection Data\TestData.dat');
end;
procedure TForm1.LoadBtnClick(Sender: TObject);
begin
MyData.LoadFromFile('E:\AProject\Collection Data\TestData.dat');
end;
end.
Alan Lloyd
|
|
0
|
|
|
|
Reply
|
alanglloyd
|
10/28/2009 7:54:24 AM
|
|
"Maarten Wiltink" <maarten@kittensandcats.net> wrote in message
news:4ae6e171$0$83251$e4fe514c@news.xs4all.nl...
> "Paul E. Schoen" <paul@peschoen.com> wrote in message
> news:ZkAFm.15340$MZ1.6882@newsfe11.iad...
>
>> I used a TStringList object for storing, sorting, and accessing records,
>> but I found a problem with finding records with a unique ID field. I use
>> the first 15 characters of each string as an ID which must be unique,
>> and the remainder of the string is a sequence of data values. But now I
>> realize that the TStringList.Find function checks for an exact match. I
>> had thought that it might only check for equality of the number of
>> characters in the search string. So I had to create my own function.
>
> People really do make the oddest assumptions. What does the help say?
> What would you think is reasonable for a 'list of strings'?
After I went through the debugging process and created a function to do
what I wanted, I had a sort of d'oh slap on the forehead moment. I think I
may have been thinking of a database-oriented find function or possibly
equality of strings in VB. The help does clearly state that its purpose is
to avoid duplicate strings or to find an exact match.
> I looked over some old code that does essentially the same thing (use
> a TStrings for an environment, a list of name-value pairs) and it
> appears TStrings is (or was then) not sufficiently flexible to do it
> properly - apart from plumbing to put integers and Booleans in the list,
> there is a new IndexOfName method. No useful overrides.
Yes, it was probably more difficult forcing it to work than just learning
how to use the database functions properly.
>> I ran into a little unexpected problem when I used an integer variable
>> "Index" which I used in a for-next loop, and when I used it later as a
>> string index it was no longer defined. I suppose I could have used a
>> "while" loop with an increment of the "Index" variable. The compiler
>> did issue a warning.
>
> This is part of the documented semantics of for loops: the loop counter
> is valid only within the loop, and is read-only to you. This allows the
> compiler to use certain optimisations, and to correctly handle
> 'for i:=low(i) to high(i) do ...;' (think about it).
>
> If you want a valid index after the loop, use a while loop.
>
> If at all possible, fix warnings. Disable them only if you really must.
> Never, never, NEVER ignore them.
Actually I only noticed the warning when I finally ran the program in the
IDE. When I did the syntax check it did not show the warnings. It just
seemed odd to me that having defined and initialized the loop counter as a
var in the procedure before the loop, and also using it after the loop,
would have caused the compiler to recognize my intention and bypass the
optimization. But that was a bad ASSumption.
>
>
>> Also I found that when I used the TStrings.SaveToStream (where stream
>> is a file), I had to use Seek(0,0) before calling or else the updated
>> StringList was appended to the file.
>
> It doesn't matter that the stream was a file; it could have happened
> with any stream. Streams have a current position. It's a feature.
>
> Seek takes a number as it second parameter but that's a mistake. It
> should have been an enumeration (and in the 64-bit overload, it is).
> Please use the named constants soFromBeginning/Current/End.
Yes, that was just a lazy shortcut. Certainly not good programming
practice. But it had been a long night.
>
>
>> Something else I found difficult to do without writing a special
>> procedure was to copy a string into an array of characters where I
>> wanted the initial array to be kept as it was initialized with all
>> spaces.
>
> There's nothing wrong with writing your own procedures for things.
> It's what makes us programmers.
Probably I was thinking of strings and character arrays in C, where they
can be more freely mixed and there are functions I had been accustomed to
that would do what I wanted.
>> This is what I did:
> [...]
>
>> TReclCurve = record
>> case TReclCurveType of
>> Rec: (R: TReclCurveRec);
>> Str: (S: Array[0..sizeof(TReclCurveRec)-1] of Char;) // should be ); ?
>
> I have no idea. Nor do I care much. If that's what the compiler wants,
> that's what it gets.
I tried it both ways with the same apparent result. No errors displayed
anyway.
>> I found this construct rather confusing and now that I copied it here I
>> see an apparent error that seemed to work anyway. But I did not know
>> just what to call this in Delphi. In "C" it would be a union.
>
> The Pascal term is a 'variant record'. No relation with Variants.
Now I finally found it in help, as "Variant parts in records". It is not
really the same as a "C" union, as the variant records may be of different
size. In my case I had a block of memory (an array of characters) which I
wanted to handle as a single block, or record, and also as fixed length
fields.
>> So the help file didn't
>> find the proper information for this. It seems a bit strange.
>
> They're a historical feature and I don't like them much. They're mostly
> useful in performing disk I/O, which isn't often done with fixed-size
> records anymore.
>
>
>> I refer to
>> the individual record fields as .R and the entire record as .S, for
>> instance:
>
>>
>> S := StringOfChar(' ', sizeof(ReclCurve));
>> //Initialize entire record with spaces
>
> You could just as easily use FillChar on .R. (In fact, you then wouldn't
> even need .S, and could remove the .R indirection as well.)
>
>
>> StrToArray( S, ReclCurve.S );
>> S := StringOfChar('_', sizeof(ReclCurve.R.ReclIndex));
>> //Initialize index fields to underlines
>> StrToArray( S, ReclCurve.S );
>> StrToArray(cbReclType.Text, ReclCurve.R.ReclIndex.rType);
>> StrToArray(cbReclCoil.Text, ReclCurve.R.ReclIndex.rCoil);
>> StrToArray('A', ReclCurve.R.ReclIndex.rCurve);
>>
>> My special function is:
>>
>> procedure StrToArray( S: String; var A: Array of char );
>> var i: integer;
>> begin
>> for i := 1 to length(S) do begin
>> if (i > sizeof(A)-1) then
>> exit;
>> A[i-1] := S[i];
>> end;
>> end;
>
> I'm not sure SizeOf(A) will do what you want. Although it might; I just
> don't trust it.
>
> Anyway, this is what Move is for.
>
> Were you never tempted to start your array indices at 1?
Probably another "C" throwback, where arrays of characters (and strings)
are zero based. It was clearer to me to use the string array based at 1. I
find the multitude of string-like types confusing, especially when some
functions use String, PChar, and even TCaption for essentially the same
purpose. Often I just try a typecast and if the compiler doesn't choke, I
let it go. And probably sometimes it bites me in the butt.
>> This would all probably be much easier using database functions, but
>> I had problems before and this seems like it will do the job. And
>> maybe I just need to get some sleep...
>
> And to read an old book on Pascal. Some things will be impressive for not
> having changed in forty years, others for people ever having been forced
> to actually use them at all. You'll come out with a new appreciation
> for Strings and TStreams, and hopefully with an understanding of how
> Pascal really works. From your questions over the last few years, I've
> gotten an impression of you as a bit of the 'magic' type of programmer,
> and that's really a pity. And quite unnecessary; it's all quite simple
> once you know how (and why) it works underneath.
I'm sure I still have my first book on Pascal (and Turbo Pascal) that I
bought in 1987 when I took a "structured programming" course. By that time
I had been using BASIC and various forms of assembly for about 20 years.
But that consisted of college computer courses from 1967 to 1970 (BASIC and
a little Fortran and Assembly on mainframes using punch cards and paper
tape on a teletype with acoustic modem), and then very little until around
1980 when I got involved with CP/M and 8085 and Z80 assembly, then BASIC
and a little assembly on early IBM PCs starting around 1982. But my
principal skillset was (and still is) electronics design and high power
electrical design, although after 1985 much instrumentation was based on
microprocessers and controllers.
Not long after doing some simple programs in Borland Turbo Pascal I
discovered C, and then I used Borland C for many MSDOS console
applications, mostly with a lot of low-level I/O. It was probably around
1997 that I bought both Borland Delphi 4 Pro and also Borland C++ Builder
3, each for about $100 at a computer show. At first I just used the Borland
C++ for its better Windows-based IDE but still for MSDOS console
applications. I tried my hand at C++ and eventually used it around 1996 to
make a very early Windows based version of my Ortmaster program which I
originally released as an MSDOS app in 1994. As my first foray into Windows
applications it was very crude and I lacked familiarity with OOP.
I'm not sure how I got started with Delphi. By 1999 I had made a demo
Ortmaster application using Delphi, and by 2003 there were many customers
who had purchased the old Ortmaster system and now their new computers
would not run the application, so my distributor and I started work on a
new design which would no longer require the parallel port for the hardware
interface and true MSDOS to run. By 2005 I had a hardware and software
solution using a serial port, but for various reasons the software being
developed by my distributor proceeded sporadically. He decided to use
VB.NET because one of his technicians learned it in school, but after a
couple of years he quit, and finally he hired a professional programmer who
had helped me with some basic concepts of Delphi.
At this point I have designed and built a USB version of the hardware and I
have invested in 120 PC boards and parts, but the other half of the
software (which is mostly data processing and reports) is still not ready,
and I have decided that I must proceed with my own version so I can get
something out to customers who have been screaming for this new release for
several years. Thus my recent efforts as touched upon here.
So, my involvement in software is on an "ad hoc" basis, such that I do just
enough programming to get this system (as well as others) working. I am
also involved with the hardware design, board layout, assembly,
prototyping, and production, as well as marketing, procurement, and
accounting. This is now my major project, but I have been similarly
involved in other projects. This project has been especially frustrating
because I have had to work with my distributor and he has his own narrow
set of ideas on how to structure the design effort. And he has refused to
write any sort of software specification, claiming that he will do so
*after* the program is complete, because he feels it is a waste of time to
write it and then change it as the project takes shape. So the concept is
still in his head except for bits and pieces that I get from his occasional
emails.
I know this has been "too much information", but perhaps it begins to
explain why I do not have the depth of experience and knowledge that most
professional programmers have and need to succeed. I consider Delphi as one
tool among many, and I use it because I find it very capable and actually
fun to use. But I do not have the time or desire to do extensive learning
about everything it can do. I try to write programs that are well
structured and maintainable, but often I find that I must learn on-the-fly
and often that means ugly code and a debugging nightmare. But I have many
other priorities.
Whew, that's enough! And I appreciate all the help you've given me over the
past few years.
Thanks,
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
10/28/2009 8:16:51 AM
|
|
"Paul E. Schoen" wrote:
>
> TReclIndex = record //All 15 characters comprise a unique
>key
> rType: Array[0..4] of Char;
> rCoil: Array[0..6] of Char;
> rCurve: Array[0..2] of Char;
> end;
...
> This would all probably be much easier using database functions, but I had
> problems before
I wonder what those problems exactly were? I am almost 99% sure that
using some ready written Database that has been tested for years would
be the reason to your problem.
Now you have chosen to start writing your own database look-alike
solution. Of course that may be interesting for some time.
But of course that is also not what you should do. Not even if you are a
part time programmer. Your first attempts will be much clumsier and have
tons of bugs, compared tothose finalized components. And there's no time
when someone asks for multi user, better reports etc.
So you have decided that your data should be saved to CSV semicolon
limited text file? Even then your better _not_ start writing that kind
of functionality yourself. All that already exists, tested with tens of
hundreds of people, and all sources are available for free.
Use for instance components TkbmMemTable and its counterpart
TkbmCSVStreamFormat. You'll be able to use your data indexed, sorted and
manipulated with ease. And you can save get your data to a CSV file.
"@@FILE VERSION@@","251"
"Name","Phone","Address",
"Susan","888-777 890","Rubicon Lane 542",
"Peter","990-67890","Parsons Street 7",
TkbmMemTable uses Delphi's standard TDataSet schema. Works nicely with
all Data Controls, DbGrids etc. You'll easily find code how to export
your data from TkbmMemTable to Excel format, or how to write simple
reports from your TkbmMemTable datasets etc.
> And maybe I just need to get some sleep...
All right then. And maybe I also just need to let you continue writing
your code and solve your problem exactly as you wish.
Making your own small programming inventions and findings may be more
rewarding for some time (even some years..) than just struggling to make
your everyday living in programming.
I do not have that kind of luxury any more. I just can't start writing
any bigger chunk of code that already exists and that is available for
me for free or costs some hundred bucks.
-AP
|
|
0
|
|
|
|
Reply
|
AP
|
10/28/2009 9:08:46 AM
|
|
"Paul E. Schoen" <paul@peschoen.com> wrote in message
news:Q8TFm.15413$MZ1.12901@newsfe11.iad...
> "Maarten Wiltink" <maarten@kittensandcats.net> wrote in message
> news:4ae6e171$0$83251$e4fe514c@news.xs4all.nl...
>> "Paul E. Schoen" <paul@peschoen.com> wrote in message
>> news:ZkAFm.15340$MZ1.6882@newsfe11.iad...
[...]
>>> TReclCurve = record
>>> case TReclCurveType of
>>> Rec: (R: TReclCurveRec);
>>> Str: (S: Array[0..sizeof(TReclCurveRec)-1] of Char;) // should be ); ?
>>
>> I have no idea. Nor do I care much. If that's what the compiler wants,
>> that's what it gets.
>
> I tried it both ways with the same apparent result. No errors displayed
> anyway.
Probably it's yet another instance of the semicolon being a separator,
not a terminator, and empty parts being allowed. The effect is that you
don't need a semicolon after the last declaration, and can sprinkle them
anywhere you like.
So I use them as terminators except where expressly forbidden, as I
expect most Pascal programmers do.
[...]
>>> maybe I just need to get some sleep...
>>
>> And to read an old book on Pascal. ...
>
> I'm sure I still have my first book on Pascal (and Turbo Pascal) that I
> bought in 1987 when I took a "structured programming" course. By that
> time I had been using BASIC and various forms of assembly for about 20
> years.
<snip The Story of Paul's Professional Life>
> I know this has been "too much information", but perhaps it begins to
> explain why I do not have the depth of experience and knowledge that
> most professional programmers have and need to succeed. ...
No, it's not TMI; I like hearing this sort of stuff. It reminds me that
not everybody is a programmer and there are other worthy skills that I
don't have.
I'll readily admit that sometimes I'm disappointed by it, but I know it's
a reality that no, in fact most professional programmers manage to get
by with a disturbing (to me) _lack_ of experience and knowledge. As I get
older, it becomes easier to live with.
Working in assembly is usually a good preparation for higher-level
programming. It shows how a computer works on the level below third
generation languages, and takes the mystery out of it. Knowing what
Pascal needs to translate can explain many of the design choices made
in the language.
Groetjes,
Maarten Wiltink
|
|
0
|
|
|
|
Reply
|
Maarten
|
10/28/2009 10:23:05 AM
|
|
<alanglloyd@aol.com> wrote in message
news:eeb236c6-26ae-4391-b82e-d24ac17aa82f@v30g2000yqm.googlegroups.com...
> Paul
>
> For a small database I would use descendants of TCollection /
> TCollectionItem. These ancestors provide the skeleton & glue to do
> what they say (with Add, Items methods etc). One adds functionality as
> one needs it. I've used these many times.
>
> Here's a quickie of your basic needs (I think). It uses a TStringList
> to add your storage in each TDataItem (descended from TCollectionItem)
> and a TData to hold all the TDataItems (descended from
> TCollectionItem) together with SaveTo & LoadFrom methods.
>
> Any there are any elements which are new to you, feel free to email me
> for assistance.
Thanks for the code. I made an additional form in my Ortmaster project,
inserted your code and placed buttons and the ListBox as components, and I
added a little button to show the form. I realize that the example was only
a framework, but looking at it more closely I don't think it will do what I
want any better than what I already have, and it would take some work to
get that far.
I think it will become important to manipulate and store the data in a true
database. The curve data that I am working on now has fixed length fields,
the first three of which constitute a searchable and unique key, based on
model, coil size, and curve. The remaining data are times corresponding to
preset multiples of current (2X, 3X, 10X, etc), and using a cubic spline
function the time for any current within and somewhat beyond the limits may
be determined. Thus test results may be compared to the standard curve
points and the deviation may be compared to the tolerance and used for
GO/NOGO results.
There will be another database which is indexed on a specific device serial
number or other ID. This data will contain information on specific details,
which include the model, coil size, and one or more curves that may apply
depending on how it is configured.
A third database will consist of test results, which have a unique
date/time stamp and also a Recloser ID which identifies the model, coil
sizes, and curves. Each test result will have up to four current values,
four trip time values, and four reclose intervals (time between current
pulses). Each current/time pair correspond to a particular curve. There
will also be a field for test type, which may be specified as 3X, 4X, 8X,
etc. There is also a MPU test which will have only a current value which
should be a certain multiple (2x or maybe 1.5x) of the coil size. And there
is also a GND test which may be conducted at several multiples of a
separate GND TRip coil.
You can see that this is rather complex, and there may be even more
databases such as Technician and Company. The Ortmaster program is
primarily for obtaining and storing test results, and determining GO/NOGO
results. The curves and recloser databases may be maintained using an
external database program, but they need to be readable with the Ortmaster
program, and the test results need to be formatted for inclusion. The
original concept used a separate program to do the database manipulation,
and the Ortmaster program simply accepted a text file with information
needed to set up the test, and the results were returned in a different
text file for data analysis and storage, as well as reports and maintenance
of the other supporting databases. Perhaps this may be the better approach.
I am now undertaking this part of the project because of difficulties
working with someone else who had developed the previous MSDOS version of
his TCC application that worked with my MSDOS ORTRUN program. We had been
working on the Windows version of this project since about 2004, at which
time I had a working version of the hardware and software. It went through
many changes, including the use of a USB connection rather than a serial
port, but the main problem as I see it was the development of the TCC
program. The project was originally coded in VB .NET, and it was started by
a student and then transferred to a professional programmer I recommended,
who introduced me to Delphi but who also knows VB. However he is not
familiar with the actual testing process and the entire concept of the TCC
software exists only in the brain of the original developer, who has
refused to write a software specification. He considers that a waste of
time and says he will do it only when the program is finished. Kind of like
having a house built and then building the foundation under it.
I'm thinking that I might need to upgrade from D4 to a newer version. I
think D4 introduced database functionality but used the proprietary BDE. D5
AIUI introduced ADO which is more universal and allows connection to a MS
Access database, which I am fairly familiar with. I am also familiar with
dBase III+ format which I used in another project almost 20 years ago
(Nantucket Clipper). It would be possible to make (or perhaps
find/purchase) a Delphi unit that could manipulate that format, as it is
mostly text files. But using index files and building and maintaining
relations is a bit trickier.
So, maybe upgrading would be the best option. I think there are upgrades
available for about $500 or less to D7 and maybe even D2009 Pro. There may
even be some D5 or D6 or D7 on eBay for cheap. I've certainly gotten my
$100 worth from D4 pro, and having the latest and greatest may be well
worth it. My main worry is getting used to the new IDE and making sure I
don't introduce subtle bugs or compatibility problems.
I have an older version of the Ortmaster program and some additional
information on my website www.Ortmaster.com if you would like to have a
look. I will post a newer version (in setup format) that will actually
install the program. It's a simple install and does not use the registry or
take any other possibly dangerous action.
Suggestions welcome. Thanks!
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
10/30/2009 4:21:33 PM
|
|
If you're really convinced to go a "real" database then what about
InterBase (IB) datasets, which respond to SQL. Or MySQL.
OTOH I've found TCollection/TCollectionItem work well with all simple
accesses (not more than a couple of criteria). The separation of
methods which "belong" to the whole data from that for a particular
item is most convenient.
I've gone the route I have because I am not totally familiar with SQL
language.
I think a detailed outline of what you want to do with the data, and
their relationships, would clarify your choice and be necessary anyway
whatever route you chose.
Alternateively 4th Dimension is a powerful, easy to start, but
somewhat quirky. It has powerful graphic IDE (from its Mac heritage
which it carried across to its Windows implementation). Its got good
documenting capabilities.
Alan Lloyd.
|
|
0
|
|
|
|
Reply
|
alanglloyd
|
10/31/2009 10:23:09 AM
|
|
"Paul E. Schoen" <paul@peschoen.com> wrote in message
news:tpEGm.836$3P2.458@newsfe09.iad...
[...]
> I think it will become important to manipulate and store the data
> in a true database.
Are your data relational? If not, there are few advantages over
text files. (I'm very fond of text files myself because *I* can
parse them, too, and edit them if necessary.)
[...]
> There will be another database which is indexed on a specific device
> serial number or other ID. ...
Databases aren't indexed. Tables are indexed.
> A third database will consist of test results, which have a unique
> date/time stamp and also a Recloser ID which identifies the model,
> coil sizes, and curves. Each test result will have up to four current
> values, four trip time values, and four reclose intervals (time
> between current pulses). ...
Three databases? You may be thinking in the wrong direction. You can
create any number of tables all in the same database. You can have
tables linked into clusters through foreign keys, and you can have
several unrelated clusters (I tend to think of them as subsystems)
still in the same database.
> [...] the entire concept of the TCC software exists only in the brain
> of the original developer, who has refused to write a software
> specification. He considers that a waste of time and says he will do
> it only when the program is finished.
Hm. Optimised for job security... his.
> I'm thinking that I might need to upgrade from D4 to a newer version.
> I think D4 introduced database functionality but used the proprietary
> BDE. D5 AIUI introduced ADO which is more universal and allows
> connection to a MS Access database, ...
I was supplied with Delphi 2007 at work but we're _still_ stuck with
the BDE.
Can't you just import the right type libraries into D4? In my previous
job we worked with raw ADO and it was a breeze compared to the mess of
datamodules and dbgrids I get to maintain now.
Groetjes,
Maarten Wiltink
|
|
0
|
|
|
|
Reply
|
Maarten
|
10/31/2009 2:13:54 PM
|
|
"Maarten Wiltink" <maarten@kittensandcats.net> wrote in message
news:4aec4623$0$83235$e4fe514c@news.xs4all.nl...
> "Paul E. Schoen" <paul@peschoen.com> wrote in message
> news:tpEGm.836$3P2.458@newsfe09.iad...
> [...]
>> I think it will become important to manipulate and store the data
>> in a true database.
>
> Are your data relational? If not, there are few advantages over
> text files. (I'm very fond of text files myself because *I* can
> parse them, too, and edit them if necessary.)
I feel more comfortable with text files for similar reasons. I think I can
use what I have concocted and maybe add an export utility for a CSV file
that can be read by Excel or Access. I will probably want to keep my curves
database separate from the test results, which will be used for reports.
> [...]
>> There will be another database which is indexed on a specific device
>> serial number or other ID. ...
>
> Databases aren't indexed. Tables are indexed.
That's just from my days working with dBase III+ which used separate DBF
files for tables (and separate NDX and NTX files, among others. But, yes, I
meant tables.
>> A third database will consist of test results, which have a unique
>> date/time stamp and also a Recloser ID which identifies the model,
>> coil sizes, and curves. Each test result will have up to four current
>> values, four trip time values, and four reclose intervals (time
>> between current pulses). ...
>
> Three databases? You may be thinking in the wrong direction. You can
> create any number of tables all in the same database. You can have
> tables linked into clusters through foreign keys, and you can have
> several unrelated clusters (I tend to think of them as subsystems)
> still in the same database.
Yes, I have worked with MS Access 97 for quite some time and now I have
Access 2007. The new software will open old DBF files and old Access97 MDB
files, but the new file format is ACCDB
>> [...] the entire concept of the TCC software exists only in the brain
>> of the original developer, who has refused to write a software
>> specification. He considers that a waste of time and says he will do
>> it only when the program is finished.
>
> Hm. Optimised for job security... his.
He and I worked together fairly well in the beginning when I just had to
develop the hardware and software to interface to his original MSDOS
application. He wrote the application himself, and it is amateurish, even
for an MSDOS console application. The information must be entered
sequentially in response to prompts, and you can't go back and edit if you
make a mistake. But since that time he has left his job as a recloser test
technician and he has been doing network installations (as well as
operating a skeet shooting range and going hunting for deer and bear). He
does not have the skills to do serious programming even at my fairly
amateurish level, and the programmer he hired does not have much knowledge
of the testing of reclosers. I got a patent for a recloser test set in 1980
and I have fairly extensive experience in the field of electrical testing,
and I offered to do the TCC software but he had already started it with a
student programmer who used VB .NET and he didn't want to "waste" the code
by using a different language like Delphi. And he claims to be working
10-12 hours a day, 7 days a week, so I think he is sleep deprived and
probably not thinking too clearly and having anger issues. So I am glad to
be breaking away from his influence.
>> I'm thinking that I might need to upgrade from D4 to a newer version.
>> I think D4 introduced database functionality but used the proprietary
>> BDE. D5 AIUI introduced ADO which is more universal and allows
>> connection to a MS Access database, ...
>
> I was supplied with Delphi 2007 at work but we're _still_ stuck with
> the BDE.
>
> Can't you just import the right type libraries into D4? In my previous
> job we worked with raw ADO and it was a breeze compared to the mess of
> datamodules and dbgrids I get to maintain now.
I have searched for and found some Delphi components that do not use the
BDE. Some are freeware and some cost $150 or so. But I'm not sure just what
I need. Mostly I'd be happy if I could work with an Access database. There
will be some fairly simple relationships that could be handled even with
text files.
Several I've looked at are:
http://bde-replacements.aidaim.org/in-memory_sql_database_delphi.htm
http://www.componentace.com/bde_replacement_database_delphi_absolute_database.htm
http://www.freedownloadscenter.com/Programming/Delphi_Tools_and_Components/LMD_Tools_4_5X_for_Delphi_4.html
http://www.smartcode.com/downloads/delphi-personal-database-component.html
http://www.aptrio.com/Development/Databases-Networks/branko-s-database-components-1155.html
I've made some good progress with the program and now I just need to figure
out exactly how some testing is done. The single phase hydraulic reclosers
I am most familiar with just have a sequence of up to four operations which
may be either fast trip or delayed according to preset time/current curves.
Fast trip curves are designated as "A", and the delayed curves may be B, C,
D, or E. Three phase reclosers just have three units ganged together, so
the tests must specify phase A, B, or C. But some reclosers have more
complicated curves designated as 1, 1-2, 1-3, 19, and others. Many of these
are ground trip curves which can be set in various ways and the curves are
sometimes shifted by a certain time period. I am working with someone at a
large testing company who has agreed to help.
For more information on reclosers and their testing there is a lot of
literature on the Cooper website:
http://www.cooperpower.com/Library/Literature/section.asp?ProductLineID=12
Thanks,
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
10/31/2009 3:31:35 PM
|
|
I just uploaded this new version of Ortmaster to my www.Ortmaster.com
website. It is Ortmaster.zip, and you just run the "install.exe" program.
When you run the Ortmaster.exe program, use the menu\view\enhanced mode to
show the Recloser Data button. When you click on it, it opens the main data
form where you select the first items in the combo boxes for a 3H type, 5
amp, B or C curve. I have tabbed pages for the curve data. To run a test,
select test type 6X, and click Run Test. On the main test form click start,
and the program will simulate a test in real time from a saved waveform
file. Once the operations are complete, the CheckTCC button will be
enabled. That will show the results form, with the test results and
minimum, maximum, and optimum values. You can also click on "Keyboard
Input" and edit the test results, then click "Analyze" to check the new
results. There is also a "View Curves" button that shows the curves
graphically.
There is also a "View Waveform" menu item that is on the main test form and
it shows the waveform of the current and allows measurements of portions
like a digital storage oscilloscope.
I need to add the actual checking of trip times with the curves. That will
take another day or two. The recloser curve database file is
"Ortmaster.rcf" in the Ortmaster directory under App Data.
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
10/31/2009 3:56:24 PM
|
|
"Paul E. Schoen" <paul@peschoen.com> wrote in message
news:sMYGm.1375$XP2.292@newsfe17.iad...
[...]
> I have searched for and found some Delphi components that do not use
> the BDE. Some are freeware and some cost $150 or so. But I'm not sure
> just what I need. Mostly I'd be happy if I could work with an Access
> database.
I certainly don't know what exactly you need, but if you're not using
data-aware controls, you can probably get everything done with
manually declared Database and Recordset (interface) variables and
calling methods on them.
Groetjes,
Maarten Wiltink
|
|
0
|
|
|
|
Reply
|
Maarten
|
10/31/2009 4:54:13 PM
|
|
I have just made a Delphi project to try and understand how to create and
use the database controls and objects. I was (finally) able to create a
dbTest.DBF file and insert one record of data. But I ran into problems when
the file existed and I tried to open it. Here is my code:
procedure TForm1.btCreateClick(Sender: TObject);
var DBIresult: Word;
begin
if DataSource1 = nil then
DataSource1 := TDataSource.Create(self);
if Table1 = nil then
Table1 := TTable.Create(self);
if FileExists('dbTest.dbf') then begin
if not Table1.CheckOpen(DBIresult) then //This gives me
a BDE exception
exit;
If not Table1.Exists then begin // If I bypass
the CheckOpen this gives me AVs
Table1.FieldDefs.Clear;
Table1.FieldDefs.Add('ITEM', ftString, 30, True);
Table1.FieldDefs.Add('QTY', ftInteger, 0, True);
Table1.CreateTable;
Table1.Active := True;
Table1.InsertRecord( ['ABC', 123]);
end;
end
else begin // When I
delete the file, this works OK
Table1.FieldDefs.Clear;
Table1.FieldDefs.Add('ITEM', ftString, 30, True);
Table1.FieldDefs.Add('QTY', ftInteger, 0, True);
Table1.CreateTable;
Table1.Active := True;
Table1.InsertRecord( ['ABC', 123]);
end;
Table1.Active := True;
dbTest1.Open;
dbTest1.StartTransaction;
end;
On Form Close:
if dbTest1.InTransaction then
dbTest1.Commit;
if dbTest1.Connected then
dbTest1.Close;
Table1.Close;
Table1.Free;
Table1 := nil;
DataSource1.Free;
DataSource1 := nil;
The database components are set up as follows:
Table1.DatabaseName := dbTest;
Table1.TableName := dbTest;
Table1.TableType := TTDbase;
dbTest1: TDatabase;
dbTest1.DatabaseName := dbTest;
dbTest1.DriverName := Microsoft Access dBASE Driver (;
DataSource1.DataSet := Table1;
When I close the application I can open the dbTest.DBF file in MS Access
2007 and it seems fine. It also saves it as dbTest.accdb.
When I added dbGrid and dbNavigator components, and set the DataSources to
DataSource1, I got an AV error and then when I tried again it went into an
endless loop and the CPU window showed garbage. Previously I also sometimes
got the SQL cursor but it was hung up. Sometimes I got an insufficient
memory error and I had to restart Delphi.
I have another application that uses some of these same components but
somehow I got it to run without serious errors, although it did not really
run correctly. In that project I created the components rather than
dropping them on the form. Here is some of the code:
DataSourceOptions := TDataSource.Create(FormData);
DataSource1 := TDataSource.Create(FormData);
Table1 := TTable.Create(FormData);
Table1.DatabaseName := 'dBase Files';
Table1.TableType := ttdBase;
Table1.FieldDefs.Clear;
Table1.FieldDefs.Add('ITEM', ftInteger, 0, True);
Table1.FieldDefs.Add('QTY', ftInteger, 0, True);
Table1.TableName := 'BOMdata1';
Table1.CachedUpdates := True;
Table1.CreateTable;
DataSource1.DataSet := Table1;
DataSource1.AutoEdit := True;
DataSource1.Enabled := True;
DBGrid1.DataSource := DataSource1;
DBGrid1.Columns.Add;
DBGrid1.Columns[0].Field := Table1.FieldByName('ITEM');
DBGrid1.Columns.Add;
DBGrid1.Columns[1].Field := Table1.FieldByName('QTY');
DBNavigator1.DataSource := DataSource1;
DBGrid1.Enabled := True;
Table1.Active := False;
Table1.EmptyTable;
Table1.Active := True;
Table1.AppendRecord([CompName, CompType, CompDecal, PartNum,
PartCost,
PartDescr, PartValue, PartTolerance, PartPower, PartVoltage,
PartCurrent,
PartMfr1, PartMfrNum, AttrCount, AttrList]);
Table1.Refresh; // Remove duplicates
This seems to work, but I was unable to save the database. I probably
needed to add:
dbTest1.Open;
dbTest1.StartTransaction;
dbTest1.Commit;
dbTest1.Close;
Every time I think I understand it, something seems to go wrong. When I
tried to use the Microsoft Access driver I got a log-on dialog and it would
not accept blanks. I checked the driver setups and I changed the user name
and password but it still would not accept them and gave errors. Either I
am doing something very stupid or there is something wrong with the Delphi
implementation. Maybe a combination of both.
If you can shed some light on any errors in the above code and fix it so I
can just create or open this simple file and use the dbGrid and navigator,
and save the file, that will probably be enough. But I really hope to
understand why I get the severe errors I do. Perhaps there is a patch for
D4 for that I don't have? There should be a stupid simple demo project that
can be used to determine if there is a problem with the BDE or some of the
database functions.
Ugh, another all-nighter...Thanks!
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
11/1/2009 11:43:03 AM
|
|
I just tried to add a dbGrid component, and when I tried to use the object
inspector to set the field names, the whole IDE crashed instantly. When I
tried again, I got the SQL cursor forever until I ended the program.
Something is very wrong....
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
11/1/2009 12:03:54 PM
|
|
"Paul E. Schoen" <paul@peschoen.com> wrote in message
news:XPeHm.3884$Mg.2368@newsfe01.iad...
>I just tried to add a dbGrid component, and when I tried to use the object
>inspector to set the field names, the whole IDE crashed instantly. When I
>tried again, I got the SQL cursor forever until I ended the program.
>Something is very wrong....
>
> Paul
I'm going to try the update packs #2 and #3 from Torry:
http://www.torry.net/pages.php?id=63
Here is a list of known issues and fixes:
http://info.borland.com/devsupport/delphi/fixes/delphi4/
Hopefully these will fix my problems. Perhaps I should also reinstall or
repair Delphi from my original disk first. And hopefully these are genuine
fixes and not something malicious. If anyone knows of other patches or if
the above are OK then please let me know.
Thanks!
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
11/2/2009 6:30:54 PM
|
|
"Paul E. Schoen" <paul@peschoen.com> wrote in message
news:pweHm.3882$Mg.1509@newsfe01.iad...
>I have just made a Delphi project to try and understand how to create and
>use the database controls and objects. I was (finally) able to create a
>dbTest.DBF file and insert one record of data. But I ran into problems when
>the file existed and I tried to open it. Here is my code:
>
> procedure TForm1.btCreateClick(Sender: TObject);
> var DBIresult: Word;
> begin
> if DataSource1 = nil then
> DataSource1 := TDataSource.Create(self);
> if Table1 = nil then
> Table1 := TTable.Create(self);
> if FileExists('dbTest.dbf') then begin
> if not Table1.CheckOpen(DBIresult) then //This gives me
> a BDE exception
No surprise here. You create a tTable component but you have yet to assign
it a Session, Database, or Tablename. It's no wonder that you cannot open
the table.
If you have created a physical table why not keep the programming simple and
drop a tTable component onto a form. Set the required properties
appropriately and away you go for testing. For more versitile work, check
out the BeforeOpen event.
|
|
0
|
|
|
|
Reply
|
BRoberts
|
11/3/2009 1:00:48 AM
|
|
"BRoberts" <berdontemail@caneris.ca> wrote in message
news:88807$4aef80d5$45c49ff1$24925@TEKSAVVY.COM-Free...
> "Paul E. Schoen" <paul@peschoen.com> wrote in message
> news:pweHm.3882$Mg.1509@newsfe01.iad...
>>I have just made a Delphi project to try and understand how to create and
>>use the database controls and objects. I was (finally) able to create a
>>dbTest.DBF file and insert one record of data. But I ran into problems
>>when the file existed and I tried to open it. Here is my code:
>>
>> procedure TForm1.btCreateClick(Sender: TObject);
>> var DBIresult: Word;
>> begin
>> if DataSource1 = nil then
>> DataSource1 := TDataSource.Create(self);
>> if Table1 = nil then
>> Table1 := TTable.Create(self);
>> if FileExists('dbTest.dbf') then begin
>> if not Table1.CheckOpen(DBIresult) then //This gives
>> me a BDE exception
>
> No surprise here. You create a tTable component but you have yet to
> assign it a Session, Database, or Tablename. It's no wonder that you
> cannot open the table.
>
> If you have created a physical table why not keep the programming simple
> and drop a tTable component onto a form. Set the required properties
> appropriately and away you go for testing. For more versitile work, check
> out the BeforeOpen event.
I tried dropping a TTable component on the form and it still gave errors.
And I had better luck previously (I think) by creating and setting up
various database components dynamically at runtime. I've had nothing but
problems, and now I think it must be because of a broken portion of the
Delphi tool itself, or the BDE.
I am also confused about such things as the TDatabase.name and
TDatabase.DatabaseName properties. And TTable.Name and TTable.TableName. It
seems like the TableName is the filename that I am creating or wish to
open.
And apparently when I reset the application after it hung up, the session
remained active such that I could not set properties in the object
inspector. So maybe there are threads running in the background even when I
terminate Delphi, and I may have to reboot each time until I get it right.
I probably had it right several times but the previous errors caused errors
that would not have occurred if there had been no errors to begin with.
Maybe that's the whole problem.
Thanks for the input, but I still don't know just what to do.
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
11/3/2009 6:07:50 AM
|
|
"Paul E. Schoen" wrote:
>
> Thanks for the input, but I still don't know just what to do.
>
http://101.lv/learn/delphi/ch16.htm
http://portal.aauj.edu/portal_resources/downloads/database/delphi_database_application_developers_book.pdf
http://delphi.about.com/od/database/a/databasecourse.htm
http://en.allexperts.com/q/Delphi-1595/become-professional-delphi-database.htm
http://www.ayton.id.au/gary/it/Delphi/D_db1.htm
http://www.pdf-search-engine.com/delphi-database-programming-pdf.html
http://www.freeprogrammingresources.com/delphi.html
Also, slightly adjust the thread's topic. Acting with databases, reports
etc., and turning them to a usable GUI-application never tend to be too
simple. Learning curve is not only a urban legend, it exists.
-AP
|
|
0
|
|
|
|
Reply
|
AP
|
11/3/2009 9:16:03 AM
|
|
"AP" <ap.newsonly@nomails.please.com> wrote in message
news:4AEFF4D3.D33BAD61@nomails.please.com...
> "Paul E. Schoen" wrote:
>>
>> Thanks for the input, but I still don't know just what to do.
>>
> http://101.lv/learn/delphi/ch16.htm
> http://portal.aauj.edu/portal_resources/downloads/database/delphi_database_application_developers_book.pdf
> http://delphi.about.com/od/database/a/databasecourse.htm
> http://en.allexperts.com/q/Delphi-1595/become-professional-delphi-database.htm
> http://www.ayton.id.au/gary/it/Delphi/D_db1.htm
> http://www.pdf-search-engine.com/delphi-database-programming-pdf.html
> http://www.freeprogrammingresources.com/delphi.html
>
> Also, slightly adjust the thread's topic. Acting with databases, reports
> etc., and turning them to a usable GUI-application never tend to be too
> simple. Learning curve is not only a urban legend, it exists.
I realize that database programming is not simple, but I have done it with
dBase III+ (using Clipper) and also with MS Access (using VBA). I admit
that there are many advanced concepts that I have not mastered or even have
usable competency, but I should be able to create, open, edit, and save a
simple table.
I tried the Chapter 16 of the first link and I found that I could not
select the DBDEMOS alias. When I type it in I get an error. I located the
demo database files in C:\Program Files\Common Files\Borland Shared\Data,
but there is no file or folder called DBDEMOS. The Data folder has
Animals.dbf and Clients.dbf. I was able to open Animals.dbf using the
Database Desktop but I was unable to find them or any other DBF files with
the Database Explorer even when I copied them into the working project
directory. When I selected Text Files it found files with the .TXT
extension.
I was able to find them and examine the fields when I closed and restarted
Delphi, although it gave a warning about a Production Index Missing and I
could open them only as Read Only. Then I copied the .MDX files over and I
was able to use the Explorer.
I dropped a TTable, TDatabase, and TDataSource onto the form, and using the
Object Inspector I was able to select one of the DBF files As the
Table1.TableName. But it did not read the FieldDefs until I set the
Table1.Active True. I dropped a TDBGrid and set the DataSource to
DataSource1 and it showed the fields in the grid. I changed the
Table1.TableName to another existing DBF file and when I made it active
again it used the new table fields and records. And I added a TDBNavigator
set the source, and ran the App. I was able to edit the field data and add
a record. I also added the Table1.IndexName so that the added record would
show in the Object inspector.
So now this appears to work. I did install the updates #2 and #3, and
perhaps that helped.
OK. Thanks for your patience. I think I can take it from here.
I'll have to see if I can also create a new database at runtime rather than
use one that already exists, although I will probably distribute my
database files with my application. At this point I am OK with using dBase,
as I do not appear to be able to use others in the dropdown list because I
can't get past the login prompt.
Speaking of Login Prompt, I could not get the application to run without
displaying the login prompt dialog, even though I set the
DataBase1.LoginPrompt False. But I removed the DatabaseName from both the
Table1 and Database1 components and now the app no longer prompts for
login. IOn fact I was able to delete the TDatabase component and everything
still seems to work. So here are the properties I used for the SimpleDB
project (there is no code yet):
DataSource1.DataSet := DataSet1;
Table1.Active := True;
Table1.DatabaseName := '';
Table1.DefaultIndex := True;
Table1.IndexName := INDEX_65BC; //Selected from list
Table1.TableName := 'BOMdata1'; //Selected from list of DBF files
Table1.TableType := ttDBase;
This may be stupid simple and obvious but at least I now have a starting
point from which I can build. I'd like to use MS Access but that's not
going to happen unless I get a later version of Delphi or do some of the
tricks I've seen that might expose the elements of MSACC8.OLB or MSACC.OLB.
But that is hardly trivial. I can live with a DBF database and I can import
and export the format using MS Access 97.
Thanks,
Paul
|
|
0
|
|
|
|
Reply
|
Paul
|
11/3/2009 8:03:33 PM
|
|
"Paul E. Schoen" wrote:
>
>
> I tried the Chapter 16 of the first link and I found that I could not
> select the DBDEMOS alias.
Many of you earlier error messages and the overall diffculties even with
basic things just sound so strange. It should not be that difficult to
do start with the beginner DB demos there are descibed in manuals.
Now we at least know so much that you have some written example or
manual to follow.
The problem could be with your oldish Delphi version or maybe with the
operating system (Vista???) and some overly protected Program Files
folders.
But I have even older version, D3, installed on my machine. And all the
demos that came with this Delphi Professional version work just fine on
XP.
Aliases. You can manage existing BDE Aliases and add new ones with
BdeAdmin.exe that you shoud be able to locate.
> When I type it in I get an error. I located the
> demo database files in C:\Program Files\Common Files\Borland Shared\Data,
> but there is no file or folder called DBDEMOS.
DBDEMOS is not a folder, it's an Alias for BDE, and you can view them
with the tool mentioned earlier.
> OK. Thanks for your patience. I think I can take it from here.
Don't worry, we are only trying to save your time and maybe ours at the
same time:) Of course my approach may be killing this kind of live and
lenghy thread. With lot's of code snippets and other programming related
conversation.
But on the other hand, if you want quickly to get something to work
also, and do not want to paint youself in to a corner or dead end on a
slightly longer period.
> I'll have to see if I can also create a new database at runtime rather than
> use one that already exists, although I will probably distribute my
> database files with my application. At this point I am OK with using dBase,
> as I do not appear to be able to use others in the dropdown list because I
> can't get past the login prompt.
Use Database Desktop to create all your tables, then just distribute
those tables with your installation. There's rarely need to start
creating tables from total nil within your application code.
> Speaking of Login Prompt, I could not get the application to run without
> displaying the login prompt dialog, even though I set the
> DataBase1.LoginPrompt False.
I wonder if it is really worth to learn to use and deal with BDE, and
aliases ans everything such any more. I understood that you want to have
an easy applcaton, with easy installation. BDE always needs to be
installed to the target machines, and there are constant problems with
BDE NetDir errors etc.
If you have chosen that dBase will be your data format and D4 is the
version where you will stay, then mayne Halcyon with $100 would be a
suitable BDE replacement http://www.griffinsolutions.com/halcyon6.php
On the other hand, if you can get D5 or better, then your can install
free NexusDB version. that is available also to D5 and upwards.
http://www.torry.net/quicksearchd.php?String=nexus&Title=Yes
http://www.nexusdb.com/support/index.php?q=FreeEmbedded
These do NOT use dBase file format, but that should not be a problem. I
abandoned all dBase files already over decade ago.
> This may be stupid simple and obvious but at least I now have a starting
> point from which I can build. I'd like to use MS Access but that's not
> going to happen unless I get a later version of Delphi or do some of the
> tricks I've seen that might expose the elements of MSACC8.OLB or MSACC.OLB.
> But that is hardly trivial. I can live with a DBF database and I can import
> and export the format using MS Access 97.
You should be able to install full DAO data access to your D4 version
for free, and that way use also Access databases.
http://www.torry.net/pages.php?id=569#5157
Yet those DAO things are mostly grey area to me, and I do not know if
all those work or not.
It may well be that you can build your DB app totally without upgrading
anything or buying anything. There is a wide selecton of free code and
alternatives, and you may be lucky.
But If you do have something like $100 to spend, it also may be that
spending now that money wisely to right upgrades may save you from a lot
of troubles and questions in the future.
-AP
|
|
0
|
|
|
|
Reply
|
AP
|
11/4/2009 11:26:59 AM
|
|
|
20 Replies
337 Views
(page loaded in 0.716 seconds)
Similiar Articles: Adding two columns to recordset in code for report to display ...Adding simple database, excel export, and reports with D4 Pro ... I looked over some old code that does essentially ... DataSource := DataSource1; DBGrid1.Columns.Add ... Max. size of CLOB in ADO.NET - comp.databases.btrieveAdding simple database, excel export, and reports with D4 Pro ... "Maarten Wiltink" <maarten@kittensandcats.net> wrote in ... The curve data that I am working on now has ... Proc Import Excel Range - comp.soft-sys.sasAdding simple database, excel export, and reports with D4 Pro ..... difficult to do without writing a special procedure ... as well as operating a skeet shooting range ... Report Lite - comp.text.pdfAdding simple database, excel export, and reports with D4 Pro ... Report Lite - comp.text.pdf Adding simple database, excel export, and reports with D4 Pro ... software ... Developing Access 97 on Windows 7 x64 freezing up - comp.databases ...Simple Clipping Broken -- Where did I get this code? - comp ... Developing Access 97 ... Developing Access 97 on Windows 7 x64 freezing up DataBase Access 97 seems to run ok on ... how to set background image for jasper report - comp.lang.java ...Adding simple database, excel export, and reports with D4 Pro ... Make simple reports based on this data and information ... string} LenStr := ReadStreamInt(Stream); {set ... Compare strings as integers - comp.unix.solarisAdding simple database, excel export, and reports with D4 Pro ... Compare strings as integers - comp.unix.solaris Adding simple database, excel export, and reports with D4 ... web database submit button - click once - help - comp.databases ...Adding simple database, excel export, and reports with D4 Pro ... In the Help for D4 there is information on Quick ... quite unnecessary; it's all quite simple > once ... How to manage security in a multi file solution in fm8 - comp ...Adding simple database, excel export, and reports with D4 Pro ... Export the data and results of comparison to a file ... By 2005 I had a hardware and software solution ... CreateObject and events - comp.lang.xharbourHi! I would like to call an external library that provides the use of events. Does someone have an example of how to use those events with xHar... PDF Export Takes Forever - comp.graphics.apps.pagemakerAdding simple database, excel export, and reports with D4 Pro ... When I >tried again, I got the SQL cursor forever until I ended the program. ... Exporting Reports ... system analysis/audit report in HTML format. - comp.unix.solaris ...... like nickel (HP-UX) available for Solaris 9 t ge > system analysis/audit report in ... ODS Html Style Graph with SGPLOT in Excel Sheet - comp.soft-sys ... system analysis ... Reading a large mixed CSV file of unknown types and size - comp ...Adding simple database, excel export, and reports with D4 Pro ..... in C, where they can be more freely mixed and ... and maybe add an export utility for a CSV file that ... Establish When Multiple Fields Are True/False -1/0 Yes/No From A ...Has anyone found a simple way to check that all ... this can be done by using a Union Query and adding ... Design Table? - comp.cad.solidworks ... Answer: Excel Export ... Adding a second CPU to a DS20E - comp.os.vmsAdding simple database, excel export, and reports with D4 Pro ... > > Seek takes a number as it second parameter but that's a ... tried again it went into an endless loop ... Adding simple database, excel export, and reports with D4 Pro ...I would like to add some simple database functionality to a D4 application I have been developing for quite a while. I tried previously to use some of How to Export QuickBooks Reports to Excel | eHow.com... reports and get them the attention they deserve, export your QuickBooks reports to Excel. By following a few simple guidelines, you can add ... Database to an Excel ... 7/28/2012 11:38:54 AM
|