Aplicação rápida com ListStore como preferência


10

Estou começando a escrever um programa com 'rapidamente'. Uma lista dos idiomas desejados será uma preferida. Exemplo:

languages = ["en", "de"]

O código (criado automaticamente) rapidamente que lida com a parte preferencial se parece com:

# Define your preferences dictionary in the __init__.main() function.
# The widget names in the PreferencesTestProjectDialog.ui
# file need to correspond to the keys in the preferences dictionary.
#
# Each preference also need to be defined in the 'widget_methods' map below
# to show up in the dialog itself.  Provide three bits of information:
#  1) The first entry is the method on the widget that grabs a value from the
#     widget.
#  2) The second entry is the method on the widget that sets the widgets value
#      from a stored preference.
#  3) The third entry is a signal the widget will send when the contents have
#     been changed by the user. The preferences dictionary is always up to
# date and will signal the rest of the application about these changes.
# The values will be saved to desktopcouch when the application closes.
#
# TODO: replace widget_methods with your own values


widget_methods = {
    'languages': ['getter', 'setter', 'changed'],
}

Na GUI, parece que o widget escolhido no gtk para uma lista é um ListStore (que não é um widget, mas um modelo, mas está definido no arquivo Glade ...). Alguém pode me dizer o que iria trabalhar para um ListStore para o 'getter', 'setter'e 'changed'no código acima?

A abordagem parece fácil para widgets de entrada simples e similares, mas não sei como usá-la com listas.

Como alternativa, eu obviamente aceitaria qualquer outra maneira de lidar com listas como preferências, desde que o comprimento da lista não seja fixo.


Não é uma resposta para a pergunta, mas por que seu aplicativo precisa mudar de idioma? Não é possível simplesmente usar gettext e a localidade definida pelo usuário para determinar o idioma? Essa é a maneira padrão de lidar com as traduções de um aplicativo: funcionaria automaticamente e seria muito menos útil para você.
David Planella 14/10

@ DavidPlnella: uma boa pergunta. Não muda de idioma. O aplicativo procura episódios de TV em um banco de dados. Como muitas pessoas falam mais de um idioma, os episódios em todos eles podem ser recuperados. Exemplo: assisto a episódios de TV em alemão e inglês.
Xubuntix 14/10

Respostas:


2

Isenção de responsabilidade: eu não sabia nada rapidamente até ler sua postagem ou sobre programação de GUI em geral para esse assunto. Portanto, sinceramente, não tenho negócios tentando responder a essa pergunta :)

Dito isto, rapidamente é um projeto interessante. Examinei brevemente a fonte do padrão e identifiquei as seguintes abordagens em potencial para adicionar uma preferência de estilo de lista suportada pelo ListStore:

  1. 'Monkey-patch' obtém e define widget_methods em um widget TreeView de estoque (com modelo ListStore) conforme definido em data / ui / Preferences $ PROJECTNAME $ Dialog.ui com glade.
  2. Implemente set_widget_from_preferencee set_preferencena subclasse de PreferencesDialog do projeto (a subclasse é Preferences $ PROJECTNAME $ Dialog) e faça algo diferente quando keyou widgetfor o widget TreeView suportado pelo ListStore.
  3. Escreva uma subclasse personalizada de gtk.TreeView com um widget personalizado correspondente para glade .

Para testá-las, eu implementei todas essas três idéias - cada uma funcionou como pretendido e a AFAICT, de forma idêntica. No final, o terceiro (em particular) me pareceu o mais limpo e mais próximo das convenções usadas em todo o painel, apesar de inicialmente esperar o contrário.


Aqui estão os passos que eu segui para o número três ...

Usando o glade via quickly design(rapidamente 11.10, btw) e seguindo este tutorial (parte 2) , adicione um widget ScrolledWindow ao Preferences $ PROJECTNAME $ Dialog.ui, solte um TreeView nele e nomeie o TreeView language_treeview. Crie um novo modelo ListStore para o TreeView quando solicitado e nomeie-o language_liststore, etc ... eventualmente, acabei com algo assim:

glade-properties

