Tenga en cuenta: no quiero la ayuda de codificación aquí, estoy Programmers
por una razón. Quiero mejorar mis habilidades de planificación / escritura del programa, no (solo) mi comprensión de Java .
Estoy tratando de descubrir cómo hacer un árbol que tenga un sistema de categorías arbitrarias, basado en las habilidades enumeradas para este juego LARP aquí . Mi intento anterior tuvo un efecto negativo sobre si una habilidad también era una categoría. Intentar codificar eso fue desordenado. Al dibujar mi árbol, noté que solo mis 'hojas' eran habilidades y había etiquetado a los demás como categorías.
Lo que busco es una forma de hacer un árbol que intente separar el Modelo y la Vista, y permita agregar un tipo arbitrario de nodo hijo (con una forma separada de ser editado / renderizado) a un padre arbitrario.
Nota: aquí todo se compra como una habilidad, incluso donde parece una propiedad. Los usuarios finales verán esto como habilidades de compra (que hacen en cajeros automáticos en papel), por lo que deben presentarse como tal, todo en la misma página.
Explicación del árbol: El árbol 'nace' con un conjunto de categorías codificadas de más alto nivel ( armas, física y mental, médica y más, etc.). A partir de esto, el usuario debe poder agregar una habilidad. En última instancia, quieren agregar la habilidad 'Especialización en espada de una mano' ( no elemento) por ejemplo. Para hacerlo, idealmente haga clic en 'agregar' con Weapons
seleccionado y luego seleccione One-handed
de un nodo de cuadro combinado que aparece en ese elemento secundario, luego haga clic en agregar nuevamente e ingrese un nombre en un campo de texto en ese nodo secundario que aparece. Luego haga clic en agregar nuevamente para agregar / especificar un 'nivel' o 'nivel' para esa hoja; primero competencia, luego especialización (por ejemplo).
Por supuesto, si quieres comprar una habilidad diferente, es una ruta completamente diferente a la hoja. Es posible que no necesite un cuadro combinado en el mismo nivel en el árbol como lo hizo con el ejemplo del arma, y también necesita alguna otra lógica detrás de él. Esto es lo que estoy teniendo problemas para entender y mucho menos programar; cómo hacer un conjunto de clases y no especificar en qué orden unirlas, pero aun así tenerlas en forma.
¿Cuál es un buen sistema para describir este tipo de árbol en código? Todos los otros ejemplos de JTree que he visto tienen un patrón predecible , y el mío no . No quiero tener que codificar todo esto en 'literales', con largas listas de qué tipo (cuadro combinado, campo de texto, etc.) del nodo secundario se debe permitir en qué padre. ¿Debo estar usando clases abstractas? Interfaces?
¿Cómo puedo hacer que este tipo de grupo de objetos sea extensible cuando agrego otras habilidades no mencionadas anteriormente que se comportan de manera diferente?
Si hay no un sistema bueno para el uso, ¿hay un proceso bueno para trabajar la manera de hacer este tipo de cosas?
Los engranajes en mi cabeza están girando:
Siempre necesito:
- Verifica al padre
- Proporcionar opciones basadas en el padre
Estoy comenzando a pensar debido a esta comunidad. Necesito algún tipo de clase abstracta / interfaz skill
que defina / describa métodos comunes para la habilidad y la categoría. Puedo (con suerte) poner reglas y opciones en una base de datos y leer desde allí. La pregunta es, creo, ahora, entre un método abstracto o de interfaz y cómo implementarlo.
fuente
Respuestas:
Ejemplo simple de JTree mutable
Código (cumplido y probado con Java 7 para hacer la imagen de arriba):
Un agradecimiento especial a este tutorial de JTree
Actualización: Discusión de posibles soluciones
Hay un tutorial sobre cómo hacer un árbol dinámico , usando botones en la parte inferior del marco para agregar / Eliminar / Borrar nodos.
Para los cuadros combinados y tal, desea tomar objetos de la clase swing adecuada y hacer que sean algo así como un JComboBox que implementa java.swing.tree.MutableTreeNode. El Java Swing Tutorial tiene una lista de controles .
Aún debe crear un elemento de interfaz de usuario para permitir que las personas elijan qué tipo de nodo desean agregar y editar el nodo. Si agregan un cuadro combinado, deberán poder definir qué opciones tendrá disponible el cuadro.
Necesita un modelo de datos subyacente para guardar sus datos. Puede usar el esquema de serialización predeterminado integrado en todos los objetos Java, pero es solo para la creación de prototipos: se romperá si alguna vez cambia el código de su programa. Deberá usar una base de datos con JDBC o JPA o deberá escribir sus propias rutinas de serialización (o usar una biblioteca que maneje la serialización por usted) usando algo como JSON o XML como formato de almacenamiento.
Actualización: solución propuesta con descripción general del proyecto
La solución más simple podría ser olvidarse de las bases de datos y crear primero la expresión XML de los datos, luego editar el archivo XML y simplemente mostrar los resultados como un JTree sin cuadros combinados especiales ni nada. Creo que esto es lo que Chibueze Opata estaba sugiriendo con su respuesta. Una representación XML parcial de este árbol podría tener el siguiente aspecto:
Aquí hay algunos hitos potenciales para usted:
Asegúrese de guardar una copia de seguridad de su programa cada vez que funcione al final de cada hito. Un sistema de control de fuente instalado en otra máquina es ideal para esto. Puede usar github, sourceforge o algún otro control de fuente pública si no le importa compartir su código y no desea configurar un servidor con control de fuente.
Cualquiera de estas soluciones es mucho trabajo, y definitivamente más grande que un proyecto para principiantes. Significa que pasará mucho más tiempo aprendiendo Java Swing y XML o JSON que jugando su LARP, por eso exploré por primera vez las opciones de hacer las herramientas existentes. Pero la mejor manera de aprender algo es la forma en que está más motivado para aprender. Entonces este puede ser un proyecto perfecto para ti.
Espero que eso ayude.
fuente
No creo que JTree sea la representación correcta para el problema que está tratando de resolver. Miré su sitio web y veo listas de cosas. Este es un gran comienzo, pero creo que hay un diseño de datos subyacente que puede tener, pero no lo veo.
La vida y la fuerza me parecen atributos del personaje. Los valores de aspecto Doble, Triple y Cuádruple para el atributo Fuerza. Entonces veo habilidades divididas en Arma y Medicina. Pienso en las armas como posesiones (que puedes comprar, encontrar o soltar), y supongo que la habilidad es lo que te permite ser efectivo con un arma determinada. Pero desde mi punto de vista, las armas y la medicina no tienen habilidades, el personaje sí. De hecho, sospecho fuertemente que el personaje es la figura central en su diseño de datos.
Aquí hay tres objetos de datos que me destacan de su diseño hasta ahora:
Ahora un personaje puede tener armas y habilidades, pero para un ataque realmente bueno, necesita una habilidad específica para el arma que está usando. En cualquier caso, hay relaciones de uno a muchos aquí (un personaje puede tener muchas habilidades). Pero todavía no veo árboles.
Tome un bloc de papel y en la primera página coloque al personaje en el medio de la página y enumere los 5-10 objetos más importantes del mundo del juego a su alrededor. Averigua qué datos son simplemente un atributo de otro objeto (como que la Vida y la Fuerza son partes inseparables del personaje) y cuáles son las relaciones más importantes entre los objetos, sin pensar en árboles, campos de texto o cuadros combinados. Dibuje líneas entre los objetos para representar las relaciones. Luego descubra qué relaciones son 1: 1, cuáles son 1: muchas y cuáles son muchas: muchas y etiquételas. Puede haber "has-a" y "is-a" y otros tipos de relaciones también.
Puede decidir que necesita representaciones separadas para un WeaponSkill vs. HealingSkill vs. ManufactureSkill. O puede decidir que son tan similares que pertenecen a una tabla de Habilidad (en mi ejemplo anterior) con un campo que determina qué tipo de habilidad es.
Es una buena señal de que no está satisfecho con sus intentos hasta ahora, significa que está dispuesto a considerar muchas posibilidades antes de elegir una. Cuantos más bocetos considere, mejor será su diseño final. Finalmente, el mejor se convertirá en su diagrama de datos. Cuando eso esté bastante bien resuelto, puede volver a pensar en "cuadros combinados" o "campos de texto", pero dejaría las decisiones de IU hasta el final.
En lugar de mirar JTrees, te sugiero que veas los temas de estructuras de datos, diseño de bases de datos y tal vez modelado de datos. EDITAR-> ¡O mejor aún diagramas de mapeo entidad-relación como sugirió David Kaczynski! <-EDIT Si obtiene el diseño de datos correcto, entonces Java y la UI fluirán de él de forma obvia y natural. Pero si te equivocas, entonces ninguna cantidad de Java-kung-fu o UI-beauty lo solucionará.
¡Buena suerte!
fuente
Me voy a centrar en el modelo de objetos.
Creo que por la flexibilidad que desea, probablemente desee separar sus clases en una capa de conocimiento (quizás "definición" es una mejor palabra en este caso) y una capa de transacción. Por "capa" realmente me refiero a separarlos lógicamente en tu cabeza. La capa de conocimiento contiene su definición de cómo diseñar el árbol, y los datos provienen de un diseñador de juegos y la capa de datos almacena elecciones particulares para un personaje en particular.
Su nivel de conocimiento será al menos un poco desordenado, porque está tratando de hacer un juego genial en lugar de un modelo matemáticamente limpio.
Intentando organizar lo que tienes hasta ahora, creo que tienes una clase SkillDefinition que tiene una propiedad Parent de tipo SkillDefinition. También tiene subclases de SkillDefinition (que pueden convertirse en entradas en una tabla DEF_SkillType en la base de datos) para cubrir algunos casos.
Parece que "Armas", "Físico y mental" y "Médico" no tienen más que un título (y habilidades infantiles).
"One Handed", "Strength" y "Bind Wounds" parecen tener un cuadro combinado asociado (que significa algo así como una tabla DEF_SkillChoice en la base de datos con una clave foránea para DEF_Skill). Sword and Bow parece ser una cadena definida por el usuario (por lo que no hay una tabla asociada a nivel de conocimiento, pero los datos se almacenarán en la capa de transacción).
La "vida" parece tener un número entero asociado. Es posible que no pueda compartir esta clase con ninguna característica futura que use un número entero, porque existe un comportamiento implícito sobre cómo se incrementa el número entero. En cualquier caso, actualmente necesita su propia clase.
"Espada", "Arco", "Fuerza" y "Heridas de unión" parecen tener niveles asociados de habilidad progresiva debajo de ellos en el árbol. En el caso de "Sword" y "Bow", esos niveles están realmente asociados con su habilidad principal. Creo que necesita una clase ProgressiveSkillDefinition con una colección ordenada de valores legales (tabla DEF_SkillLevel con clave externa para DEF_Skill. En el nivel de conocimiento no está completamente claro qué reglas está modelando. Si la "competencia" y la "especialización" siempre están disponibles para todas las armas, es posible que tenga una tabla DEF_SkillLevel con los registros de "competencia" y "especialización" que tengan claves foráneas para el registro de "Armas".
Esto cubre lo que tiene saber a nivel de conocimiento. El nivel de transacción (¿quizás "nivel de personaje" sería un nombre mejor?) Solo apunta al nivel de conocimiento apropiado. Entonces, en tu ejemplo, tendrías un objeto Character con un objeto Skills que tiene una colección de habilidades, solo las que realmente tiene.
Entonces, el personaje tendría una habilidad "Competencia" cuyo padre es la habilidad "espada" y cuyo tipo es Skill_Level. En la base de datos, el registro TRANS_SkillDefinition tiene una clave foránea para el registro de habilidad "espada" transaccional y el registro de nivel de conocimiento DEF_SkillLevel con el nombre "Proficiency".
La habilidad de habilidad tendría un objeto padre de la habilidad "espada", del tipo Skill_UserNamed. En la base de datos esto no tendría una clave foránea para el nivel de conocimiento, porque no hay nada especial definido para "espada" (es el nombre del usuario). Sin embargo, también tiene una clave externa para el registro transaccional principal, por lo que hay más información disponible a través de él.
El objeto de habilidad "espada" tiene un objeto padre de "una mano", porque el usuario eligió poner "espada" en la categoría "una mano". Este es un objeto de tipo SkillCategory. En la base de datos tiene una clave foránea para la tabla DEF_SkillChoice para el registro "con una sola mano", y no tiene un elemento principal transaccional porque todos los datos adicionales para esta habilidad se almacenan en el nivel de conocimiento.
Al construir el árbol inicial para un nuevo personaje, solo se necesita consultar el nivel de conocimiento. Para completar las elecciones realizadas para un personaje se requiere el nivel transaccional.
Necesitará código para traducir el modelo de objeto en un árbol y viceversa. Debería estar claro, espero, lo que debe hacer: cada tipo en la capa de conocimiento tendrá un conjunto asociado de controles en el árbol, que obtiene datos apropiados para ese tipo.
Más adelante, es posible que desee clases para cada opción en los registros de SkillCategory (si "Especialización" tiene un comportamiento asociado, el código tiene que ir a algún lado), pero aún no lo necesita para este árbol, y este diseño será compatible con ese. Solo tendrá que tener una fábrica que use la información del nivel de conocimiento para construir el objeto correcto.
fuente
Después de todo, siempre terminamos administrando estructuras jerárquicas, ya sea una jerarquía de clases de un programa, o el programa en sí construido a partir de diferentes módulos que lo conectan a un "mundo interno" (GUI, conexión de base de datos, lógica de negocios vinculada a datos, etc.) . Pero esta es la filosofía, ¿cómo debería funcionar en su caso?
Tiene nodos en este árbol, cada elemento es una "instancia de objeto"; mientras que su comportamiento (donde puede colocarlos, la lista de nodos secundarios permitidos, etc.) es común para algunos conjuntos, como "clases". Sí, esto es como un código de programa. Si conoce la reflexión de Java lo suficiente, incluso puede usar clases POJO y jerarquía de herencia para construir este componente, con un contenedor IoC o un mecanismo de fábrica para construir las instancias reales. Pero creo que no quieres eso, porque es un hackeo de lenguaje pesado, así que ...
Primero, cree un objeto de "clase" que describa el comportamiento de los elementos. Contiene el identificador de clase, los nombres de "campo" y los tipos permitidos y el recuento de elementos, etc. Ejemplo: la clase "raíz" es "Propiedades del jugador", tiene el campo "Físico / Mental", "Médico", "Armas". Este tipo es "final": en este momento no quieres tener diferentes tipos de jugadores. Sugerencia: más adelante puede hacerlo, utilizando las mismas herramientas para manejar "monstruos no humanos" ... :-)
El campo "Médico" es
Al contrario: no se requiere miembro de armas, debe crearse cuando se agrega la primera arma a su jugador. Esto significa: cuando "edita" su "objeto" (ahora el jugador) y desea permitirle agregar un nuevo elemento, no debe limitar la selección por las propiedades reales de la instancia (que ahora no contiene "Armas" "), pero muestra todos los campos de la definición de clase y crea perezosamente el nuevo campo (nodo secundario) cuando se usa por primera vez. Esto creará un entorno extensible. Más tarde, puede agregar el campo "Amigos" con múltiples jugadores ... er ... referencias (ver más adelante).
Siga el proceso con las "clases" reales. Te ayudará a refinar tus ideas, como: parece mejor separar los tipos de armas (espadas, dagas, arcos, ...), manejar municiones de alguna manera (sabiendo que tal vez el jugador NO tiene un arco pero puede recoger flechas, pero usando ciertas armas requieren y disminuyen la munición, algunas se pueden encontrar, otras se pierden ...) en la clase "Armas": es más fácil de inspeccionar, y también muestra si tu jugador solo lleva ese objeto o también puede usarlo ( tiene las habilidades). Por otro lado: seguramente cambiarás esta estructura más adelante, a medida que desarrolles tu juego.
Cree una "tienda de clase" disponible a nivel mundial que inicialice cuando comience su juego, y sirva las definiciones de clase cuando alguien se refiera a su nombre. Los objetos de clase def deben ser inmutables en este caso.
Los "objetos" son más fáciles: se pueden derivar de la misma clase raíz que contiene una referencia a la definición de clase y también acceso genérico a los campos. Quizás use un HashMap para contener esos elementos secundarios, identificados por el nombre del campo. Recuerde: algunos de esos campos contienen un solo objeto, otros un conjunto de objetos. Estas instancias son mutables, por supuesto.
Ahora para la interfaz. Primero, debe consultar el tutorial de JTree ... , y ahora debería ser obvio. Cada "objeto" puede ser representado por un DefaultMutableTreeNode, el "userObject" del nodo debe ser su objeto (creo que toString () de ese nodo se muestra como la etiqueta del nodo, pero puede crear un formateador de celda personalizado). Cada vez que abre un nodo, navega por los campos del objeto y crea nodos secundarios debajo del padre (si desea hacerlo dinámicamente), o navega por todo el árbol y construye la estructura TreeNode cuando muestra el JTree (pista: allí es un constructor JTree con un parámetro TreeNode).
Cuando selecciona un nodo en el árbol, tiene la instancia de Object. Por su clase, puede mostrar un panel de editor adecuado, o uno genérico generado por la definición de clase (como: paneles de pestañas con los campos, editores para el campo real por la declaración de campo: un botón que crea un hijo del tipo adecuado de le permite seleccionar una de las clases disponibles; y campos de editor para esa instancia, como propiedades de armas). Después de modificar la estructura, debe actualizar el árbol en sí mismo: el TreeModel y su función fuego ... cambiar son sus amigos.
¿Se ve bien? O muy complejo? Bueno, esta es una pequeña fracción de la historia. No he hablado de
De todos modos, espero que puedas usar algo de esta sesión de calentamiento.
fuente
No voy a darle una respuesta larga, pero me he enfrentado a este tipo de situación antes y, francamente, dejé de intentar usar cualquier estructura de datos existente. Simplemente creé mi propio objeto que podría aceptar nuevos padres e hijos similares a un Nodo XML.
Sin embargo, en su caso, creo que usar una clase Xml ayudará. Luego puede tener propiedades para cada nodo que le pueden decir si una clase es una habilidad y puede obtener fácilmente padres e hijos de cualquier nodo que desee usar en un cuadro combinado o de otra manera.
Además, me gustaría agregar que no debes huir de la idea de tener muchos textos / cadenas. Los juegos generalmente involucran IA, y la IA generalmente involucra muchos textos.
fuente