3

I have an application which has an Edit Field. The user will type a search phrase in this field. I am trying to show in real time the hits against the user's text. After entering three characters, I do my first search, and then after every character or backspace the search is performed again.

The problem is that as my search algorithm is getting more advanced, it takes longer to do the search. The user can type faster than the results are before generated/displayed. As a result, the app is feeling sluggish/slow. I have a couple options: (1). Wait until the user hits enter (2). Put the search in a different thread and do it asynchronously. Kinda hesitant here since I have never worked with threads before (3). Implement some type of delay so that if the user is still typing, I wait for the user to stop.

I am leaning towards option 3, but how do I detect if the user is still typing? Do I have to keep a timestamp associated with every keystroke?

user1009073
  • 3,160
  • 7
  • 40
  • 82
  • 1
    Do the search asynchronously. Start immediately. When you are ready to show the results show them. If the user types before you are ready, throw away your previous search efforts, and search again. – David Heffernan Oct 26 '14 at 13:14
  • 1
    @David, that might be unnecessary wasting of resources (depends on what is searched and how of course; we've discussed this some time ago). user1009073, for case 3 I wrote [`this component`](http://pastebin.com/45Z2d7pE). – TLama Oct 26 '14 at 13:23
  • 6
    A simple `TTimer` will do the job with a small interval (f.i. 250ms) and `Timer1.Enabled := false; Timer1.Enabled := true;` to reset the timer on every change event of the edit field. `TTimer.OnTimer` start the search – Sir Rufo Oct 26 '14 at 13:36
  • 1
    @TLama Why would that matter? As a user I'd prefer that my computer's resources were put to use to get me my answer more quickly. – David Heffernan Oct 26 '14 at 17:22
  • @David, consider the (worst) case of having a database backend behind this search. Would you bother DBMS with executing a query on every single key press (take also into account, that not all DBMSs support running query interruption) ? – TLama Oct 26 '14 at 17:36
  • 2
    @TLama In that case waiting a quarter of a second is hardly any better. If you can't cancel db and it's expensive to query, then let the user tell you they are ready. – David Heffernan Oct 26 '14 at 17:54
  • @David, it wasn't me suggesting quarter of a second. Even though for fast typists it might be enough. My point is that I would prefer using delay rather than performing search for every single key press. – TLama Oct 26 '14 at 20:48
  • 1
    @TLama Users don't care about stuff like that. They prefer whatever gets them answers most effectively. Just as it would be bad to do an expensive db query every key press, it would be bad to postpone a quick operation when you had idle capacity. Imagine how horrid to use shell auto complete would be with a delay. Choose the solution that best fits the bill. – David Heffernan Oct 26 '14 at 20:53
  • @TLama Avoiding efficient coding (i.e. a worker thread) - especially in use cases where the result would be instantly recognizable - because of superstitious fear of learning something new (i.e. threading) is a bad practice and should not be encouraged. – mg30rg Oct 28 '14 at 10:00
  • @mg30rg, I was talking about the worst possible case. About a DB backend which doesn't allow you to interrupt a search in progress. In that case you should just avoid executing frequent search (no matter if it's in a thread or not). – TLama Oct 28 '14 at 13:31
  • @TLama - In that case you should bypass the problem by locally caching the search data (we are talking about autocomplete so a bit outdated data should not be an issue). And then the threading solution remains the best. – mg30rg Oct 28 '14 at 13:42
  • @mg30rg, agreed. For instance (if applicaple), if you get fetched the (ideally) complete results, you can just filter the fetched resultset if the user only adds some text to the search term. – TLama Oct 28 '14 at 13:55

1 Answers1

0

If I were you I would stick with the threading solution.


It is faster, does not lag and - if written properly - will not introduce additional problems, and is a great opportunity to learn threading by a not so risky or difficult problem. If you choose this solution you will have to perform four easy steps:

  1. Create an OnSearchFinished() event handler on your form and assign it to a message code (like WM_USER + 1). This message will be sent by your thread when it has finished producing search results.
  2. Create a TThread descendant with your search code in its .Execute() method that will perform the search. It has to have a field with the search term. (The .Execute() will not be called directly so it can't handle parameters. You execute TThread descendents by .Resume()ing them.) The instance of this class can be created in the constructor of your form and needs to be created in suspended state.
  3. Assuming your search code has a main cycle, you will have to check if your main program called .Terminate() over your object. If it has, you have to exit your cycle.
  4. In the .OnChange() or .OnKeyDown() where you handle your search, you should (first) .Terminate() your thread (to stop an already running search if there is any), then set the field to your new search term and .Resume() it.
Community
  • 1
  • 1
mg30rg
  • 1,311
  • 13
  • 24