Observação: não quero ajuda de codificação aqui, estou ativada Programmers
por um motivo. Quero melhorar minhas habilidades de planejamento / gravação de programas e não (apenas) meu entendimento de Java .
Estou tentando descobrir como fazer uma árvore com um sistema de categorias arbitrário, com base nas habilidades listadas para este jogo LARP aqui . Minha tentativa anterior teve um problema para saber se uma habilidade também era uma categoria. Tentando codificar isso foi confuso. Ao desenhar minha árvore, notei que apenas minhas 'folhas' eram habilidades e rotulei as outras como categorias.
O que eu busco é uma maneira de criar uma árvore que tente separar Model e View e permitir adicionar um tipo arbitrário de nó filho (com uma maneira separada de ser editada / renderizada) a um pai arbitrário.
NB Tudo aqui é comprado como uma habilidade, mesmo onde parece uma propriedade. Os Usuários Finais verão isso como habilidades de compra (o que eles fazem no caixa eletrônico); portanto, devem ser apresentados como tal, todos na mesma página.
Explicação da árvore: A Árvore "nasce" com um conjunto de categorias de nível superior codificadas ( Armas, Físico e Mental, Médico e mais, etc.). A partir disso, o usuário precisa poder adicionar uma habilidade. Por fim, eles querem adicionar a habilidade 'Especialização em espada com uma mão' ( não o item), por exemplo. Para fazer isso você teria idealmente clique em 'add', com Weapons
selecionada e, em seguida, selecionar One-handed
a partir de um nó combobox que aparece em que a criança, em seguida, clique em Adicionar novamente e digite um nome em um campo de texto em que nó filho que aparece. Em seguida, clique em adicionar novamente para adicionar / especificar um 'nível' ou 'camada' para essa folha; primeira proficiência, depois especialização (por exemplo).
Obviamente, se você quiser comprar uma habilidade diferente, é uma rota completamente diferente. Você pode não precisar de uma caixa de combinação no mesmo nível abaixo da árvore, como fez com o exemplo de arma, e também precisa de alguma outra lógica por trás dela. É isso que estou tendo problemas para entender, e muito menos programar; como criar um conjunto de classes e não especificar em que ordem anexá-las, mas ainda assim elas devem se encaixar.
Qual é um bom sistema para descrever esse tipo de árvore no código? Todos os outros exemplos de JTree que eu já vi têm algum padrão previsível , e o meu não . Eu não quero ter que codificar tudo isso em 'literais', com longas listas de que tipo (caixa de combinação, campo de texto etc.) do nó filho devem ser permitidas em qual pai. Devo estar usando classes abstratas? Interfaces?
Como posso tornar esse tipo de agrupamento de objetos extensível quando adiciono outras habilidades não listadas acima que se comportam de maneira diferente?
Se houver não um sistema bom para uso, há um processo bom para trabalhar fora como fazer esse tipo de coisa?
As engrenagens na minha cabeça estão girando:
Eu sempre preciso:
- Verifique os pais
- Forneça opções com base no pai
Estou começando a pensar que, por causa dessa semelhança, preciso de algum tipo de skill
classe abstrata / interface que defina / descreva métodos comuns de habilidade e categoria. Eu posso (espero) colocar regras e opções em um banco de dados e ler de lá para cá. A questão é que penso agora, entre um método abstrato ou de interface e como implementar isso.
fonte
Respostas:
Exemplo simples de JTree mutável
Código (cumprido e testado com Java 7 para criar a imagem acima):
Agradecimentos especiais a este tutorial do JTree
Atualização: discussão de possíveis soluções
Há um tutorial sobre como criar uma árvore dinâmica , usando os botões na parte inferior do quadro para adicionar / remover / limpar nós.
Para caixas de combinação e afins, você deseja pegar objetos da classe swing apropriada e fazer com que sejam algo como um JComboBox que implementa java.swing.tree.MutableTreeNode. O Java Swing Tutorial tem uma lista de controles .
Você ainda precisa criar um elemento de interface com o usuário para permitir que as pessoas escolham qual tipo de nó eles desejam adicionar e editar o nó. Se eles adicionarem uma caixa de combinação, eles deverão poder definir quais opções a caixa disponibilizará.
Você precisa de um modelo de dados subjacente para salvar seus dados. Você pode usar o esquema de serialização padrão incorporado em todos os objetos Java, mas é apenas para prototipagem - ele será interrompido se você alterar o código do programa. Você precisará usar um banco de dados com JDBC ou JPA ou escrever suas próprias rotinas de serialização (ou usar uma biblioteca que lide com a serialização) usando algo como JSON ou XML como formato de armazenamento.
Atualização: solução proposta com visão geral do projeto
A solução mais simples pode ser esquecer os bancos de dados e criar a expressão XML dos dados primeiro, depois editar o arquivo XML e apenas exibir os resultados como um JTree sem caixas de combinação especiais ou qualquer coisa. Eu acho que é isso que Chibueze Opata estava sugerindo com sua resposta. Uma representação XML parcial dessa árvore pode se parecer com o seguinte:
Aqui estão alguns marcos em potencial para você:
Certifique-se de salvar um backup do seu programa sempre que ele funcionar no final de cada etapa. Um sistema de controle de origem instalado em outra máquina é ideal para isso. Você pode usar o github, o sourceforge ou algum outro controle de fonte pública, se não se importar em compartilhar seu código e não desejar configurar um servidor com controle de origem.
Qualquer uma dessas soluções é muito trabalhosa e definitivamente maior que um projeto iniciante. Isso significa que você gastará muito mais tempo aprendendo Java Swing e XML ou JSON do que executando seu LARP, e foi por isso que eu explorei as opções de se contentar com as ferramentas existentes. Mas a melhor maneira de aprender qualquer coisa é a maneira que você está mais motivado para aprender. Portanto, este pode ser um projeto perfeito para você.
Espero que ajude.
fonte
Não acho que o JTree seja a representação correta para o problema que você está tentando resolver. Eu olhei para o seu site e vejo listas de coisas. Este é um ótimo começo, mas acho que você pode ter um design de dados subjacente, mas não estou vendo.
Vida e Força parecem atributos de caráter para mim. Duplo, Triplo e Quádruplo parecem valores para o atributo Força. Então eu vejo habilidades divididas em Arma e Medicina. Penso em armas como posses (que você pode comprar, encontrar ou largar), e presumo que a habilidade é o que lhe permite ser eficaz com uma determinada arma. Mas do jeito que eu vejo, as armas e os remédios não têm habilidades, o personagem tem. Na verdade, eu suspeito fortemente que o Personagem seja a figura central no seu design de dados.
Aqui estão três objetos de dados que me destacam do seu design até agora:
Agora, um personagem pode ter armas e habilidades, mas para um ataque realmente bom, ele precisa de uma habilidade específica da arma que está usando. De qualquer forma, existem relacionamentos um-para-muitos aqui (um personagem pode ter muitas habilidades). Mas ainda não estou vendo árvores.
Pegue um bloco de papel e, na primeira página, coloque o personagem no meio da página e liste os 5 a 10 objetos mais importantes do mundo do jogo ao seu redor. Descubra quais dados são meramente um atributo de outro objeto (como Vida e Força são partes inseparáveis do personagem) e quais são as relações mais importantes entre os objetos, sem pensar em árvores, campos de texto ou caixas de combinação. Desenhe linhas entre os objetos para representar relacionamentos. Em seguida, descubra quais relacionamentos são 1: 1, quais são 1: muitos e quais são muitos: muitos e os rotule. Pode haver "tem um" e "é um" e outros tipos de relacionamento também.
Você pode decidir que precisa de representações separadas para um SkillSkill vs.HealingSkill vs. ManufactureSkill. Ou você pode decidir que eles são tão parecidos que pertencem a uma tabela de habilidades (no meu exemplo acima) com um campo que determina qual tipo de habilidade é.
É um bom sinal de que você não está satisfeito com suas tentativas até agora - significa que você está disposto a considerar muitas possibilidades antes de escolher uma. Quanto mais esboços você considerar, melhor será o seu design final. Eventualmente, o melhor se tornará seu diagrama de dados. Quando isso estiver bem resolvido, você poderá voltar a pensar em "caixas de combinação" ou "campos de texto", mas eu deixaria as decisões da interface do usuário no final.
Em vez de examinar o JTrees, sugiro que você analise os tópicos de estruturas de dados, design de banco de dados e talvez modelagem de dados. EDIT-> Ou melhor ainda , diagramas de mapeamento de relacionamento com entidades, como sugeriu David Kaczynski! <-EDIT Se você acertar o design dos dados, o Java e a UI fluirão obviamente e naturalmente. Mas se você errar, nenhuma quantidade de Java-kung-fu ou UI-beauty o consertará.
Boa sorte!
fonte
Vou focar no modelo de objeto.
Eu acho que, pela flexibilidade que você deseja, provavelmente deseja separar suas classes em uma camada de conhecimento (talvez "definição" seja uma palavra melhor nesse caso)) e uma camada de transação. Por "camada", quero dizer apenas separá-los logicamente na sua cabeça. A camada de conhecimento contém sua definição de como organizar a árvore, e os dados nela vêm de um designer de jogos e a camada de dados armazena opções específicas para um personagem em particular.
Seu nível de conhecimento será pelo menos um pouco confuso, porque você está tentando criar um jogo interessante, em vez de um modelo matematicamente limpo.
Tentando organizar o que você tem até agora, acho que você tem uma classe SkillDefinition que possui uma propriedade Parent do tipo SkillDefinition. Você também tem subclasses de SkillDefinition (que podem se tornar entradas em uma tabela DEF_SkillType no banco de dados) para cobrir alguns casos.
"Armas", "Físico e Mental" e "Médico" parecem ter apenas um título (e habilidades para crianças).
"One Handed", "Strength" e "Bind Wounds" parecem ter uma caixa de combinação associada (o que significa algo como uma tabela DEF_SkillChoice no banco de dados com uma chave estrangeira para DEF_Skill). Sword e Bow parecem ser uma string definida pelo usuário (portanto, nenhuma tabela associada no nível de conhecimento, mas os dados serão armazenados na camada de transação).
"Vida" parece ter um número inteiro associado a ela. Talvez não seja possível compartilhar essa classe com quaisquer características futuras que usem um número inteiro, porque existe um comportamento implícito em como o número inteiro é incrementado. De qualquer forma, atualmente ele precisa de sua própria classe.
"Sword", "Bow", "Strength" e "Bind Wounds" parecem todos ter níveis associados de habilidade progressiva abaixo deles na árvore. No caso de "Sword" e "Bow", esses níveis estão realmente associados à habilidade dos pais. Eu acho que você precisa de uma classe ProgressiveSkillDefinition com uma coleção ordenada de valores legais (tabela DEF_SkillLevel com chave estrangeira para DEF_Skill. No nível de conhecimento, não está totalmente claro quais regras você está modelando. Se "proficiência" e "especialização" estão sempre disponíveis para todas as armas, você pode ter uma tabela DEF_SkillLevel com os registros "proficiência" e "especialização" com chaves estrangeiras para o registro "Armas".
Isso cobre o que você sabe em nível de conhecimento. O nível de transação (talvez "nível de caractere" seria um nome melhor?) Apenas aponta para o nível de conhecimento apropriado. Portanto, no seu exemplo, você teria um objeto Personagem com um objeto Habilidades que possui uma coleção de habilidades - apenas as que ele realmente possui.
Assim, o personagem teria uma habilidade "Proficiência" cujo pai é a habilidade "espada" e cujo tipo é Skill_Level. No banco de dados, o registro TRANS_SkillDefinition possui uma chave estrangeira para o registro de habilidade "espada" transacional e o registro DEF_SkillLevel no nível de conhecimento com o nome "Proficiência".
A habilidade de proficiência teria um objeto pai da habilidade "espada", do tipo Skill_UserNamed. No banco de dados, isso não teria uma chave estrangeira para o nível de conhecimento, porque não há nada de especial definido para "espada" (é o nome do usuário). No entanto, ele também possui uma chave estrangeira no registro transacional pai, para que mais informações estejam disponíveis por meio dele.
O objeto de habilidade "espada" possui um objeto pai de "uma mão", porque o usuário optou por colocar "espada" na categoria "uma mão". Este é um objeto do tipo SkillCategory. No banco de dados, ele possui uma chave estrangeira na tabela DEF_SkillChoice para o registro "com uma mão" e nenhum pai transacional, porque todos os dados adicionais para essa habilidade são armazenados no nível de conhecimento.
Ao construir a árvore inicial para um novo personagem, apenas o nível de conhecimento precisa ser consultado. Para preencher as escolhas feitas para um personagem, é necessário o nível transacional.
Você precisará de código para converter o modelo de objeto em uma árvore e vice-versa. Espero que fique claro o que você precisa fazer - cada tipo na camada de conhecimento terá um conjunto associado de controles na árvore, que obtém os dados apropriados para esse tipo.
Posteriormente, você pode querer classes para cada escolha nos registros SkillCategory (se "Especialização" tiver um comportamento associado a ela, o código precisar ir a algum lugar), mas você ainda não precisa disso para essa árvore, e esse design será compatível com isso. Você só precisa ter uma fábrica que use as informações do nível de conhecimento para criar o objeto certo.
fonte
Afinal, sempre terminamos em gerenciar estruturas hierárquicas - seja uma hierarquia de classes de um programa ou o próprio programa construído a partir de diferentes módulos conectando você a um "mundo interno" (GUI, conexão com banco de dados, lógica de negócios vinculada a dados etc.) . Mas isso é filosofia, como deve funcionar no seu caso?
Você tem nós nesta árvore, cada item é uma "instância de objeto"; enquanto o comportamento deles (onde você pode colocá-los, a lista de nós filhos permitidos etc.) é comum em alguns conjuntos, como "classes". Sim, é como um código de programa. Se você conhece o reflexo de Java o suficiente, pode usar classes POJO e hierarquia de herança para construir esse componente, com um contêiner de IoC ou um mecanismo de fábrica para criar as instâncias reais. Mas acho que você não quer isso, porque essa é uma linguagem pesada, então ...
Primeiro, crie um objeto "class" que descreva o comportamento dos itens. Que contém identificador de classe, nomes de "campos" e os tipos e contagem permitidos de itens, etc. Exemplo: a classe "raiz" é "Propriedades do jogador", possui os campos "Físico / Mental", "Médico", "Armas". Esse tipo é "final": agora você não deseja ter tipos diferentes de jogadores. Dica: mais tarde você pode fazê-lo, usando as mesmas ferramentas para lidar com "monstros não humanos" ... :-)
O campo "Médico" é
Ao contrário: o membro das armas não é necessário, deve ser criado quando a primeira arma for adicionada ao seu jogador. Isto significa: quando você "edita" seu "objeto" (agora o jogador) e deseja adicionar um novo item a ele, não deve limitar a seleção pelas propriedades reais da instância (que agora não contém "Armas" "), mas mostre todos os campos da definição de classe e crie preguiçosamente o novo campo (nó filho) quando usado pela primeira vez. Isso criará um ambiente extensível. Posteriormente, você pode adicionar o campo "Amigos" com várias referências de player ... er ... (veja mais adiante).
Siga o processo com as "classes" reais. Isso o ajudará a refinar suas idéias, como: parece melhor separar tipos de armas (espadas, punhais, arcos, ...), manusear munição de alguma forma (sabendo que talvez o jogador NÃO tenha um arco, mas possa coletar flechas, mas usando certas armas exigem e diminuem munição, algumas delas podem ser encontradas, outras são perdidas ...) na classe "Armas": é mais fácil pesquisar e também mostra se o seu jogador apenas carrega esse item ou também pode usá-lo ( tem as habilidades). Por outro lado: você certamente mudará essa estrutura mais tarde, à medida que desenvolve seu jogo.
Crie uma "loja de classe" disponível globalmente que você inicialize quando o jogo iniciar e sirva as definições de classe quando alguém se referir ao nome. Os objetos de classe def devem ser imutáveis nesse caso.
"Objetos" são mais fáceis: eles podem ser derivados da mesma classe raiz que contém uma referência à definição de classe e acesso genérico aos campos também. Talvez use um HashMap para conter esses filhos, identificados pelo nome do campo. Lembre-se: alguns desses campos contêm um único objeto, outros um conjunto de objetos. Essas instâncias são mutáveis, é claro.
Agora para a interface. Primeiro, você deve verificar o tutorial do JTree ... e agora deve ser óbvio. Cada "objeto" pode ser representado por um DefaultMutableTreeNode, o "userObject" do nó deve ser o seu objeto (acho que o toString () desse nó é exibido como o rótulo do nó, mas você pode criar um formatador de célula personalizado). Sempre que você abre um nó, você navega nos campos do objeto e cria nós filhos sob o pai (se desejar fazê-lo dinamicamente) - ou navega na árvore inteira e constrói a estrutura TreeNode quando exibe o JTree (dica: é um construtor JTree com um parâmetro TreeNode).
Quando você seleciona um nó na árvore, você tem a instância Object. Por sua classe, é possível exibir um painel do editor adequado ou um genérico gerado pela definição da classe (como: painéis de guias com os campos, editores do campo real pela declaração de campo: um botão que cria um filho do tipo apropriado permite selecionar uma das classes disponíveis e campos de editor para essa instância, como propriedades da arma). Depois de modificar a estrutura, você deve atualizar a própria árvore - o TreeModel e suas funções de mudança de fogo ... são seus amigos.
Parece legal? Ou muito complexo? Bem, essa é uma pequena fração da história. Eu não falei sobre
De qualquer forma, espero que você possa usar algo dessa sessão de aquecimento.
fonte
Não vou lhe dar uma resposta longa, mas já enfrentei esse tipo de situação antes e, francamente, desisti de tentar usar qualquer estrutura de dados existente. Eu simplesmente criei meu próprio objeto que poderia aceitar novos pais e filhos semelhantes a um Nó XML.
No seu caso, no entanto, acho que usar uma classe Xml ajudará. Você pode ter propriedades para cada nó que podem lhe dizer se uma classe é uma habilidade e você pode facilmente obter pais e filhos de qualquer nó que desejar para uso em uma caixa de combinação ou não.
Além disso, gostaria de acrescentar que você não deve fugir do pensamento de ter muitos textos / strings. Os jogos geralmente envolvem IA, e a IA geralmente envolve muitos textos.
fonte