Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Search record containing 3 to 4 phone numbers 3

Status
Not open for further replies.

Joy Tan

IS-IT--Management
Nov 3, 2020
5
CA
Hi All,

Does anyone have a suggestion of how to search a table where each record has 3-4 phone numbers?
for example:
firstname, lastname, custno, phone1, phone2, phone3, phone4 etc.

I need to search with phone number wildcard search: like phone numbers that start with 895-24*, or 267-1* etc. etc.

Any suggestions on how to build the index and the search routine?

Thank you so much.
Joy
 
If you are only set on numbers that START with a sequence you could assemble indices on the four phone numbers
and then just seek the bit you do know:

This establishes the indexes (only need once)

Code:
select myTable
index on phone1 tag phone1
index on phone2 tag phone2
index on phone3 tag phone3
index on phone4 tag phone4

Then to find 895-24*

Code:
FINDPHONE("895-24*")

FUNCTION FINDPHONE(m.LPPHONONO)
	LOCAL m.LFLAG
	m.LFLAG = .T.
	** lose the *
	m.LPPHONENO = ALLTRIM(STRTRAN(m.LPPHONENO,"*",""))
	SELECT MYTABLE
	SET ORDER TO PHONE1
	SEEK (m.LPPHONENO)
	IF !FOUND()
		SET ORDER TO PHONE2
		SEEK (m.LPPHONENO)
		IF !FOUND()
			SET ORDER TO PHONE2
			SEEK (m.LPPHONENO)
			IF !FOUND()
				SET ORDER TO PHONE4
				SEEK (m.LPPHONENO)
			ENDIF
		ENDIF
	ENDIF
	IF !FOUND
		m.LCFLAG = .F.
	ENDIF
	RETURN(m.LCFLAG)
ENDFUNC

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0
 
You can do this in a single SELECT statement:

Code:
* Assume lcTarget contains the searched-for string, using
* the % character as a wildcard; e.g.  895-24% or 267-1%.

SELECT * FROM MyTable WHERE ;
  Phone1 LIKE lcTarget OR ;
  Phone2 LIKE lcTarget OR ;
  Phone3 LIKE lcTarget OR ;
  Phone4 LIKE lcTarget INTO CURSOR csrResults

* The cursor csrResults will now contain all the records containing
* the searched for number.

This assumes that the number always starts with the target string. In that case, the search will be very much faster if you first create the indexes, as shown by Griff, above.

If the target string can appear anywhere within the number, then place another percent sign at the front of the string (e.g. %5-24%). But in that case, the indexes won't help, and the search won't be optimised.

I'm assuming here that you have exactly four phone number fields (some of which might be empty).

Having said all that, I would question the design of your table. Rather than multiple phone number fields, it might be better to have a separate phone number table with a pointer from it to the parent record. But let's leave that discussion for later.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Well, it's a case for moving those 4 numbers into a different table, i.e. normalize data.

But that doesn't change the task to make a number searchable with a pattern, you have to do the same search in 4 columns instead of one column in 4 times as many records.

There's no index that optimizes a search pattern like 555*37, for example, only "starts with" is optimizable. You seem only to need start with optimization so I second Griff and would not go into any more complex indexing options.

The only way to enable searching instring is cutting the numbers into all substrings and indexing on that extra data and that would still only allow to search for patterns like %123% and not %12%3% or %1?3%, so even strategies for more complex indexing have much overhead for a low enhancement and won't enable searching for any patterns you can use with LIKE.

How many billion numbers do you have? If your data is about 1000 phone numbers there's really no big need for optimization and LIKE expressions are very flexible to look for a specific number, say starting with 555, having a 7 somewhere and ending with 1? 555%7%1.

You can always optimize single searches by creating an index for them, but that won't improve that first search, you're then better off with caching the result. So overall you could think of cache strategies, especially if a user would like to search within a search result.

Chriss
 
myself said:
...you have to do the same search in 4 columns instead of one column in 4 times as many records.

Well, actually not, unless you have exactly 4 phone numbers in every record. In normalized data you only have as many rows as you have actual phone numbers, so you won't search empty fields.

Which means data normalization here actually also saves search time. Even if you prefix every search condition with phoneX<>'' AND numbersearchcondition you're not getting as fast as only searching in actual phone number data.

