Final conversion 16 bit to FWH
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: Final conversion 16 bit to FWH
Marc,
OK, I see, you were just trying to update the DBF/DBT file structure to the current format.
I will be interested to hear how your conversion from TSBrowse to XBrowse goes.
James
OK, I see, you were just trying to update the DBF/DBT file structure to the current format.
I will be interested to hear how your conversion from TSBrowse to XBrowse goes.
James
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
- Marc Venken
- Posts: 1485
- Joined: Tue Jun 14, 2016 7:51 am
- Location: Belgium
Re: Final conversion 16 bit to FWH
James,
I implemented my first little OOP (for now with standard FWH
)
In this code is see a 'James Bott' OOP
The code for changing the oDbfklant:tel_nr and oDbfklant:fax_nr could be changed into a new method from the save() as you told early.
So when saving, the update is performent. Not for now, but this will happen at the end of the conversion, and when I build new functions.
Just wanted to let you know, since this stuff I have learned from you. Thanks BTW.
I implemented my first little OOP (for now with standard FWH

Code: Select all | Expand
DATABASE oDbfklant
REDEFINE GET oDbfklant:Naam_1 ID 110 OF oDlg UPDATE on change oBtn1:enable()
REDEFINE GET oDbfklant:Naam_2 ID 120 OF oDlg UPDATE on change oBtn1:enable()
REDEFINE GET oDbfklant:Straat ID 130 OF oDlg UPDATE on change oBtn1:enable()
REDEFINE GET oDbfklant:Postcode ID 140 OF oDlg UPDATE on change oBtn1:enable()
REDEFINE GET oDbfklant:Gemeente ID 150 OF oDlg UPDATE on change oBtn1:enable()
REDEFINE GET oDbfklant:Tel_nr ID 160 OF oDlg UPDATE on change oBtn1:enable()
REDEFINE GET oDbfklant:Fax_nr ID 170 OF oDlg UPDATE on change oBtn1:enable()
///.....
//and for saving
function endklant(oDbfklant,oDlg)
if oDbfklant:modified()
if msgyesno("Gewijzigde gegevens bewaren")
oDbfklant:save()
If !dial->(dbseek(oDbfklant:tel_nr))
dial->(dbappend())
dial->tel = TrimTelFax(oDbfklant:tel_nr)
dial->firma = oDbfklant:naam_1
dial->code = oDbfklant:klant_nr
dial->type = "K"
dial->toestel = "T"
endif
If !dial->(dbseek(oDbfklant:fax_nr))
dial->(dbappend())
dial->tel = TrimTelFax(oDbfklant:fax_nr)
dial->firma = oDbfklant:naam_1
dial->code = oDbfklant:klant_nr
dial->type = "K"
dial->toestel = "F"
endif
endif
endif
return(.t.)
In this code is see a 'James Bott' OOP
The code for changing the oDbfklant:tel_nr and oDbfklant:fax_nr could be changed into a new method from the save() as you told early.
So when saving, the update is performent. Not for now, but this will happen at the end of the conversion, and when I build new functions.
Just wanted to let you know, since this stuff I have learned from you. Thanks BTW.
Marc Venken
Using: FWH 23.08 with Harbour
Using: FWH 23.08 with Harbour
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: Final conversion 16 bit to FWH
Well, kudos, Marc. I'm glad to see you starting to try OOP.
I like to make the object names as much like real-world names as possible. And I try to make table objects plural so I can use a singular object of the same type later. For instance oCustomers and oCustomer. So, I would suggest for you to use oKlants now so you can use oKlant later. It seems that if you are using oKlants it is obvious that it is a DBF (or table).
And rather than opening the table using conventional syntax, I would create a subclass and open the database and indexes in that as I have shown before in other messages. Then it takes only one line of code to create the table object and if you need to change or add indexes you do that in the class for that object. It is a good rule to write each piece of code only once--not only for less work, but you only have to change it in one place.
oKlants := TKlants():new()
I recently calculated (for some very old code) that I could eliminate over 2000 lines of code that were used for opening files and their indexes, just by converting to database classes.
I am so glad to see you recognize that your function should be a method. And that you see how you can convert a little at a time instead of all or nothing.
Keep at it.
James
I like to make the object names as much like real-world names as possible. And I try to make table objects plural so I can use a singular object of the same type later. For instance oCustomers and oCustomer. So, I would suggest for you to use oKlants now so you can use oKlant later. It seems that if you are using oKlants it is obvious that it is a DBF (or table).
And rather than opening the table using conventional syntax, I would create a subclass and open the database and indexes in that as I have shown before in other messages. Then it takes only one line of code to create the table object and if you need to change or add indexes you do that in the class for that object. It is a good rule to write each piece of code only once--not only for less work, but you only have to change it in one place.
oKlants := TKlants():new()
I recently calculated (for some very old code) that I could eliminate over 2000 lines of code that were used for opening files and their indexes, just by converting to database classes.
I am so glad to see you recognize that your function should be a method. And that you see how you can convert a little at a time instead of all or nothing.
Keep at it.
James
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: Final conversion 16 bit to FWH
Marc,
I'm not sure what you meant, but you should make a new Save() method in the TKlants class and add that code to the new save method.
Now you just do:
oKlants:save()
I suggest opening the Dial database INSIDE the TKlants class. And closing it too, of course. This encapsulates the database--you don't have to rely on the database being open before saving the oKlants record. Whew, you might have to read that twice--it is a new concept; a database class inside a database class.
James
The code for changing the oDbfklant:tel_nr and oDbfklant:fax_nr could be changed into a new method from the save()
I'm not sure what you meant, but you should make a new Save() method in the TKlants class and add that code to the new save method.
Code: Select all | Expand
Class TKants from TDatabase
Method New()
Method Save()
Endclass
Method New()
...
Return Self
Method Save() Class TKants
::super:save() // call the parent save method
// add code to save phone numbers
// add code to save fax numbers
Return nil
Now you just do:
oKlants:save()
I suggest opening the Dial database INSIDE the TKlants class. And closing it too, of course. This encapsulates the database--you don't have to rely on the database being open before saving the oKlants record. Whew, you might have to read that twice--it is a new concept; a database class inside a database class.
James
Last edited by James Bott on Sat Jul 08, 2017 6:12 am, edited 1 time in total.
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: Final conversion 16 bit to FWH
Marc,
While looking at your EndKlant() function I noticed that it contains user interface code:
User interface code should not be inside any buisness object, so this should be moved to outside the function when it is changed to a method of the customer class. Here are a couple of reasons why.
1) Granularity--you want to strive for small pieces of code that have a single purpose.
2) Automation-- For instance, if you wanted to update all the records with new data, you need to be able to call the Save() method once per record. Thus you cannot have user interface code popping up for each record.
Business objects and human interface objects should be totally separate. You can, of course, have an edit-business-object class, for instance EditCustomer. You then can then pass a customer object to that class for editing.
Simple.
James
While looking at your EndKlant() function I noticed that it contains user interface code:
Code: Select all | Expand
if msgyesno("Gewijzigde gegevens bewaren")
...
endif
User interface code should not be inside any buisness object, so this should be moved to outside the function when it is changed to a method of the customer class. Here are a couple of reasons why.
1) Granularity--you want to strive for small pieces of code that have a single purpose.
2) Automation-- For instance, if you wanted to update all the records with new data, you need to be able to call the Save() method once per record. Thus you cannot have user interface code popping up for each record.
Business objects and human interface objects should be totally separate. You can, of course, have an edit-business-object class, for instance EditCustomer. You then can then pass a customer object to that class for editing.
Code: Select all | Expand
oCustomer:=TCustomer():New(cCustNo)
oEditCustomer:=TEditCustomer():New()
oEditCustomer:edit(oCustomer)
Simple.
James
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
- Marc Venken
- Posts: 1485
- Joined: Tue Jun 14, 2016 7:51 am
- Location: Belgium
Re: Final conversion 16 bit to FWH
Thanks James, I will take this info in my further devellopments.
You know that I'm transferrings into Xbrowse, so It is also possible to give the save() functions from Xbrowse a extra method ?
Let say 'as example' that I also want to save a extra phone number and Fax nummer into a second database, when I add a record into a Xbrowse,
you would probably add a method like below ?
This can be done for all classes.
I remember that you normaly put 1 class in a prg file. Is this also for addind smaller methods like above ?
You know that I'm transferrings into Xbrowse, so It is also possible to give the save() functions from Xbrowse a extra method ?
Let say 'as example' that I also want to save a extra phone number and Fax nummer into a second database, when I add a record into a Xbrowse,
you would probably add a method like below ?
Code: Select all | Expand
Class MyBrowse from Xbrowse
Method New()
Method XB_Save()
Endclass
Method xB_save() Class MyBrowse
::super:save() // call the parent save method from xbrowse and let Xbrowse do all it normaly does.
// add code to save phone numbers
// add code to save fax numbers
Return nil
This can be done for all classes.
I remember that you normaly put 1 class in a prg file. Is this also for addind smaller methods like above ?
Marc Venken
Using: FWH 23.08 with Harbour
Using: FWH 23.08 with Harbour
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: Final conversion 16 bit to FWH
Marc,
Sorry, no that is not how you do it.
Since you are using a database object, you don't have to do anything!
To prove it, just define a test database class with a new() method and a test save() method like this:
Then create and run a test browse.
Then run the test program and when the data is saved the msgInfo() will popup.
So if you add the updating of the other database to the oKlants:Save() method it will get updated also. XBrowse already calls oDBF:save() so your object's Save() method gets called.
See is it simpler than you thought.
James
Sorry, no that is not how you do it.
Since you are using a database object, you don't have to do anything!
To prove it, just define a test database class with a new() method and a test save() method like this:
Code: Select all | Expand
Method New() Class TKlants
::super():New(,"klant") // or whatever the filename is
::use()
::load()
Return self
Method Save() Class TKlants
msgInfo("Save method called")
Return nil
Then create and run a test browse.
Code: Select all | Expand
oKlants := TKlants():New()
@ 0, 0 XBROWSE oBrw OF oWnd OBJECT oKlants
...
Then run the test program and when the data is saved the msgInfo() will popup.
So if you add the updating of the other database to the oKlants:Save() method it will get updated also. XBrowse already calls oDBF:save() so your object's Save() method gets called.
See is it simpler than you thought.
James
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
- Marc Venken
- Posts: 1485
- Joined: Tue Jun 14, 2016 7:51 am
- Location: Belgium
Re: Final conversion 16 bit to FWH
James,
A other issue I have,
In this case, I read emails from the testpop3.prg sample (source class = Tpop3.prg)
Insite the class, there is in the method NEW
::lDelMsgs := .t.
::lHeaderOnly:=.F.
I want to change this in the testpop3.prg , so I thought changing simply
oInMail:lHeaderOnly:=.T.
oInMail:lDelMsgs := .F.
would work, but it seems not ? Afther reading the mail (that works) the mails still is erased on the server, and as far as I can tell,
putting the lDelMsgs := .F. would prevent this from happening
A other issue I have,
In this case, I read emails from the testpop3.prg sample (source class = Tpop3.prg)
Insite the class, there is in the method NEW
::lDelMsgs := .t.
::lHeaderOnly:=.F.
I want to change this in the testpop3.prg , so I thought changing simply
oInMail:lHeaderOnly:=.T.
oInMail:lDelMsgs := .F.
would work, but it seems not ? Afther reading the mail (that works) the mails still is erased on the server, and as far as I can tell,
putting the lDelMsgs := .F. would prevent this from happening
Code: Select all | Expand
function GetMail()
local oInMail
oWnd:SetMsg( "Geting Internet email..." )
oInMail = TPop3():New( "MycIp",110,"MyAccount", "MyPaswoord" ) // mail server IP
oInMail:lHeaderOnly:=.T.
oInMail:lDelMsgs := .F.
oInMail:bConnecting = { || oWnd:SetMsg( "Connecting to 194.224.203.2..." ) }
oInMail:bConnected = { || oWnd:SetMsg( "Connected" ) }
oInMail:bDone = { || ReadEmails( oInMail ) }
oInMail:GetMail()
return nil
//----------------------------------------------------------------------------//
function ReadEmails( oInMail )
local n
MsgInfo( "Total emails: " + Str( Len( oInMail:aMsgs ) ) )
for n = 1 to Len( oInMail:aMsgs )
MsgInfo( oInMail:aMsgs[ n ] )
next
return nil
//----------------------------------------------------------------------------//
Marc Venken
Using: FWH 23.08 with Harbour
Using: FWH 23.08 with Harbour
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: Final conversion 16 bit to FWH
Marc,
I looked at the TPop3.prg and I don't see any problems with it.
I think the issue is that when you execute the getMail() routine it issues a "quit" when it is done, which is probably disconnecting from the server. Then your getEmails() function is trying to read emails from a disconnected server.
Instead of using your getEmails() function, try to read them with the GetMail() function again, after the first time, to see if they are still there.
-----
Did you try your browse with a customer class yet?
James
I looked at the TPop3.prg and I don't see any problems with it.
I think the issue is that when you execute the getMail() routine it issues a "quit" when it is done, which is probably disconnecting from the server. Then your getEmails() function is trying to read emails from a disconnected server.
Instead of using your getEmails() function, try to read them with the GetMail() function again, after the first time, to see if they are still there.
-----
Did you try your browse with a customer class yet?
James
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: Final conversion 16 bit to FWH
Marc,
I had a few mintues to kill, so I wrote up a sample customer class for you.
If you are using MS Edge, don't copy the source from it--use a different browser. Edge puts in invisible characters which will give you syntax errors that will drive you crazy.
The code will need a few additions to be workable (see the comments).
Regards,
James
I had a few mintues to kill, so I wrote up a sample customer class for you.
If you are using MS Edge, don't copy the source from it--use a different browser. Edge puts in invisible characters which will give you syntax errors that will drive you crazy.
The code will need a few additions to be workable (see the comments).
Regards,
James
Code: Select all | Expand
/*
Purpose : Customer class
Program : TKlants.prg
Author : James Bott
Date : 07/20/2017 10:09:18 AM
Company : Intellitech
Copyright:
Language : Fivewin/xHarbour
Updated :
Notes : For Marc Venken
*/
#include "fivewin.ch"
Function Main()
Local oKlants
Field klant_nr, naam_1
REQUEST DBFCDX
rddsetdefault( "DBFCDX" )
SET(_SET_AUTOPEN, .T. )
SET EXCLUSIVE OFF
// Test only
use Klant
index on klant_nr tag "klant_nr" to klant
index on naam_1 tag "naam_1" to klant
use
// End test
oKlants:= TKlants():New()
msgInfo( oKlants:naam_1, "Naam_1")
oKlants:end()
Return nil
//---------------------------------------------------------------------------//
// Customers database class
// Question, do the phone and fax numbers need to be loaded from the dial database?
// If so then a Load() method will also be needed.
Class TKlants from TDatabase
Data oDial
Method New()
Method Save()
Method TrimTelFax()
Method End()
endclass
Method New() Class TKlants
::super:new(,"klant")
::use()
::setOrder(1) // primary key index
::oDial:= TDial():New()
//::oDail:setOrder( ? ) // phone number index
Return Self
// Function endKlant made into TKlants:save() method
Method Save() Class TKlants
::super:save()
If ! ::oDial:seek(::tel_nr)
::oDial:append()
::oDial:tel = ::TrimTelFax(::tel_nr)
::oDial:firma = ::naam_1
::oDial:code = ::klant_nr
::oDial:type = "K"
::oDial:toestel = "T"
::oDial:save()
endif
If ! ::oDial:seek(::fax_nr)
::oDial:append()
::oDial:tel := ::TrimTelFax(::fax_nr)
::oDial:firma = ::naam_1
::oDial:code = ::klant_nr
::oDial:type = "K"
::oDial:toestel = "F"
::oDial:save()
endif
Return nil
Method End() Class TKlants
::oDial:close()
::super:close() // Because TDatabase doesn't have an End method
Return nil
Method TrimTelFax(cNumber) Class TKlants
// cNumber := ?
return cNumber
//---------------------------------------------------------------------------//
Class TDial from TDatabase
Method New()
Endclass
Method New() Class TDial
::super():New(,"dial")
::use()
//::setOrder( ? ) // the primary key index
Return self
//---------------------------------------------------------------------------//
// EOF
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
- Marc Venken
- Posts: 1485
- Joined: Tue Jun 14, 2016 7:51 am
- Location: Belgium
Re: Final conversion 16 bit to FWH
Thanks,
Will look into this in a fex days.
Marc
Will look into this in a fex days.
Marc
Marc Venken
Using: FWH 23.08 with Harbour
Using: FWH 23.08 with Harbour
- James Bott
- Posts: 4840
- Joined: Fri Nov 18, 2005 4:52 pm
- Location: San Diego, California, USA
- Contact:
Re: Final conversion 16 bit to FWH
Marc,
I forgot to mention a few things.
Notice that we use total encapsulation in this class. You don't have to open either the customer database or the dial database. Nor do you have to remember which indexes to set. And there are no work areas or aliases to worry about. Finally, you don't have to remember to save the phone numbers to a different database. All you have to do is:
oKlants := TKlants():New()
Then everything is all setup and ready to go.
If you need to make any modifications to the behavior of this class, there is only one place that needs to be modified.
This provides very easy to use and update code. And very stable code.
Regards,
James
I forgot to mention a few things.
Notice that we use total encapsulation in this class. You don't have to open either the customer database or the dial database. Nor do you have to remember which indexes to set. And there are no work areas or aliases to worry about. Finally, you don't have to remember to save the phone numbers to a different database. All you have to do is:
oKlants := TKlants():New()
Then everything is all setup and ready to go.
If you need to make any modifications to the behavior of this class, there is only one place that needs to be modified.
This provides very easy to use and update code. And very stable code.
Regards,
James
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10