Em seguida, adicione um catálogo glade (data / ui / preferências_ $ PROJECTNAME $ _treeview.xml) com o seguinte conteúdo:

<glade-catalog name="preferences_$PROJECTNAME$_treeview" domain="glade-3"
               depends="gtk+" version="1.0">
  <glade-widget-classes>
    <glade-widget-class title="$PROJECTNAME$ Preferences TreeView" name="Preferences$PROJECTNAME$TreeView"
                        generic-name="Preference$PROJECTNAME$TreeView" parent="GtkTreeView"
                        icon-name="widget-gtk-treeview"/>
  </glade-widget-classes>
</glade-catalog>

Em seguida, edite as Preferências $ PROJECTNAME $ Dialog.ui, adicionando ...

<!-- interface-requires preferences_$PROJECTNAME$_treeview 1.0 -->

... para o topo, abaixo da marca requer. E altere o atributo de classe de language_treeview para Preferences $ PROJECTNAME $ TreeView, em preparação para uma etapa posterior.

Por fim, adicione o seguinte elemento à lista widget_methods em Preferences $ PROJECTNAME $ Dialog.py

'language_treeview': ['get_languages', 'set_languages', 'button-release-event']

E no final do mesmo arquivo (Preferências $ PROJECTNAME $ Dialog.py), adicione

import gtk

ALL_LANGUAGES = [
  'en', 'uk', 'de', 'fr', # ... much longer list
]

class Preferences$PROJECTNAME$TreeView(gtk.TreeView):
    __gtype_name__ = "Preferences$PROJECTNAME$TreeView"

    def __init__(self, *args):
        super(Preferences$PROJECTNAME$TreeView, self).__init__(*args)
        self.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

    # loads the liststore with all languages, 
    # selecting/highlighting in the treeview those 
    # already retrieved from previously saved preferences
    def set_languages(self, preferred_languages):
        model = self.get_model()
        for row, lang in enumerate(ALL_LANGUAGES):
            model.append([lang])
            if lang in preferred_languages:
                self.get_selection().select_iter(model.get_iter(row))

    # collects only the selected languages in the treeview
    # to save in the preferences database
    def get_languages(self):
        model, rows = self.get_selection().get_selected_rows()
        result = [model.get_value(model.get_iter(row), 0) for row in rows]
        return result

Se você estiver interessado em ver minhas tentativas de uma e duas, fico feliz em agradecer.

Editar: para o leitor casual, substitua qualquer ocorrência de $ PROJECTNAME $ pelo nome real do seu projeto rápido (conforme especificado em quickly create).

HTH!


Isso funciona muito bem e parece bastante claro, portanto as outras duas tentativas não são necessárias, mas obrigado novamente por experimentá-las ... Como sua resposta é muito longa, mas ainda clara, convém estendê-la para um tutorial completo aqui: developer.ubuntu.com/resources/tutorials/all De qualquer forma: obrigado novamente!
Xubuntix #

@xubuntix Essa é uma ideia interessante, vou dar uma olhada nela. Obrigado pelo link e pelo representante!
mwalsh

0

Eu não tentei 'rapidamente', mas com a minha experiência no GTK, usaria os botões de opção para lidar com a seleção de idiomas.

Observar o toggledevento junto com o button.get_active()método deve ser suficiente para verificar o que o usuário selecionou.


Seguindo sua sugestão, olhei novamente para os botões de opção, mas isso não parece ideal: como a lista de idiomas possíveis é muito mais longa do que os botões de opção, a única alternativa seria ter um widget separado que adiciona botões de opção adicionais, e todos os botões de opção estão sempre ativos. Isso não parece tão legal.
Xubuntix 17/10

Verifique se você está usando os grupos de rádio corretamente. Além disso, o toggledevento pode ser usado para botões selecionados e não selecionados, é por isso que deve ser suficiente.
Alexandre

O que eu quis dizer é: ter 200 botões de opção não é uma boa interface de usuário. O que eu preciso é de uma maneira de armazenar uma lista na qual os itens possam ser adicionados e removidos sob demanda.
Xubuntix 18/10
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.