Chriss
 
Hi Joy,

...

or (depending on the number of records in your table) you may want to consider to store the phone numbers in memo field and search with the AT() function. Beware though that this function returns ALL the filtered records whether they start with or contain the searched string - similar to the SQL ... WHERE cPhone1 LIKE "%1234%" or the Foxpro function ... LIKE("*1234*", cPhone1) and that it cannot be optimized by Rushmore

Code:
Select * from tblTable where AT("1234", mPhonenumbers) # 0 into Cursor csrPhonenumbers

MarK

 
Hi Griff,

Your code may be tweaked a liitle bit


Code:
FINDPHONE("895-24*")

FUNCTION FINDPHONE(tcPhoneNumber)
[indent]Local llFound
	** lose the *
tcPhoneNumber = ALLTRIM(STRTRAN(tcPhoneNumber,"*",""))

SELECT MYTABLE

If IndexSeek(tcPhoneNumber, .T., "MyTable", "Phone1") OR 
[indent]IndexSeek(tcPhoneNumber, .T., "MyTable", "Phone2") OR ;
IndexSeek(tcPhoneNumber, .T., "MyTable", "Phone3") OR ;
IndexSeek(tcPhoneNumber, .T., "MyTable", "Phone4") 
[/indent]

*!* Data found

llFound = .T.

Else

*!* No data found

llFound = .F.

Endif

Return llFound[/indent]

ENDFUNC

MarK
 
Well, you surely would like records, not just a true or false. So SQL, not a function that just returns .T. or .F.

It's only that there are no good index options other than just the usual index on the phone fields and they enable starts-with searches, no matter if 1 or 4 or 200 phone number fields. The more phone number fields you have, the more indexes are necessary.

Chriss
 
If the user enters the number as (898)555-1212 or enters as 898-555-1212 or enters as 8985551212, then you have a problem with the format matching for search. I would suggest to remove all non-numeric characters and store the phone number as 8985551212. Use the form control to format the display of the phone number that is either set by you or an allowed format set by the user. You can use the following logic to remove all non-numeric characters:

REPLACE ALL tablename.phone1 WITH CHRTRAN(tablename.phone1, CHRTRAN(tablename.phone1, "0123456789",""), "") IN tablename



Greg
 
Mark,

That does improve the clarity a little...

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0
 
Hi,

... and code for a demo. The cursor has 100'000 records and each record has 5 phone numbers stored in a MEMO field. The search is done with the AT() function.

Code:
goForm = CREATEOBJECT("clsMainForm")
goForm.Visible = .T.
goForm.SHOW()

Read EVENTS

CLOSE ALL

CLEAR ALL 

RETURN 

**********		

