Por que cada widget precisaria de uma referência ao pai em um sistema simples de widgets?

8

Estou trabalhando em um sistema de widgets simples (janela única, tamanho fixo). Cada widget recebe seu pai (ou seja, o widget que o contém) passado para o construtor - exceto o widget raiz, que eu chamei de Tela .

Tenho algumas dúvidas se essa abordagem faz sentido. Eu fiz isso porque a maioria dos sistemas de widgets que eu costumava fazer antes (Qt, GTK, ...), mas percebi que estes são um pouco mais complexos que o meu:

  • Não tenho redimensionamento de janela
  • Não pretendo dimensionar recipientes com base no tamanho de seus filhos
  • Acho que não preciso dele para gerenciamento de memória (estou usando C ++), posso usar ponteiros compartilhados (basicamente como funcionaria em Java)

Existe alguma razão para um widget precisar de uma referência ao seu pai?

É uma grande refatoração mudar isso. Portanto, antes de prosseguir e implementar contêineres e layouts, quero ter uma boa idéia se vou precisar desse pai ou não.

Edit: Por favor, note que os pais sabem todos os seus filhos de qualquer maneira, eu só estou me perguntando se os filhos precisam conhecer os pais também.

futlib
fonte

Respostas:

5

Como você apontou, o filho em si raramente precisa acessar o pai, contanto que ele faça todo o trabalho e acompanhe seus filhos. No entanto, o clássico getParenté mais útil quando você usa a estrutura de fora.

Cenário

Uma operação simples que pode causar problemas é a seguinte: dados dois widgets concretos que estão em algum lugar da sua árvore geral de widgets e um caso de uso que exige que você troque esses dois, como funciona a troca?

Opção 1: diga às crianças

Diga ao seu widget filho para swap(withOtherChild). Mas a troca envolve atualizar a estrutura de dados dos filhos dos pais de alguma forma. Como seu filho não conhece seus pais, como conseguir isso?

Opção 2: informe aos pais

Diga aos pais de uma criança para removê-lo e adicione o outro. Oh espere, mesmo problema. Você só tem objetos filhos e não há getParentneles.

Opção 3: trabalho pesado

Como opção final, você pode percorrer toda a árvore de widgets para encontrar um pai com hasChild(x)e outro com hasChild(y)e depois voltar para a opção 2.

Solução

Você deve manter o pai, se desejar construir grandes árvores de widgets e executar operações que exijam mover a posição de um widget na árvore. Se suas árvores de widgets forem muito pequenas ou tiverem uma profundidade muito pequena, mas hasChildacessadores rápidos , a opção 3 poderá ser aceitável para você e você poderá omitir a referência pai.

Referências em estruturas de dados em geral

O que você planeja fazer aqui é criar uma estrutura de dados para uma árvore. Vamos considerar uma simplificação e, por uma questão de argumento, suponha que todo widget possa ter apenas um filho. O resultado, é claro, é uma lista e sua pergunta agora se torna "eu deveria ter uma lista com um ou dois links?".

E, assim como as listas, não há resposta definitiva, mas apenas prós e contras. Os profissionais óbvios para o link único (ou seja, nenhuma referência aos pais) são a) mais fáceis de implementar eb) menos memória. Mas os contras incluem: a) algumas operações tornam-se lentas porque precisam atravessar a estrutura eb) não ter acesso fácil a essas operações pode significar que a estrutura de dados é difícil de usar ec) usa mais memória.

Por outro lado, a variante de dupla ligação, ou seja, com referência aos pais, praticamente inverte esses prós e contras.

Porém, em termos de uma biblioteca / estrutura da GUI, os limites de memória geralmente não são um problema que proíbe os indicadores-pai. Se você excluir isso e perceber que é uma biblioteca / estrutura, e, portanto, é preferível que seja difícil de implementar, mas fácil de usar, então você basicamente exclui os profissionais acima de uma abordagem de vínculo único.

Não conheço as peculiaridades do seu projeto, por isso não pretendo dizer para você manter a referência dos pais, pois alguns dos meus argumentos acima podem não se aplicar ao seu caso. Em geral, no entanto, considero que as referências pai em uma estrutura de dados de widget valem a pena pelas razões acima.

Frank
fonte
2

Na maioria desses casos, existe alguma comunicação entre pais e filhos em caso de eventos, sinais ou mudança de estado (ou simplesmente destruir filhos quando necessário). Por exemplo, uma caixa de agrupamento pode lidar com os botões de opção contidos para garantir que apenas um deles esteja "ativado" em um determinado momento.

Você pode ou não planejar ter funcionalidades desse tipo. Pessoalmente, duvido que um sistema de widget sem ele valha o tempo, pois não ofereceria muito. Mas então eu simplesmente usaria uma das soluções existentes de qualquer maneira.

thorsten müller
fonte
1
Tudo isso parece possível quando os pais conhecem seus filhos, o que é o meu caso. Só estou me perguntando se a criança precisa conhecer os pais também.
Futlib #
Eu usaria felizmente algo existente, mas estamos em um ambiente bastante único aqui e imaginamos que nosso próprio sistema simples é a melhor abordagem.
Futlib #
Sempre há razões, é claro, e o Qt, por exemplo, é bastante pesado. A razão pela qual a criança precisa conhecer seu pai é principalmente para que possa se registrar com ele na criação ou depois enviar alterações de estado.
Thorsten Müller
Você quer dizer que quando um botão de opção é clicado, ele precisa informar o pai ou a mãe para que possa desmarcar a opção anteriormente marcada. Sim, acho que seria difícil sem a conexão filho-> pai ... Você consegue pensar em outros exemplos?
Futlib #
2
"Baseado em tamanho e posição" pode deixar você com um código realmente desagradável. Eu preferiria apresentar eventos. Assim como o pai recebe o evento, ele "pergunta" a seus filhos se eles são responsáveis, o que eles decidem com base em suas próprias informações de posição e tamanho. Outros exemplos? Depende da complexidade dos seus widgets. Você diz que eles não serão tão complicados. Mas, por outro lado: se você adicionar o ponteiro pai desde o início, não vai doer muito e você os terá quando precisar. As barras de rolagem são outro bom exemplo, eu acho. Eles relatam a rolagem para o pai, o pai informa a exibição para atualizar.
Thorsten Müller
2

Eu diria que, quando as crianças conhecem seus pais, um widget e todos os seus ancestrais formam uma cadeia de responsabilidades . Um exemplo típico é um evento de mouse recebido por um widget: o widget pode consumir o evento (e reagir adequadamente) ou transmitir o evento ao pai, que pode consumir ou transmitir ao pai, etc.

No caso de Qt, cada widget recebe seu pai pelo construtor, e isso indica que o widget pertence ao pai. Em particular, a exclusão do pai aciona a exclusão do widget.

barjak
fonte