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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Search Combo Box revisited 2

Status
Not open for further replies.

herbstgy

Programmer
Jan 30, 2018
62
HU
Hi Guys,

I tried to create a Search Combo Box like you were discussed in thread184-1312767.
Also tried Mike Gagnon's solution with the ComboBox Interactive Event modification in faq184-1792.
Both solution does what it supposed to, with one flaw: neither of them works with international characters.
Does anyone have an idea to circumvent this problem?
 
What do you mean by "international characters"? Do you perhaps mean letters with accents and diacryticals, such as à and é?

If so, Mike Gagnon's auto-fill combo box should still work, but with one small modification. In the InteractiveChange event, look for this line:

Code:
IF (lnLastKey>=32 and lnLastKey<=126)

and change it to

Code:
IF (lnLastKey>=32 and lnLastKey<=[b]255[/b])

The effect will be to include all characters in the so-called upper-ASCII range, which includes accented letters, diphthongs, currency symbols and certain others.

But have you also considered using a textbox with Autocomplete set to .T.? That will give you the same benefits as an auto-fill combo, but with considerably less effort.

Mike





__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike,
Your solution to extend to chr(255) will work, but what happens if user types an 'unwanted' character like e.g. [ ?
Presently I have to validate that only normal alphabet characters (a~z), numbers 1~0 and all accented characters ä ~ ý are allowed have therefore coded
Code:
lcValue = Alltrim(Lower(This.Value))
Do Case
	Case Inlist(m.lcValue,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u')
		lcLettervalu = m.lcValue
	Case Inlist(m.lcValue,'v','w','x','y','z','ä','á','à','ë','è','é','ï','í','ì','ö','ó','ò','ü','ú','ù','ç','ý')
		lcLettervalu = m.lcValue
	Case Inlist(m.lcValue,'1','2','3','4','5','6','7','8','9','9','ø','ñ','æ','å','ß','ã')
		lcLettervalu = m.lcValue
endcase

was 'forced' to break it into 3 cases since inlist has a restricted length not covering the lot.

This solution, in my opinion is however clumsy and should be recoded into something more elaborate, haven't yet found it and meanwhile, since 'it works - it works'

Regards,

Koen

Please not that this site changed some accented characers into like '&ograve' a.s.o in my vfp coding it is just an o with the accent grave, don't know why this happens with the o u letters only.
 
Olaf,

Thanks, isalpha an isdigit will be much better. One exception: ý this character, which is part of the Dutch alphabet however since it is very rarely used, we normally just type ij to get the effect and very few people make use of the key-combination '+y to get that letter I can accept that 'bug'. Thanks.

Koen
 
Besides you could also put all the characters you want to allow in a single string - it'll also be shorter than 256 characters automatically, and then use the $ operator (is contained in) or check AT()>0 or OCCURS() function, many ways to solve that without INLIST.

Besides preventing those as last key, you could just filter unwanted characters from the value even after they are in it already. Mike Gagnons code actually redoes the base behaviour of keypress (before interactivechange) by working on displayvalue instead of value and by keeping displayvalue at what you types, so the natural working of value is overridden.

But you could simpler work retroactive you accept any input as normal and then remove unwanted characters.

I just checked out what lastkey() is when I use backspace: 127. Besides Ascii code is 8. That would not be allowed. Even for autocomplete I'd like to be able to backspace..., you don't get along very well if you just compare chr(lastkey()) to allowed characters.

I'd also plead for a textbox with autocomplete instead.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Your solution to extend to chr(255) will work, but what happens if user types an 'unwanted' character like e.g. [ ?

Your right, Koen. But that's the same situation as with Mike Gagnon's original solution. If there is an entry in the combo that contains, say, a square bracket, then pressing that key will find it. Whether that's correct or not depends on what you want to achieve. If you want to limit the search to alphabetical characters, then I agree that a test for ISALPHA() would be better.

Of course, we are making assumptions about what the original questioner means by "international characters". It would be useful if he could clarify that.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Olaf,

so we have [ul]
[li]inlist()[/li][li]isalpha()[/li][li]occurs() $[/li][li]at() $[/li]
[/ul]

all doing basicly the same, where I believe isalpha is the shortest.
Thanks,
Koen
 
[ol 1]
[li]inlilst() -> limited to 27 items[/li]
[li]isalpha() only good for alphabetic, can be extended using isdigit()[/li]
[li]at(newchar,listofallowedchars)>0, occurs(newchar,listofallowedcahrs) or (newchar $ listofallowedchar) being the most versatile to use, as they can cover more than characters and digits.[/li]
[/ol]

The $ operator is most to the pont for this test, as you only need to know whether the newly entered char is in the allowed list, neither where (at) it is not how often it (occurs) it exists.
Don't you know the $ operator?

Code:
If lcNewChar $ "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyzƒŠŒšœŸÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÓÔÕÖÛÜÝÞßàáâãäåæçèéêëìíîïðñóôõöøûüýþÿ0123456789.,:;?(){]"

This will check whether the new input is space (notice the space between uppercase an lowercase normal english latin letters), any letters (aside of some the forum translates awkwardly into html entities), any digits and some more and you can configure it to any set of characters you want to allow.

And this approach is very well known. For example in thread184-1673722 or in thread184-1476889

Still, whether you limit the value of lastkey or check the char is in a certain list you disallow keys that have no valid cahracter but are a valid action like delete or backspace, therefore I suggested to go the other route and check Value for invalid characters and remove them.

Bye, Olaf.

Olaf Doschke Software Engineering
 
ISALPHA() is definitely the shortest. More to the point, it doesn't depend on the programmer working out in advance which letters to include. Assuming our intepretation of "international characters" is correct, that choice is built into the function.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I question the whole approach anyway, because this doesn't allow to edit the searchtext. Even just the normal intellisnese in VFPs code editing allows you to backspace.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Dear All,
thank you for all the answers.
The fact of the matter is I tried both aforementioned approach: the modified combobox and the textbox with autocomplete. Both of them has disadvantages.
- The textbox with autocomplete would be the smoother solution, but it does not accept accented national characters. It just doesn't. I tried to use it with a couple of hundred predefined search suggestions which I fill in the textbox's Init method. It works well until I only use only the classic latin letters.
- The Combobox accepts accented characters after Olaf's ISALPHA() check modification, but does not open down with the suggestions. I even tried to call this.dropdown from the interactivechange method from the key detection, but no avail. (it also requires to create four additional properties in the combobox class which never really use later. I didn't really understand this, but I've found they can be left out)
 
You mean these 4 properties:

1. acstyle (Default value = 2)
2. lastdisplayvalue (Default value = [none])
3. lastsellength (Default value = 0)
4. lastselstart (Default value = 0)

Well, they are used by the code given.

herbstgy said:
which never really use later

well, then you haven't used the given code.

Besides that

herbstgy said:
The textbox with autocomplete would be the smoother solution, but it does not accept accented national characters.

I also can't aay that, you must have populated the "search suggestions" wrong. You wouldn't do that in init, but prepare an autocomplete table.

If you simply set 'AutoComplete to 1 and let VFP create the necessary DBF for autocomplete sure this will also record International characters and search b them:
autocomplete_qlyi3a.png

I don't used a specific Autocomplete Table, but you can copy out the one VFP automatically uses as described in the help at Home(7)+"autocomp.dbf" and put in our initial data.

Did you read into the topic well enough to define your autocomplete data the way it's needed for your case? It doesn't seem so.

Bye, Olaf.



Olaf Doschke Software Engineering
 
The textbox with autocomplete would be the smoother solution, but it does not accept accented national characters. It just doesn't. I tried to use it with a couple of hundred predefined search suggestions which I fill in the textbox's Init method. It works well until I only use only the classic latin letters.

That's not the normal way to use autocomplete. It's not the programmer's job to populate the table. That's done for your automatically from the user's entries. In fact, that's the whole point of autocomplete. It "learns" your data from what has been entered previously.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Well, you can populate it, and the advanced feature of weighted suggestions or ordering by frequency even ask for it. You just have to use the DBF structure as given for AutoComp tables. You can't just use any list of values as AutoComp table. The possibilities are much more vast than simple autocomplete or intellisense, though the latter has a specialty in showing parametrizations of functions, for example. By the way the intellisense feature of VFP can also be used at runtime in edit memo windows or even editboxes, IIRC. Doug Henning has some white paper on that, I doubt this is for you, when you even don't get into the details of a code example or the AutoComplete feature. What you expose here doesn't look like just bad luck, sorry to say so, but success is not instant, if you give up after the first try and even make wrong accusations that won't give you much joy, and I only think about the effect you have on your own to yourself, not the responses you get from a forum about that. AutoComplete really just even needs to be set to 1 to work off hands, if you want to populate suggestions just enter one, read the help topic in all detail to know VFP stores a table in Home(7)+"autocomp.dbf", take that dbf and expand it with your suggestions. As easy as that.

I can't reproduce the disadvantage you found about international characters, unless you tell me you want to use international characters not available to any ANSI code page you could use in VFP. I'd like to understand your problem, but you don't even tell what you tried. And what you tell about the usage of Mike Gagnons code is you haven't used it as intended, as the four given new properties are used in the code.

In regard to international characters: Besides the given AutoComp structure you can choose codepage and collation sequence as you like, as long as VFP supports it. VFP has support for simplified Chinese and I think also Japanese, Ansi 1252 supports many special characters of german, french, scandinavian or slavic languages, greek is another matter again, and then there are alphabets VFP doesn't support at all, like indian Urdu.

The characters you have in Ansi 1252 are shown above, all those are available and some more (I already said above I skippped some as the forum processes them to HTML entities).

If you only give it a try and never even come to a forum asking why something doesn't work as expected with your code, you'll never know why, especially if you give up before you even dig into the details of the family of properties and data working hand in hand with the autocomplete feature. It's really offering very advanced and even more modes than I'd ask of an autocomplete mode with the little as data structure it needs.

The need or the wish to prepopulate it asks you to read into the concept in more details than just setting AutoComplete=1 and AutoCompTable to any table. I'm reminded about a situation someone just did set a DBF with a single column of values and expected this to be taken as suggestions. You get what you deserve, if you don't read the manual or follow the given instructions of a FAQ.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Olaf said:
If you simply set 'AutoComplete to 1 and let VFP create the necessary DBF for autocomplete sure this will also record International characters and search b them:
I don't used a specific Autocomplete Table, but you can copy out the one VFP automatically uses as described in the help at Home(7)+"autocomp.dbf" and put in our initial data.
Did you read into the topic well enough to define your autocomplete data the way it's needed for your case? It doesn't seem so.

That I did. I don't really understand why you assume the opposite. Here's the code I used:

Code:
SELECT DISTINCT ALLTRIM(addr_city)+' '+ALLTRIM(addr_street)+' '+TRANSFORM(addr_number,'@Z 999.')+' '+ALLTRIM(company) AS srchdata ;
 FROM gepek ;
 WHERE alive ;
 ORDER BY 1 ;
 INTO CURSOR srchdata
DELETE FILE (HOME(7)+"qsrch.dbf")
CREATE TABLE (HOME(7)+"qsrch.dbf") (Source C(20),Data C(254),Count I,Weight I,Created T,updated T,user M)
INSERT INTO qsrch (Source,Data,count,created,updated) ;
 SELECT "txtQsrch",srchdata,1,DATETIME(),DATETIME() FROM srchdata
USE IN qsrch
USE IN srchdata
WITH this
	.AutoCompSource="txtQsrch"
	.AutoCompTable=(HOME(7)+"qsrch.dbf")
	.AutoComplete= 1
ENDWITH

it simply builds a table named qsrch.dbf in the HOME(7) dir with the same structure as autocomp.dbf. and it works, apart from the accented characters...

Olaf said:
I also can't aay that, you must have populated the "search suggestions" wrong.

that was my first thought too. :)
so I tried without the predefined suggestions, and let VFP to fill the autocomp.dbf as it wants...
same thing, it fails on the accented characters.
I'm out of ideas here...

(also, can't upload pics to illustrate my problem. but that's just the icing on the cake.)
 
 https://files.engineering.com/getfile.aspx?folder=8598f9a2-ced5-4e94-a0aa-f7d8076adbd0&file=Clipboard-1.png
Olaf said:
You mean these 4 properties:

1. acstyle (Default value = 2)
2. lastdisplayvalue (Default value = [none])
3. lastsellength (Default value = 0)
4. lastselstart (Default value = 0)

Well, they are used by the code given.

Quote (herbstgy)
which never really use later

well, then you haven't used the given code.

yes, I meant those properties in faq184-1792.
and this code:

Code:
In the InterActive Event of the ComboBox:


LOCAL lnStyle, lnLastKey, lcDisplayValue
lnLastKey=lastkey()
lnStyle = this.style
IF this.style = 2
    this.style = 0
ENDI
IF (lnLastKey>=32 and lnLastKey<=126)
    IF this.selstart>=1
        lcDisplayValue=substr(this.displayvalue,1,this.selstart-1)+(chr(lnLastKey))
    ELSE
        lcDisplayValue=(chr(lnLastKey))+allt(this.displayvalue)
    ENDI
    IF empty(lcDisplayValue)
        lcDisplayValue=allt(chr(lnLastKey))
    ENDI
    FOR i = 1 to this.listcount
            If Upper(lcDisplayValue) == Upper(Substr(This.List(i),1,Len(lcDisplayValue)))
                This.DisplayValue=This.List(i)
                This.SelStart=Len(lcDisplayValue)
                nlLength=Len(Allt(This.DisplayValue))-Len(lcDisplayValue)
                This.SelLength=Iif(nlLength <0,0,nlLength)
                this.lastdisplayvalue = this.displayvalue
                this.lastselstart = this.selstart
                this.lastsellength = this.sellength
                RETURN
            ENDI
    ENDFOR
ENDIf


In the combobox requery:


this.Value = this.DisplayValue && Just to reset the display value


In the valid of the combobox:


If !Empty(This.DisplayValue)
    Local cTableName,cFieldName,nAnswer,cValue
    Store Juststem(This.RowSource) To cTableName &&Won't work for VFP5.0
    Store Justext(This.RowSource) To cFieldName && This is normally used for 3 character extension, but it works for any lenght. Won't work for VFP5.0
    Select (cTableName)
    Locate For &cFieldName = This.DisplayValue
    If !Found()
        nAnswer = Messagebox("This value was not found in the table,"+Chr(13)+"Do you want to save it in the table?",36,"")
        If nAnswer = 6
            Insert Into &cTableName (&cFieldName) Values (This.DisplayValue)
            If CursorGetProp("Buffering") > 1  && Check to see if we should use tableupdate
                Tableupdate(1,.T.,cTableName)
            ENDIF
        this.Requery() && To reset the display value
        Else
            Store '' To This.DisplayValue
        Endif
    Endif
ENDIF

could you point out where those properties are actually used? maybe I'm really missing something here.

but that's really beside the point.
this combobox solution could really be used instead of textbox autocomplete, if the popup part would open automatically as the user starts typing in it. could you help with that?
 
Well, I have to make some assumptions of doing something wrong when it doesn't work for you. Your code doesn't show your data, but my screenshot was already showing autocomplete reacting to German umlauts, if that doesn't prove anything to you I can't help you.

The first problem I see in your approach is trying to create a table into HOME(). This by default is in Program Files directory write protected and you'll likely find your DBF in your profile in some subfolder of C:\Users\%Username%\AppData\Roaming\Microsoft\Visual FoxPro 9}...

So you're doing this too literally as VFP. VFP has one advantage: It has installed this DBF where it is, during installation you can write files and such writes are not redirected. Do you know such mechanisms as write redirections since Vista? So first criticism is: Store your data in your own directories. The way VFP works with his central DBF is surely something you would need to replace when you deploy your application anyway.

Next, I can't judge what your expression ALLTRIM(addr_city)+' '+ALLTRIM(addr_street)+' '+TRANSFORM(addr_number,'@Z 999.')+' '+ALLTRIM(company) AS srchdata results in, I don't have your gepek.dbf

And in regard what I told about codepage, what is CPDBF("gepek.dbf") Is that the same code as you create with your CREATE TABLE statement? You obviously miss, that CREATE TABLE has a codepage=nnnn option, and if you don't use that and create a dbf with VFPs default codepage, which will depend on your locale, yes - of course - you are likely destroying your data because your insert of the data isn't converting anything. You can only copy this way when the source and target DBF have the same codepage.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Where are the four properties used?

Code:
    FOR i = 1 to this.listcount
            If Upper(lcDisplayValue) == Upper(Substr(This.List(i),1,Len(lcDisplayValue)))
                This.DisplayValue=This.List(i)
                This.SelStart=Len(lcDisplayValue)
                nlLength=Len(Allt(This.DisplayValue))-Len(lcDisplayValue)
                This.SelLength=Iif(nlLength <0,0,nlLength)
[highlight #FCE94F]                this.lastdisplayvalue = this.displayvalue
                this.lastselstart = this.selstart
                this.lastsellength = this.sellength[/highlight]
                RETURN
            ENDI
    ENDFOR

Indeed I don't see acstyle used or have an idea why it is defined, the code acts directly in the native Style property. But these three properties are a central part of making the code work remembering the situation of the last interactive change, as that already changed in the native properties when the event happens, THIS.Value is already the new value, and the way Mike Gagnon picks up on the old is remembering lastdisplayvalue. The code is really just a few lines, if you don't understand what something is doing feel free to ask.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top