Пожалуйста, обратите внимание: я не хочу помогать кодированию здесь, я нахожусь по Programmers
причине. Я хочу улучшить свои навыки планирования / написания программ, а не (просто) мое понимание Java .
Я пытаюсь выяснить , как сделать дерево , которое имеет произвольную систему категорий, на основе навыков , перечисленных в этой LARP игру здесь . Моя предыдущая попытка была связана с тем, относится ли навык к категории. Попытка закодировать это было грязно. Рисуя мое дерево, я заметил, что только мои «листья» были навыками, а другие я назвал категориями.
Мне нужен способ создать дерево, которое пытается разделить Model и View, и позволяет добавить произвольный тип дочернего узла (с отдельным способом редактирования / визуализации) к произвольному родителю.
NB. Все здесь покупается как навык, даже если это похоже на собственность. Конечные пользователи увидят в этом навыки покупки (которые они делают на бумажном банкомате), поэтому они должны быть представлены как таковые, все на одной странице.
Объяснение дерева: Дерево «рождено» с набором жестко закодированных категорий высшего уровня ( оружие, физическое и умственное, медицинское и т. Д.). Из этого пользователь должен иметь возможность добавить навык. В конечном итоге они хотят добавить навык « Одноручный меч» ( не предмет), например. Для этого в идеале нужно нажать «добавить» с Weapons
выбранным, а затем выбрать One-handed
из списка в выпадающем списке, который появляется на этом дочернем элементе, затем снова нажать «Добавить» и ввести имя в текстовое поле на этом дочернем узле, который появляется. Затем нажмите «Добавить» еще раз, чтобы добавить / указать «уровень» или «уровень» для этого листа; сначала знание, затем специализация (например).
Конечно, если вы хотите купить другой навык, это совершенно другой путь к листу. Вам может не понадобиться поле со списком на том же уровне вниз по дереву, как вы делали с примером с оружием, и вам нужна другая логика за ним. Это то, что я испытываю проблемы с тем, чтобы не думать о программировании; как сделать набор классов и не указывать, в каком порядке их объединять, но все же они все подходят.
Что такое хорошая система для описания такого рода дерева в коде? Все остальные примеры JTree, которые я видел, имеют предсказуемый паттерн, а мой - нет . Я не хочу кодировать все это в «литералах», с длинными списками того, какой тип (комбинированный список , текстовое поле и т. Д.) Дочернего узла должен быть разрешен для какого родителя. Должен ли я использовать абстрактные классы? Интерфейсы?
Как я могу сделать такой кластер объектов расширяемым, когда я добавлю другие навыки, не перечисленные выше, которые ведут себя по-другому?
Если нет хорошей системы для использования, есть ли хороший процесс для разработки, как делать такие вещи?
Шестерни в моей голове крутятся:
Мне всегда нужно:
- Проверьте родителя
- Предоставить варианты на основе родителя
Я начинаю думать, что из-за этой общности мне нужен какой-то абстрактный skill
класс / интерфейс, который определяет / описывает общие методы для навыков и категорий. Я могу (надеюсь) поместить правила и опции в базу данных и читать там. Вопрос сейчас в том, что я думаю, между абстрактным или интерфейсным методом и как это реализовать.
источник
Ответы:
Простой изменяемый пример JTree
Код (соответствует и протестирован с Java 7 для создания изображения выше):
Особая благодарность этому уроку JTree
Обновление: обсуждение возможных решений
Существует руководство по созданию динамического дерева с использованием кнопок внизу рамки для добавления / удаления / очистки узлов.
Для комбо-блоков и тому подобного вы хотите взять объекты соответствующего свингового класса и сделать их похожими на JComboBox, который реализует java.swing.tree.MutableTreeNode. Учебник по Java Swing имеет список элементов управления .
Вам все еще нужно создать элемент пользовательского интерфейса, чтобы люди могли выбирать, какой тип узла они хотят добавить, и редактировать узел. Если они добавят поле со списком, они должны будут иметь возможность определить, какие варианты будет делать окно.
Вам нужна базовая модель данных, чтобы сохранить ваши данные. Вы можете использовать схему сериализации по умолчанию, встроенную во все объекты Java, но она предназначена только для прототипирования - она сломается, если вы когда-нибудь измените свой программный код. Вам нужно будет либо использовать базу данных с JDBC или JPA, либо вам нужно написать свои собственные процедуры сериализации (или использовать библиотеку, которая обрабатывает сериализацию для вас), используя что-то вроде JSON или XML в качестве формата хранения.
Обновление: предлагаемое решение с обзором проекта
Самым простым решением может быть забыть о базах данных и сначала придумать XML-выражение данных, затем отредактировать XML-файл и просто отобразить результаты в виде JTree без специальных комбинированных полей или чего-либо еще. Я думаю, что это то, что Чибуэзе Опата предлагал своим ответом. Частичное XML-представление этого дерева может выглядеть следующим образом:
Вот несколько потенциальных вех для вас:
Обязательно сохраняйте резервную копию вашей программы каждый раз, когда она работает в конце каждого этапа. Система контроля источника, установленная на другом компьютере, идеально подходит для этого. Вы можете использовать github, sourceforge или какой-либо другой общедоступный элемент управления исходным кодом, если вы не против поделиться своим кодом и не хотите настраивать сервер с контролем исходного кода.
Любое из этих решений - большая работа, и определенно больше, чем начинающий проект. Это означает, что вы потратите гораздо больше времени на изучение Java Swing и XML или JSON, чем на игру в LARP, поэтому я впервые изучил варианты использования существующих инструментов. Но лучший способ научиться чему-либо - это способ учиться у вас больше всего. Так что это может быть идеальным проектом для вас.
Надеюсь, это поможет.
источник
Я не думаю, что JTree - правильное представление о проблеме, которую вы пытаетесь решить. Я посмотрел на ваш веб-сайт, и я вижу списки вещей. Это хорошее начало, но я думаю, что у вас есть базовый дизайн данных, но я его не вижу.
Жизнь и Сила для меня выглядят как атрибуты персонажа. Double, Triple и Quadruple выглядят как значения для атрибута Сила. Затем я вижу навыки, разделенные на оружие и медицину. Я думаю об оружии как об имуществе (которое вы можете купить, найти или выбросить), и я предполагаю, что именно умение позволяет вам быть эффективным с данным оружием. Но, как я смотрю на это, у оружия и лекарств нет навыков, у персонажа есть. На самом деле, я сильно подозреваю, что Персонаж является центральной фигурой в вашем дизайне данных.
Вот три объекта данных, которые до сих пор выделяются из вашего дизайна:
Теперь персонаж может иметь оружие и навыки, но для действительно хорошей атаки ему нужен навык, специфичный для оружия, которое он использует. В любом случае, здесь есть отношения один ко многим (один персонаж может иметь много навыков). Но я пока не вижу деревьев.
Возьмите блокнот и на первой странице поместите персонажа в середину страницы и перечислите 5-10 наиболее важных объектов игрового мира вокруг него. Выясните, какие данные являются просто атрибутом другого объекта (например, «Жизнь и сила» являются неотъемлемыми частями персонажа) и каковы наиболее важные отношения между объектами, не думая о деревьях, текстовых полях или комбинированных полях. Нарисуйте линии между объектами, чтобы представить отношения. Затем выясните, какие отношения 1: 1, 1: многие, а какие много: многие, и пометьте их. Могут быть отношения «есть» и «есть», а также другие виды отношений.
Вы можете решить, что вам нужны отдельные представления для WeaponSkill против HealingSkill против ManufactureSkill. Или вы можете решить, что они настолько похожи, что они принадлежат одной таблице навыков (в моем примере выше) с полем, определяющим тип этого навыка.
Это хороший признак того, что вы пока не удовлетворены своими попытками - это означает, что вы готовы рассмотреть множество возможностей, прежде чем выбрать одну. Чем больше эскизов вы рассмотрите, тем лучше будет ваш окончательный дизайн. В конце концов, лучшим из них станет ваша диаграмма данных. Когда это довольно хорошо решено, вы можете вернуться к размышлениям о «комбинированных окнах» или «текстовых полях», но я бы оставил решения по пользовательскому интерфейсу до конца.
Вместо того, чтобы смотреть на JTrees, я бы посоветовал вам изучить темы структур данных, проектирования баз данных и, возможно, моделирования данных. РЕДАКТИРОВАТЬ-> Или, еще лучше, диаграммы сопоставления сущностей, как предложил Дэвид Качиньский! <-EDIT Если вы правильно разработали дизайн данных, то Java и пользовательский интерфейс будут исходить из него явно и естественно. Но если вы ошиблись, то никакое количество Java-кунг-фу или UI-beauty не исправит это.
Удачи!
источник
Я собираюсь сосредоточиться на объектной модели.
Я думаю, что для гибкости, которую вы хотите, вы, вероятно, хотите разделить свои классы на уровень знаний (возможно, «определение» - более подходящее слово в данном случае) и слой транзакций. Под «слоем» я действительно подразумеваю логическое разделение их в вашей голове. Уровень знаний содержит ваше определение того, как выстраивать дерево, и данные в нем поступают от дизайнера игр, а уровень данных хранит конкретные варианты выбора для конкретного персонажа.
Ваш уровень знаний будет по крайней мере немного грязным, потому что вы пытаетесь сделать классную игру, а не математически чистую модель.
Пытаясь организовать то, что у вас есть, я думаю, что у вас есть класс SkillDefinition, у которого есть свойство Parent типа SkillDefinition. У вас также есть подклассы SkillDefinition (которые могут стать записями в таблице DEF_SkillType в базе данных), чтобы охватить несколько случаев.
«Оружие», «Физический и умственный» и «Медицинский», кажется, не имеют ничего, кроме названия (и навыков ребенка).
«Одноручное», «Сила» и «Связанные раны», кажется, имеют связанный комбинированный список (что означает что-то вроде таблицы DEF_SkillChoice в базе данных с внешним ключом для DEF_Skill). Sword и Bow кажутся заданной пользователем строкой (поэтому нет связанной таблицы на уровне знаний, но данные будут храниться на уровне транзакций).
«Жизнь», кажется, связана с целым числом. Возможно, он не сможет совместно использовать этот класс с какими-либо будущими характеристиками, использующими целое число, поскольку подразумевается поведение приращения целого числа. В любом случае, в настоящее время ему нужен собственный класс.
«Меч», «Лук», «Сила» и «Связанные раны», кажется, имеют связанные уровни прогрессивного мастерства ниже их в дереве. В случае «Меча» и «Лука» эти уровни действительно связаны с их родительским умением. Я думаю, что вам нужен класс ProgressiveSkillDefinition с упорядоченным набором допустимых значений (таблица DEF_SkillLevel с внешним ключом для DEF_Skill. На уровне знаний не совсем ясно, какие правила вы моделируете. Если всегда доступны «уровень знаний» и «специализация» для всех видов оружия у вас может быть таблица DEF_SkillLevel с записями «навыка» и «специализации», имеющими внешние ключи к записи «оружия».
Это охватывает то, что вы знаете на уровне знаний. Уровень транзакции (возможно, «уровень персонажа» будет лучшим названием?) Просто указывает на соответствующий уровень знаний. Итак, в вашем примере у вас будет объект Character с объектом Skills, у которого есть набор навыков - только те, которые он на самом деле имеет.
Таким образом, у персонажа будет навык «Мастерство», чьим родителем является навык «меч», а тип - Skill_Level. В базе данных запись TRANS_SkillDefinition имеет внешний ключ для записи навыка транзакции «меч» и запись уровня DEF_SkillLevel уровня знаний с именем «Уровень».
Навык умения будет иметь родительский объект навыка «меч» типа Skill_UserNamed. В базе данных это не будет иметь внешний ключ к уровню знаний, потому что нет ничего особенного для «меча» (это имя пользователя). Однако он также имеет внешний ключ для родительской записи транзакции, поэтому через него можно получить больше информации.
Объект умения «меч» имеет родительский объект «одноручный», поскольку пользователь решил поместить «меч» в категорию «одноручный». Это объект типа SkillCategory. В базе данных он имеет внешний ключ к таблице DEF_SkillChoice для записи «одной рукой» и не имеет транзакционного родителя, поскольку все дополнительные данные для этого навыка хранятся на уровне знаний.
При построении исходного дерева для нового персонажа необходимо запрашивать только уровень знаний. Чтобы заполнить выбор, сделанный для персонажа, требуется транзакционный уровень.
Вам понадобится код для перевода объектной модели в дерево и обратно. Надеюсь, должно быть ясно, что вам нужно сделать - каждый тип на уровне знаний будет иметь связанный набор элементов управления на дереве, который получает данные, соответствующие этому типу.
Позже вам могут потребоваться классы для каждого выбора в записях SkillCategory (если с «Специализацией» связано поведение, код должен куда-то идти), но вам пока это не нужно для этого дерева, и этот дизайн будет совместим с этим. Вам просто нужно иметь фабрику, которая использует информацию уровня знаний для создания правильного объекта.
источник
В конце концов, мы всегда заканчиваем управлением иерархическими структурами - будь то иерархия классов программы или сама программа, построенная из разных модулей, соединяющих вас с «внутренним миром» (GUI, соединение с БД, бизнес-логика с привязкой к данным и т. Д.) , Но это философия, как это должно работать в вашем случае?
У вас есть узлы в этом дереве, каждый элемент является «экземпляром объекта»; в то время как их поведение (где их можно разместить, список разрешенных дочерних узлов и т. д.) является общим для некоторых наборов, например, «классов». Да, это как программный код. Если вы достаточно хорошо знаете Java-отражение, вы можете даже использовать классы POJO и иерархию наследования для создания этого компонента с контейнером IoC или фабричным механизмом для создания реальных экземпляров. Но я думаю, что вы не хотите этого, потому что это тяжелый взлом языка, так что ...
Сначала создайте объект класса, который будет описывать поведение элементов. Содержит идентификатор класса, имена «полей» и разрешенные типы и количество предметов и т. Д. Пример: «корневой» класс - «Свойства игрока», имеет поля «Физический / Ментальный», «Медицинский», «Оружие». Этот тип является «окончательным»: сейчас вы не хотите иметь разные типы игроков. Подсказка: позже вы можете сделать это, используя те же инструменты для обработки "нечеловеческих монстров" ... :-)
«Медицинское» поле
Наоборот: член Оружия не обязателен, его следует создавать при добавлении первого оружия вашему игроку. Это означает: когда вы «редактируете» свой «объект» (теперь игрок) и хотите разрешить добавление в него нового элемента, вы не должны ограничивать выбор фактическими свойствами экземпляра (который теперь не содержит «оружия»). "), но покажите все поля определения класса и лениво создайте новое поле (дочерний узел) при первом использовании. Это создаст расширяемую среду. Позже вы можете добавить поле «Друзья» со ссылками на несколько игроков ... э ... (см. Позже).
Следуйте процессу с фактическими «классами». Это поможет вам усовершенствовать ваши идеи, например: кажется, лучше разделять типы оружия (мечи, кинжалы, луки, ...), как-то обращаться с боеприпасами (зная, что, возможно, игрок НЕ имеет лука, но может собирать стрелы, но используя некоторые виды оружия требуют и уменьшают боеприпасы, некоторые из них могут быть найдены, другие потеряны ...) в классе «Оружие»: легче исследовать, а также показать, если ваш игрок носит только этот предмет или может использовать его ( имеет навыки). С другой стороны: вы обязательно измените эту структуру позже, когда будете разрабатывать свою игру.
Создайте глобально доступный «магазин классов», который вы инициализируете при запуске игры, и предоставляйте определения классов, когда кто-либо ссылается на их имя. В этом случае объекты класса def должны быть неизменными.
«Объекты» проще: они могут быть получены из того же корневого класса, который содержит ссылку на определение класса, а также общий доступ к полям. Возможно, используйте HashMap, чтобы содержать тех детей, идентифицированных именем поля. Помните: некоторые из этих полей содержат один объект, другие - набор объектов. Эти случаи, конечно, изменчивы.
Теперь для интерфейса. Во-первых, вы должны проверить учебник JTree ... , и теперь это должно быть очевидно. Каждый «объект» может быть представлен DefaultMutableTreeNode, «userObject» узла должен быть вашим объектом (я думаю, что toString () этого узла отображается как метка узла, но вы можете создать пользовательский форматер ячеек). Всякий раз, когда вы открываете узел, вы просматриваете поля объекта и создаете дочерние узлы под родительским (если вы хотите сделать это динамически) - или просматриваете все дерево и строите структуру TreeNode при отображении JTree (подсказка: там является конструктором JTree с параметром TreeNode)
Когда вы выбираете узел в дереве, у вас есть экземпляр объекта. По его классу вы можете отобразить правильную панель редактора или общую панель, сгенерированную определением класса (например: панели вкладок с полями, редакторы для фактического поля посредством объявления поля: кнопка, которая создает дочерний элемент соответствующего типа of позволяет вам выбрать один из доступных классов и поля редактора для этого экземпляра, например свойства оружия). После изменения структуры вы должны обновить само дерево - TreeModel и его функции fire ... change - ваши друзья.
Выглядит хорошо? Или слишком сложный? Ну, это небольшая часть истории. Я не говорил о
Во всяком случае, я надеюсь, что вы можете использовать что-то из этой разминки.
источник
Я не собираюсь давать вам длинный ответ, но я сталкивался с подобной ситуацией раньше и, честно говоря, я перестал пытаться использовать любую существующую структуру данных. Я просто создал свой собственный объект, который мог бы принимать новых родителей и детей, подобно узлу XML.
В вашем случае, однако, я думаю, что использование класса Xml поможет. Затем вы можете иметь свойства для каждого узла, которые могут сказать вам, является ли класс навыком, и вы можете легко получить родителей и потомков любого узла, который вы хотите использовать в поле со списком или иным образом.
Кроме того, я хотел бы добавить, что вы не должны избавляться от мысли, что у вас будет много текстов / строк. В играх обычно используется ИИ, а в ИИ обычно много текстов.
источник