Results 1 to 4 of 4

Thread: Advanced Autocompletion where QCompleter might not cut it

  1. #1
    Join Date
    Jun 2008
    Posts
    88
    Thanks
    4
    Thanked 4 Times in 3 Posts
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11
    Wiki edits
    1

    Question Advanced Autocompletion where QCompleter might not cut it

    I'm looking for some suggestions on how to implement autocomplete on several different datasets. I'm looking to implement something like what Google Chrome has. You type a word into the location bar and it autocompletes on your bookmarks, recently visited sites, and commonly searched for terms. (see the attached image)

    autocomplete-chrome.png

    The difference is, I'm doing this for a directory browser. So I need to complete on these 3 datasets
    1. recently visited directory paths
    2. bookmarked directory paths
    3. bookmark names
    I can figure out the ui side of things, creating a drop down with bold matching text, etc. I was hoping I could find a wise Qt smith to spark some ideas on how to implement matching side of things... even better if it can be done in a bg thread to avoid locking up the rest of the ui. There's nothing more annoying than interrupting the user when they're typing

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,363
    Thanks
    3
    Thanked 5,012 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Advanced Autocompletion where QCompleter might not cut it

    I guess it all boils down to having some kind of index to search the information in. It seems the datasets you want can easily be indexed. If all you want is static text search then you can build a tree of substrings that point to your items. When the user types a character, you go one step down the tree with all possible matches being stored in the current node. It requires quite much memory to hold such an index and possibly quite some time to build it but then searching through the tree is instantaneous. Other than that, QCompleter does more or less what you want (a simple filter proxy model is also sufficient) Finding matches will be slower though. If you want patterns then you have to search through all possible entries every time the user changes the search string. Since the collection is read-only, you can use threads to traverse the list faster.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    Jun 2008
    Posts
    88
    Thanks
    4
    Thanked 4 Times in 3 Posts
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11
    Wiki edits
    1

    Default Re: Advanced Autocompletion where QCompleter might not cut it

    I wrote a pretty dumbed down completer in a bg thread that suits my purposes. The dataset I'm looking through is going to be mighty small so the naiive algorithm I'm using will work fine. If I had a larger dataset I would probably need to do like you said and create an indexed search. It's also possible to take the dataset, break it up into a bunch of smaller pieces and fire it off to other threads to crunch the comparisons. Here's the initial version in all of its glory in PyQt. (the line edit has an instance of the thread and there's plenty of special logic for displaying my own completion popup)

    Qt Code:
    1. class QdCompletionThread(QtCore.QThread):
    2. def __init__(self, parent=None):
    3. QtCore.QThread.__init__(self, parent)
    4. self.directory = QtCore.QDir.root()
    5. self._dir_expr = re.compile(unicode("^" + self.directory.path() + ".*"))
    6.  
    7.  
    8. self.text = ""
    9. self.directory_history = []
    10. self.bookmarks = {}
    11.  
    12.  
    13. def match(self, text):
    14. self.text = text
    15. self.start()
    16.  
    17.  
    18. #
    19. # Pre-Populating the Gatherer
    20. #
    21.  
    22.  
    23. def setDirectoryHistory(self, directories):
    24. """Sets the history the completer can pull from"""
    25. self.directory_history = set(directories)
    26.  
    27.  
    28. def setBookmarks(self, bookmark_dict):
    29. """Sets the bookmarks the completer can pull from, names and directories"""
    30. self.bookmarks = bookmark_dict.copy()
    31.  
    32.  
    33. #
    34. # Synchronous Matching Methods
    35. #
    36.  
    37.  
    38. def getDirectoryMatches(self, text):
    39. """Returns the directory matches based on text"""
    40. text = unicode(text)
    41. if text.endswith(os.sep):
    42. clean_path = text
    43. parent_dir = text
    44. match_name = ""
    45. else:
    46. clean_path = unicode(QtCore.QDir.cleanPath(text))
    47. parent_dir = os.path.dirname(clean_path)
    48. match_name = os.path.basename(clean_path)
    49.  
    50.  
    51. # check that the directory exists or is readable
    52. if not self.directory.cd(parent_dir):
    53. return []
    54.  
    55.  
    56. matches = self.directory.entryList([match_name + "*"],
    57. QtCore.QDir.Dirs | QtCore.QDir.NoDotAndDotDot)
    58. return [os.path.join(parent_dir, unicode(match)) for match in matches]
    59.  
    60.  
    61. def getMatches(self, text):
    62. """Returns all of the matches based on the history, bookmarks and directories"""
    63. matches = set()
    64.  
    65.  
    66. # check if it matches any directories
    67. if self._dir_expr.match(text):
    68. matches.update(self.getDirectoryMatches(text))
    69.  
    70.  
    71. directories = self.directory_history.copy()
    72. directories.update(self.bookmarks.values())
    73.  
    74.  
    75. # check known directory names and parts
    76. for directory in directories:
    77. if text in directory:
    78. matches.add(directory)
    79.  
    80.  
    81. # check bookmark names
    82. for bookmark_name in self.bookmarks:
    83. if text in bookmark_name:
    84. matches.add(bookmark_name)
    85.  
    86.  
    87. return list(sorted(matches))
    88.  
    89.  
    90. #
    91. # Overloaded Qt Methods
    92. #
    93.  
    94.  
    95. def run(self):
    96. text = unicode(self.text)
    97. matches = self.getMatches(text)
    98.  
    99.  
    100. if text != self.text:
    101. # the text has changed since the thread has started
    102. self.run()
    103. return
    104.  
    105.  
    106. self.emit(SIGNAL("matched(QString, QStringList)"), text, matches)
    To copy to clipboard, switch view to plain text mode 

  4. #4
    Join Date
    Jun 2008
    Posts
    88
    Thanks
    4
    Thanked 4 Times in 3 Posts
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11
    Wiki edits
    1

    Default Re: Advanced Autocompletion where QCompleter might not cut it

    Here's a shot in the dark... I'm trying to see if I can do the following with a QCompleter

    if I type 'Desktop', I want the completer to display whatever I found in my thread from my last post... ie

    /home/foo/Desktop/
    /home/foo/Desktop/photos/
    /home/foo/Desktop/photos/vacation/
    /home/bar/Desktop/notes/

    A stock QCompleter seems to only recognize those results if I type "/home/foo/Desktop". The entire completion prefix needs to be in place. If there's no way to get a QCompleter to do this, it means I have to essentially copy a bunch of functionality from QCompleter, like the event filter it does. And man would that stink. Any ideas on how to tell the QCompleter to display what I tell it to?


    Added after 4 minutes:


    Answering my own question 5 mins later:

    Qt Code:
    1. completer.setCompletionMode(QtGui.QCompleter.UnfilteredPopupCompletion)
    To copy to clipboard, switch view to plain text mode 
    This will show everything in the completion model and still do all the event filtering for me. There's probably still some details, like selecting the best match or at least the first one in the list while the user is typing. But this will do
    Last edited by chezifresh; 14th October 2011 at 02:48.

Similar Threads

  1. Replies: 7
    Last Post: 12th July 2011, 14:50
  2. Advanced use of QUiLoader
    By doberkofler in forum Newbie
    Replies: 0
    Last Post: 27th October 2009, 21:02
  3. Autocompletion using Qt
    By bismitapadhy in forum Qt Programming
    Replies: 2
    Last Post: 7th August 2009, 17:02
  4. Replies: 1
    Last Post: 12th October 2008, 08:21
  5. QcomboBox autoCompletion
    By Lele in forum Qt Programming
    Replies: 3
    Last Post: 11th July 2006, 16:44

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.