customizing completion of GtkComboBoxText

前端 未结 2 781
甜味超标
甜味超标 2020-12-20 14:00

How can I customize the completion of a GtkComboBoxText with both a \"static\" aspect and a \"dynamic\" one? The static aspect is because some entries are known and added to

2条回答
  •  無奈伤痛
    2020-12-20 14:39

    I will not show exact code on how to do it because I never did GTK & C only GTK & Python, but it should be fine as the functions in C and Python functions can easily be translated.

    OP's approach is actually the right one, so I will try to fill in the gaps. As the amount of static options is limited probably won't change to much it indeed makes sense to add them using gtk_combo_box_text_append which will add them to the internal model of the GtkComboBoxText.

    Thats covers the static part, for the dynamic part it would be perfect if we could just store this static model and replace it with a temporay model using gtk_combo_box_set_model() when a _ was found at the start of the string. But we shouldn't do this as the documentation says:

    You should not call gtk_combo_box_set_model() or attempt to pack more cells into this combo box via its GtkCellLayout interface.

    So we need to work around this, one way of doing this is by adding a GtkEntryCompletion to the entry of the GtkComboBoxText. This will make the entry attempt to complete the current string based on its current model. As an added bonus it can also add all the character all options have in common like this:

    As we don't want to load all the dynamic options before hand I think the best approach will be to connect a changed listener to the GtkEntry, this way we can load the dynamic options when we have a underscore and some characters.

    As the GtkEntryCompletion uses a GtkListStore internally, we can reuse part of the code Nominal Animal provided in his answer. The main difference being: the connect is done on the GtkEntry and the replacing of GtkComboText with GtkEntryCompletion inside the populator. Then everything should be fine, I wish I would be able to write decent C then I would have provided you with code but this will have to do.

    Edit: A small demo in Python with GTK3

    import gi
    
    gi.require_version('Gtk', '3.0')
    
    import gi.repository.Gtk as Gtk
    
    class CompletingComboBoxText(Gtk.ComboBoxText):
        def __init__(self, static_options, populator, **kwargs):
            # Set up the ComboBox with the Entry
            Gtk.ComboBoxText.__init__(self, has_entry=True, **kwargs)
    
            # Store the populator reference in the object
            self.populator = populator
    
            # Create the completion
            completion = Gtk.EntryCompletion(inline_completion=True)
    
            # Specify that we want to use the first col of the model for completion
            completion.set_text_column(0)
            completion.set_minimum_key_length(2)
    
            # Set the completion model to the combobox model such that we can also autocomplete these options
            self.static_options_model = self.get_model()
            completion.set_model(self.static_options_model)
    
            # The child of the combobox is the entry if 'has_entry' was set to True
            entry = self.get_child()
            entry.set_completion(completion)
    
            # Set the active option of the combobox to 0 (which is an empty field)
            self.set_active(0)
    
            # Fill the model with the static options (could also be used for a history or something)
            for option in static_options:
                self.append_text(option)
    
            # Connect a listener to adjust the model when the user types something
            entry.connect("changed", self.update_completion, True)
    
    
        def update_completion(self, entry, editable):
            # Get the current content of the entry
            text = entry.get_text()
    
            # Get the completion which needs to be updated
            completion = entry.get_completion()
    
            if text.startswith("_") and len(text) >= completion.get_minimum_key_length():
                # Fetch the options from the populator for a given text
                completion_options = self.populator(text)
    
                # Create a temporary model for the completion and fill it
                dynamic_model = Gtk.ListStore.new([str])
                for completion_option in completion_options:
                    dynamic_model.append([completion_option])
                completion.set_model(dynamic_model)
            else:
                # Restore the default static options
                completion.set_model(self.static_options_model)
    
    
    def demo():
        # Create the window
        window = Gtk.Window()
    
        # Add some static options
        fake_static_options = [
            "comment",
            "if",
            "the_GUI",
            "the_system",
            "payload_json",
            "x1",
            "payload_json",
            "payload_vectval"
        ]
    
        # Add the the Combobox
        ccb = CompletingComboBoxText(fake_static_options, dynamic_option_populator)
        window.add(ccb)
    
        # Show it
        window.show_all()
        Gtk.main()
    
    
    def dynamic_option_populator(text):
        # Some fake returns for the populator
        fake_dynamic_options = [
            "_5Hf0fFKvRVa71ZPM0",
            "_8261sbF1f9ohzu2Iu",
            "_0BV96V94PJIn9si1K",
            "_0BV1sbF1f9ohzu2Iu",
            "_0BV0fFKvRVa71ZPM0",
            "_0Hf0fF4PJIn9si1Ks",
            "_6KvRVa71JIn9si1Kw",
            "_5HKvRVa71Va71ZPM0",
            "_8261sbF1KvRVa71ZP",
            "_0BKvRVa71JIn9si1K",
            "_0BV1KvRVa71ZPu2Iu",
            "_0BV0fKvRVa71ZZPM0",
            "_0Hf0fF4PJIbF1f9oh",
            "_61sbFV0fFKn9si1Kw",
            "_5Hf0fFKvRVa71ozu2",
        ]
    
        # Only return those that start with the text
        return [fake_dynamic_option for fake_dynamic_option in fake_dynamic_options if fake_dynamic_option.startswith(text)]
    
    
    if __name__ == '__main__':
        demo()
        Gtk.main()
    

提交回复
热议问题