Define CLASS clsMainForm AS FORM

		Caption = "Phonenumbers"
		AutoCenter = .T.
		BorderStyle = 3
		Width = 600
		MinWidth = 600
		MaxWidth = 600
		Height = 600
		MinHeight = 600
		MinButton = .F.
		MaxButton = .F.
		Themes = .F.

	ADD Object "lblFound" as "Label" with ;
		Visible = .T. , ;
		Autosize = .T. , ;
		Left = 12, ;
		Top = ThisForm.Height - 30, ;
		Caption = "Found", ;
		Anchor = 6
					
	ADD Object "lblPhoneNumbers" as "Label" with ;
		Visible = .T. , ;
		Autosize = .T. , ;
		Left = 12, ;
		Top = ThisForm.Height - 48, ;
		Caption = "Enter digits to search for :", ;
		Anchor = 6
					
	ADD object "txtSearch" as "TextBox" WITH ;
		Visible = .T. , ;
		Left = 192, ;
		Top = ThisForm.Height - 48, ;
		Height = 36, ;
		Width = 150, ;
		FontSize = 14, ;
		Anchor = 6
					 
	ADD object "cmdSearch" as "CommandButton" WITH ;
		Visible = .T. , ;
		Caption = "Search", ;
		Left = 360, ;
		Top = ThisForm.Height - 48, ;
		Height = 36, ;
		Anchor = 6
		
		PROCEDURE cmdSearch.Click()
			SELECT * FROM csrPhoneNumbers ;
					WHERE AT(ALLTRIM(ThisForm.txtSearch.Value), mPhoneNumber) # 0 ;
					INTO CURSOR tmpPHNumbers

			IF _Tally > 0
			
				ThisForm.lblFound.Caption = "Phonenumbers found : " + ALLTRIM(TRANSFORM(_Tally, "9,999,999"))
			
				WITH ThisForm.pgfMain
					.Page2.Enabled = .T.
					.ActivePage = 2
					.Page2.Click()

				ENDWITH 
			ELSE 
			
				ThisForm.pgfMain.Page2.grdPhoneNumbers.Visible = .F.
				
				= MESSAGEBOX("No data found!", 48, "Search Phonenumbers", 2500)
				
				WITH ThisForm.pgfMain
					.ActivePage = 1
					.Page1.Click()
					
				ENDWITH 			
			ENDIF 
		ENDPROC 

	Add OBJECT cmdExit AS COMMANDBUTTON WITH;
		Caption = "Exit", ;
		Backcolor = RGB(192,192,192), ;
		Left = ThisForm.Width - 120, ;
		Top = ThisForm.Height - 48, ;
		Height = 36, ;
		Anchor = 4 + 8

		PROCEDURE cmdExit.CLICK
			ThisForm.Release()
			CLEAR Events
			
		ENDPROC              

	ADD OBJECT pgfMain AS PageFrame WITH;
	    PAGECOUNT = 2, ;
	    LEFT = 12, ;
    	TOP = 12, ;
	    WIDTH = THISFORM.WIDTH - 24, ;
    	HEIGHT = THISFORM.HEIGHT - 78, ;
    	Anchor = 15
    
		PROCEDURE pgfMain.Init()
			LOCAL loPage as Object
				
			FOR i = 1 TO This.PageCount
				loPage = This.Pages(i)
				loPage.AddObject("grdPhoneNumbers","grdBase")
				loPage.Caption = ICASE(i = 1, "Original Data","Filtered Data" )

			ENDFOR 
			
			This.Page1.Click()
			This.Page2.Enabled = .F.
			
		ENDPROC 
		
		PROCEDURE pgfMain.Page1.Click()
			LOCAL loPage 
			
			loPage = ThisForm.pgfMain.Page1
			
			WITH loPage.grdPhoneNumbers
				.ColumnCount = -1
				.RecordSource = "csrPhoneNumbers"
				
				.Column1.Header1.Caption = "Name"
				.Column1.Width = 240
				
				WITH .Column2
		    		.Header1.Caption = "PhoneNumbers"
		    		.NewObject("edtComments","EditBox")
					.edtComments.BackColor = RGB(0, 240, 240)
					.edtComments.Visible = .T.
					.CurrentControl = "edtComments" 
					.Width = 240
					.Sparse = .F.
					
				ENDWITH 
			ENDWITH
		ENDPROC 

		PROCEDURE pgfMain.Page2.Click()
			LOCAL loPage 
			
			loPage = ThisForm.pgfMain.Page2

			WITH loPage.grdPhoneNumbers
				.Visible = .T.
				.ColumnCount = -1
				.RecordSource = "tmpPHNumbers"
				
				.Column1.Header1.Caption = "Name"
				.Column1.Width = 240
					
				WITH .Column2
		    		.Header1.Caption = "PhoneNumbers"
		    		.NewObject("edtComments","EditBox")
					.edtComments.BackColor = RGB(0, 240, 240)
					.edtComments.Visible = .T.
					.CurrentControl = "edtComments" 
					.Width = 240
					.Sparse = .F.
						
				ENDWITH 
			ENDWITH 
		ENDPROC 
		
	PROCEDURE Load()
		CREATE CURSOR csrPhoneNumbers (cName C(25), mPhoneNumber M)
		
		FOR i = 1 TO 100000
				INSERT INTO csrPhoneNumbers (cName, mPhoneNumber) VALUES ("T" + SYS(2015), "+352 - " + ALLTRIM(STR(100000000 * RAND())) + " - Home")
		ENDFOR
		
		UPDATE csrPhoneNumbers SET mPhoneNumber = mPhoneNumber + CHR(13) + "+32 - " + ALLTRIM(STR(100000000 * RAND())) + " - Office"
		UPDATE csrPhoneNumbers SET mPhoneNumber = mPhoneNumber + CHR(13) + "+49 - " + ALLTRIM(STR(100000000 * RAND())) + " - Cellphone"
		UPDATE csrPhoneNumbers SET mPhoneNumber = mPhoneNumber + CHR(13) + "+33 - " + ALLTRIM(STR(100000000 * RAND()))
		UPDATE csrPhoneNumbers SET mPhoneNumber = mPhoneNumber + CHR(13) + "+44 - " + ALLTRIM(STR(100000000 * RAND()))

		LOCATE 
		
	ENDPROC 
	
	PROCEDURE Destroy()
		This.cmdExit.Click()
		
	ENDPROC 
	
      
ENDDEFINE

*****

DEFINE CLASS grdBase AS Grid
		Top = 12
		Left = 12
		Height = 600 - 84 - (4 * 12)
		Width = 600 - (4 * 12)
		BackColor = RGB(0, 240, 240)
		RowHeight = 60
		AllowRowSizing = .T.
		HeaderHeight = 21
		AllowHeaderSizing = .F.
		DeleteMark = .F.
		ReadOnly = .T.
		Anchor = 15
		Visible = .T.

ENDDEFINE 
*****

hth

MarK
 
Greg,

I agree with your point about storing the numbers as digits only, without spaces or separators. But I think it's important for readability to include the appropriate spaces, hyphens or whatever when displaying the numbers to the user. I'm sure you agree.

It's also important to allow the user to enter the number in whatever (reasonable) format they want, and to let the program strip away the unnecessary characters. Where I live, it is customary to write a phone number as three digits for the dialling code, then a space, then three digits for the exchange, then a space, and then the actual four-digit number. But if I enter my phone number like that into most websites, it is rejected as being invalid; I have to re-enter it without the spaces. It's the same with credit card numbers, which are universally represented as four groups of four digits separated by a space, but which most websites insist on being entered as digits only.

I've even seen error messages that say, "Credit card number invalid. Please re-enter without spaces." What kind of programmer knows how to check the for presence of spaces but doesn't have the gumption to strip them out?

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I used mjcmkrsr's example and it doesn't take long to find numbers, I've changed it to 4 phone number fields again, and it does not slow it down, really.
So overall you might worry too much about the search time.

What would matter more is if data is stored locally vs on a network share, where network slows down searches. MarK's example also profits from the cursor being an in-memory table and since all of its data was just created in it, it's an in-memory search, which obviously is faster than a search on a table stored on a LAN share you haven't read in anything of to start with. Anyway, even storing the cursor to a file and then using that instead of the cursor doesn't slow it down much in my experience.

For convenience, it's easier to define quite complex match conditions with LIKE, make your search pattern input a ? for a single unknown digit and a % for any count of unknown digits. So I second Mike Lewis's query:
Code:
SELECT * FROM MyTable WHERE ;
  Phone1 LIKE lcTarget OR ;
  Phone2 LIKE lcTarget OR ;
  Phone3 LIKE lcTarget OR ;
  Phone4 LIKE lcTarget INTO CURSOR csrResults
In VFP9, it will use an index in the special condition lcTarget is a pattern with specific digits ending in %, because that is the special "starts with" condition an index can find faster. Before VFP9 a LIKE was never considered to be optimizable, MS added that. Might also have been done in VFP8, but I'm sure VFP7 didn't have that yet. If you don't think users will learn to use LIKE patterns, you can let searches be "starts with" searches, by adding '%' as suffix. So do something like lcTarget=ALLTRIM(form.txtSearch.Value)+'%'.

I second the advice to not store any +,-, brackets or other typical parts of phone numbers that are only there to make them better readable for humans or separate the prefix of a city or mobile provider. If you want to help people find prefixes, you could also store them separately. Going that route and making 4 prefix and 4 phone fields I'd recommend to think about storing the phone numbers in a separate table, while you're at that you could make that new table more generally contain any type of contact, also an email address and add a type field to distinguish between the types. That also enables searches for phone vs mail, home vs work etc., depending on how you structure it.

Overall, you can not only make a search better by indexing or special index trickery, just also structure your data and program the searching in ways that enable easier finding the actual contacts. Additional information makes it simple to shrink down the set to search in, if half of all numbers are work and half home or private, then you only need to search in half the phone numbers, simply by specifying whether you search a home or office number. So these things add to a better searchability.

Chriss
 
Just to shortly demo the LIKE optimization VFP can do:

Code:
Create Cursor Contacts (phone c(10))
Index on phone tag phone
Insert into contacts values ('123456')

clear

Sys(3054,1)
Select * from contacts where phone LIKE '123%'
Select * from contacts where phone LIKE '%234%'
Select * from contacts where phone LIKE '123'

If you execute that you get 3 query result browse windows, the first one contains the record 123456, the second will also find it, the third will have no result record.
While the queries are done VFP writes to _screen, that it uses the phone index to optimize the first query, that it can't optimize the second query as the pattern starts with % and then continues with specific digits to end in % again, that's an instring search, 234 anywhere within the number, it's not optimizable but of course VFP still finds the record

The third is a bit of a surprise, but you have to be aware that LIKE is very strict, if you don't add in a % it means it looks exactly for the phone number 123, no continuation, no prefix, so it's right in finding no result.

It can be tricky for users to learn something, even if it enables more specific searches, adding a % to all the searches, VFP is again able to optimize the first and the third one, so this means using LIKE and adding a % to the end of any search term users enter, you support the users, who are willing to learn LIKE search patterns and make use of them, even in the cases they don't get optimized the result can be the exact hit they need or the result is smaller and faster to scroll through to find the one contact they want.

And the "normal" user who just searches the start of a phone number can at least find that without needing to know he should add a % at the end.
So, consider how your users think, how important that feature is to them in the overall picture.

It all obviously gets another driving factor if this is the major feature of a reverse phone search website and you have some unique selling proposition that is all worldwide phone numbers or something like that. But I guess you then wouldn't use VFP for that.

Chriss
 
Joy Tan,

You have now had several replies to your question.

It would be really helpful if you could now let us know if any of these replies have been useful to you, and if you now have a solution. In particular, we have made several assumptions about your data, for example, re the format of the phone numbers within the fields, and whether there is a fixed or variable number of phone numbers for each item in the table. It would help to know if these assumptions are valid.

At the very least, as a matter of courtesy, you might have acknowledged our replies.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike Lewis--

I think you missed my statement, "Use the form control to format the display of the phone number that is either set by you or an allowed format set by the user." The form display control sets the format mask/input properties. This can be set appropriately by the programmer to be fixed, or it can be allowed in a configuration setup to be set by the end-user. So, yes as I said, the form should display with spaces, hyphens, or what is appropriate for readability.


Greg
 
Greg,

You are correct: I did miss the bit about using the Format setting. Apologies for that. But I don't think it did any harm to emphasise the point. (And the thing about websites that don't accept embedded spaces was really just a rant on my part.)

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Chris,

FWIW

Chriss said:
What would matter more is if data is stored locally vs on a network share, where network slows down searches.

I copied the data from the cursor to a dbf, which I stored on my SSD and NAS.

cursor/dbf on SSD : no noticeable difference
cursor/dbf on NAS : the average search time went up from 0.06 sec to 0.1 sec

BTW I work on a W10 Pro machine with 64GB RAM and a 512 GB SSD, The NAS has 6 GB RAM, 2 3TB WD Red Pro (Raid 1) and is connected to a 1 Gb network.

MarK
 
mjcmkrsr,

good info, and I wouldn't expect something else, even without indexing you can comb through data and find all relevant result. It's up to your demand, if you'd like instant results, like less than 0.01 seconds, that's actually already something no human user would really profit of. If I think of the normal use case of searching a contact to make a call, it doesn't prolong the call, even if the search takes 3 seconds.

If you provide a search service to millions of users, every millisecond will count. There are totally different database architectures for that kind of requirements, though.

I second Mike Lewis, it would be good to get feedback from you, Joy Tan, and rest this case or offer a perspective on other solutions.

You might need to do this in a developing country on older hardware, we only know what suits you once we get feedback to the solutions given so far.

To give a glimpse of what could be done: A server could have read in all phone numbers in a memory table, literally in RAM all the time, even a very dumb scanning of say 100000*10 = 1 MB roughly takes split seconds in today's RAM read bandwidth of several GB/s. This is doable but hints at it being done on one server and not at clients, not with a DBF but with a database server allowing actual memory tables. Now the bottleneck is just the network.

Chriss
 
Hi,

I tuned the code a little bit. Now the results show the name, the phone numbers in an edit box, the line number of the first occurrence of the searched string in the edit box and finally the number of occurrences of the searched string in the editbox .

Enjoy

Code:
goForm = CREATEOBJECT("clsMainForm")
goForm.Visible = .T.
goForm.SHOW()

Read EVENTS

CLOSE ALL

CLEAR ALL 

RETURN 

**********		

Define CLASS clsMainForm AS FORM

		Caption = "Phonenumbers"
		AutoCenter = .T.
		BorderStyle = 3
		Width = 600
		MinWidth = 600
		MaxWidth = 600
		Height = 600
		MinHeight = 600
		MinButton = .F.
		MaxButton = .F.
		Themes = .F.
		ShowTips = .T.

	ADD Object "lblFound" as "Label" with ;
		Visible = .T. , ;
		Autosize = .T. , ;
		Left = 12, ;
		Top = ThisForm.Height - 24, ;
		Caption = "Names found ", ;
		Anchor = 6
					
	ADD Object "lblPhoneNumbers" as "Label" with ;
		Visible = .T. , ;
		Autosize = .T. , ;
		Left = 12, ;
		Top = ThisForm.Height - 48, ;
		Caption = "Enter digits to search for ", ;
		Anchor = 6
					
	ADD object "txtPSearch" as "TextBox" WITH ;
		Visible = .T. , ;
		Left = 162, ;
		Top = ThisForm.Height - 48, ;
		Height = 21, ;
		Width = 168, ;
		Anchor = 6
		
	ADD object "cmdSearch" as "CommandButton" WITH ;
		Visible = .T. , ;
		Caption = "Search", ;
		Left = 360, ;
		Top = ThisForm.Height - 48, ;
		Height = 36, ;
		Anchor = 6
		
		PROCEDURE cmdSearch.Click()
	[highlight #FCE94F]		LOCAL lcPHNumber
			
			lcPHNumber = ALLTRIM(ThisForm.txtPSearch.Value)
		
			SELECT *, CAST(0 as Integer) as iLine, CAST(0 as Integer) as iOccurs FROM csrPhoneNumbers ;
					WHERE AT(lcPHNumber, mPhoneNumber) # 0 ;
					INTO CURSOR tmpPHNumbers READWRITE 

			SELECT tmpPHNumbers
			
			UPDATE tmpPHNumbers SET iLine = ATLINE(lcPHNumber, mPhoneNumber), iOccurs = OCCURS(lcPHNumber, mPhoneNumber)[/highlight]
			
			LOCATE 

			IF _Tally > 0
			
				ThisForm.lblFound.Caption = "Names found : " + ALLTRIM(TRANSFORM(_Tally, "9,999,999"))
			
				WITH ThisForm.pgfMain
					.Page2.Enabled = .T.
					.ActivePage = 2
					.Page2.Click()

				ENDWITH 
			ELSE 
			
				ThisForm.pgfMain.Page2.grdPhoneNumbers.Visible = .F.
				
				= MESSAGEBOX("No data found!", 48, "Search Phonenumbers", 2500)
				
				WITH ThisForm.pgfMain
					.ActivePage = 1
					.Page1.Click()
					
				ENDWITH 			
			ENDIF 
		ENDPROC 

	Add OBJECT cmdExit AS COMMANDBUTTON WITH;
		Caption = "Exit", ;
		Backcolor = RGB(192,192,192), ;
		Left = ThisForm.Width - 120, ;
		Top = ThisForm.Height - 48, ;
		Height = 36, ;
		Anchor = 4 + 8

		PROCEDURE cmdExit.CLICK
			ThisForm.Release()
			CLEAR Events
			
		ENDPROC              

	ADD OBJECT pgfMain AS PageFrame WITH;
	    PAGECOUNT = 2, ;
	    LEFT = 12, ;
    	TOP = 12, ;
	    WIDTH = THISFORM.WIDTH - 24, ;
    	HEIGHT = THISFORM.HEIGHT - 78, ;
    	Anchor = 15
    
		PROCEDURE pgfMain.Init()
			LOCAL loPage as Object
				
			FOR i = 1 TO This.PageCount
				loPage = This.Pages(i)
				loPage.AddObject("grdPhoneNumbers","grdBase")
				loPage.Caption = ICASE(i = 1, "Original Data","Filtered Data" )

			ENDFOR 
			
			This.Page2.Enabled = .F.
			This.Page1.Click()
			
		ENDPROC 
		
		PROCEDURE pgfMain.Page1.Click()
			LOCAL loPage 
			
			loPage = Thisform.pgfMain.Page1
			
			WITH loPage.grdPhoneNumbers
				.ColumnCount = -1
				.RecordSource = "csrPhoneNumbers"
				
				.Column1.Header1.Caption = "Name"
				.Column1.Width = 240
				
				WITH .Column2
		    		.Header1.Caption = "PhoneNumbers"
		    		.NewObject("edtComments","edtPHNumbers")
					.edtComments.Visible = .T.
					.CurrentControl = "edtComments" 
					.Width = 240
					.Sparse = .F.
					
				ENDWITH 
			ENDWITH
		ENDPROC 

		PROCEDURE pgfMain.Page2.Click()
			LOCAL loPage 
			
			loPage = ThisForm.pgfMain.Page2

			WITH loPage.grdPhoneNumbers
				.Visible = .T.
				.ColumnCount = -1
				.RecordSource = "tmpPHNumbers"
				
				.Column1.Header1.Caption = "Name"
				.Column1.Width = 216
					
				WITH .Column2
		    		.Header1.Caption = "PhoneNumbers"
		    		.NewObject("edtComments","edtPHNumbers")
					.edtComments.Visible = .T.
					.CurrentControl = "edtComments" 
					.Width = 216
					.Sparse = .F.
						
				ENDWITH 
				
				WITH .Column3
					.Header1.Caption = "Line"
					.Width = 36
					.FontBold = .T.

				ENDWITH 

				WITH .Column4
					.Header1.Caption = "N"
					.Width = 36
					.FontBold = .T.

				ENDWITH 
			ENDWITH 
		ENDPROC 
		
	PROCEDURE Load()
		CREATE CURSOR csrPhoneNumbers (cName C(25), mPhoneNumber M)
		
		FOR i = 1 TO 50000
				INSERT INTO csrPhoneNumbers (cName, mPhoneNumber) VALUES ("T" + SYS(2015), "+352 - " + ALLTRIM(STR(100000000 * RAND())) + " - Home")
		ENDFOR
		
		UPDATE csrPhoneNumbers SET mPhoneNumber = mPhoneNumber + CHR(13) + "+32 - " + ALLTRIM(STR(100000000 * RAND())) + " - Office"
		UPDATE csrPhoneNumbers SET mPhoneNumber = mPhoneNumber + CHR(13) + "+49 - " + ALLTRIM(STR(100000000 * RAND())) + " - Cellphone"
		UPDATE csrPhoneNumbers SET mPhoneNumber = mPhoneNumber + CHR(13) + "+33 - " + ALLTRIM(STR(100000000 * RAND()))
		UPDATE csrPhoneNumbers SET mPhoneNumber = mPhoneNumber + CHR(13) + "+44 - " + ALLTRIM(STR(100000000 * RAND()))

		LOCATE 
		
	ENDPROC 
	
	PROCEDURE Destroy()
		This.cmdExit.Click()
		
	ENDPROC 
	
      
ENDDEFINE

*****

DEFINE CLASS grdBase AS Grid

		Top = 12
		Left = 12
		Height = 600 - 84 - (4 * 12)
		Width = 600 - (4 * 12)
		BackColor = RGB(0, 240, 240)
		RowHeight = 90
		AllowRowSizing = .F.
		HeaderHeight = 21
		AllowHeaderSizing = .F.
		DeleteMark = .F.
		ReadOnly = .T.
		Anchor = 15
		Visible = .T.
		
ENDDEFINE 

***** 

DEFINE CLASS edtPHNumbers as EditBox
		BackColor = RGB(0, 240, 240)
		DisabledBackColor = RGB(0, 240, 240)
		IntegralHeight = .T.
		
ENDDEFINE 

*****

MarK

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top