web-dev-qa-db-ja.com

任意/汎用のカテゴリノードを持つ可変で多様なjtreeを作成するにはどうすればよいですか?

注:ここではコーディングのヘルプは必要ありません。理由はProgrammersです。 Java の理解だけではなく、プログラムの計画/作成のスキルを向上させたいです。

このLARPゲーム用にリストされているスキル here に基づいて、任意のカテゴリシステムを持つツリーを作成する方法を理解しようとしています。私の以前の試みは、スキルがカテゴリーでもあるかどうかについての真剣なものでした。それをコード化しようとすると面倒だった。自分の木を描くと、「葉」だけがスキルであり、他のものはカテゴリとしてラベル付けしていることに気付きました。

私が求めているのは、モデルとビューを分離しようとするツリーを作成し、任意の親に任意のタイプの子ノードを(追加の編集/レンダリング方法で)追加できるようにする方法です。

A tree listing various skill from the above link

N.Bプロパティのように見える場所でも、ここにあるものはすべてスキルとして購入されます。エンドユーザーはこれを購入スキル(紙のATMで行うスキル)と見なすため、すべて同じページに表示する必要があります。

ツリーの説明:ツリーは、ハードコードされた最高レベルのカテゴリのセット(武器、物理的および精神的、医療など)。これから、ユーザーはスキルを追加できる必要があります。最終的には、たとえば「片手剣スペシャライゼーション」 skill notitem)を追加したいと考えています。そのためには、Weaponsを選択して[追加]をクリックし、その子に表示されるコンボボックスノードからOne-handedを選択して、もう一度[追加]をクリックして、テキストフィールドに名前を入力するのが理想的です。 that 表示される子ノード。次に、もう一度「追加」をクリックして、そのリーフの「レベル」または「階層」を追加/指定します。最初に習熟し、次に専門分野(たとえば)。

もちろん、別のスキルを購入したい場合、それは葉への完全に異なるルートです。武器の例で行ったのと同じレベルのツリーの下にコンボボックスは必要なく、その背後に他のロジックも必要になる場合があります。これは、プログラミングだけでなく頭を悩ませるのにも苦労しています。クラスのセットを作成する方法と、notでそれらをどの順序で接続するかを指定しますが、それらすべてを適合させます。

この種のツリーをコードで記述するための優れたシステムは何ですか?私が見た他のすべてのJTreeの例には、いくつかの predictable パターンがあり、私のはありません。子ノードの type (コンボボックス、テキストフィールドなど)の何を許可する必要があるかを示す長いリストを使用して、これをすべて「リテラル」でコーディングする必要はありません。親。抽象クラスを使用する必要がありますか?インターフェース?

動作が異なる上記以外のスキルを追加するときに、この種のオブジェクトのクラスターを拡張可能にするにはどうすればよいですか?

使用するのに適したシステムが not ある場合、このようなことを行う方法を検討するための良いプロセスはありますか?

私の頭の中の歯車は回っています:

私は常にする必要があります:

  • 親を確認してください
  • 親に基づくオプションを提供する

この共通性のために、スキルとカテゴリの一般的なメソッドを定義/概説する抽象/インターフェースskillクラスが必要だと考え始めています。私は(うまくいけば)ルールとオプションをデータベースに入れ、そこから読み取ることができます。問題は、抽象メソッドまたはインターフェース・メソッドと、それをどのように実装するかの間であると私は思います。

12
Pureferret

単純な可変JTreeの例

enter image description here

コード(Java 7でコンパイルおよびテスト済み):

import Java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;

public class SimpleTree extends JFrame {
    public static void main(String[] args) {
        new SimpleTree();
    }

    public SimpleTree() {
        super("Mutable Varied JTree");
        Container content = getContentPane();
        N root = new N("Root");

        N weapons = new N("Weapons").add(
            new N("One-handed").add(
                new N("Sword").add("Proficiency", "Specialization"), 
                new N("Mace").add("Proficiency")),
            new N("Bow").add("Proficiency"));
        root.add(weapons);

        N phys = new N("Physical & Mental").add(
            new N("Life"),
            new N("Strength").add(
                "Double", "Triple", "Quadruple"));

        root.add(phys);
        N med = new N("Medical");
        med.add(new N("Bind Wounds"));
        med.add(new N("Set Broken Bones"));
        root.add(med);

        JTree tree = new JTree(root);
        content.add(new JScrollPane(tree), BorderLayout.CENTER);
        setSize(275, 300);
        setVisible(true);
    }

    private class N extends DefaultMutableTreeNode {
        public N(String s) { super(s); }
        public N add(String... strs) {
            for (String s : strs) {
                super.add(new N(s));
            }
            return this;
        }
        public N add(N... ns) {
            for (N n : ns) {
                super.add(n);
            }
            return this;
        }
    }
}

特別な感謝 このJTreeチュートリアル

更新:可能な解決策の議論

フレームの下部にあるボタンを使用してノードを追加/削除/クリアする 動的ツリーの作成に関するチュートリアル があります。

コンボボックスなどの場合、適切なスイングクラスのオブジェクトを取得して、Java.swing.tree.MutableTreeNodeを実装するJComboBoxのようなものにする必要があります。 Java Swingチュートリアルには コントロールのリスト があります。

ユーザーが追加するノードの種類を選択し、ノードを編集できるようにするには、ユーザーインターフェイス要素を作成する必要があります。コンボボックスを追加する場合は、ボックスで使用できる選択肢を定義できる必要があります。

データを保存するには、基礎となるデータモデルが必要です。すべてのJavaオブジェクトに組み込まれているデフォルトのシリアル化スキームを使用できますが、これはプロトタイプ作成のみを目的としています。プログラムコードを変更すると機能しなくなります。いずれかのJDBCでデータベースを使用する必要があります。またはJPAまたはJSONまたはXMLのようなものをストレージ形式として使用して、独自のシリアル化ルーチンを記述する(またはシリアル化を処理するライブラリを使用する)必要があります。

更新:提案されたソリューションとプロジェクトの概要

最も簡単な解決策は、データベースを忘れて最初にデータのXML式を考え出し、次にXMLファイルを編集して、特別なコンボボックスなどを使用せずに結果をJTreeとして表示することです。これが、オパタ・チブエゼの答えです。このツリーの部分的なXML表現は次のようになります。

<folder name="Physical &amp; Mental">
    <int name="Life">12</int>
    <drop-down name="Strength">
        <option name="Single" />
        <option name="Double" />
        <option name="Triple" />
        <option name="Quadruple" />
    </drop-down>
</folder>
<folder name="Medical">
    <text name="Bind Wounds" />
    <text name="Set Broken Bones" />
</folder>

ここにあなたのためのいくつかの潜在的なマイルストーンがあります:

  • XMLまたはJSONデータ形式を作成し、その形式のファイルを読み取って、コンボボックスなしでフォルダーとファイルのみのJTreeとして表示するプログラムを作成します。
  • JTreeディスプレイにスイングコントロールを追加する
  • プログラムを拡張して、同じファイルを書き込みます
  • ユーザーがGUIを使用してノードを追加および編集できるように、ユーザーインターフェイスを作成する

各マイルストーンの最後に機能するたびに、プログラムのバックアップを保存してください。別のマシンにインストールされているソース管理システムがこれに最適です。コードの共有を気にせず、ソース管理を備えたサーバーをセットアップしたくない場合は、github、sourceforge、またはその他のパブリックソース管理を使用できます。

これらのソリューションはどれも多くの作業が必要であり、初心者プロジェクトよりも確実に大きくなります。 Java LARPをプレイするよりもSwingとXMLまたはJSONを学習することに多くの時間を費やすことになります。そのため、私が最初に既存のツールで行う方法を検討しました。しかし、何でも学ぶための最良の方法は学習意欲が最も高い方法なので、これはあなたにとって完璧なプロジェクトかもしれません。

お役に立てば幸いです。

3
GlenPeterson

オブジェクトモデルに焦点を当てます。

あなたが望む柔軟性のために、おそらくクラスを知識(おそらく「定義」はこの場合はより良いWordです)層とトランザクション層に分離したいと思います。 「レイヤー」とは、実際にはそれらを論理的に分離することを意味します。ナレッジレイヤーには、ツリーのレイアウト方法の定義が含まれ、その中のデータはゲームデザイナーから取得され、データレイヤーには特定のキャラクターの特定の選択肢が格納されます。

数学的にクリーンなモデルではなく、クールなゲームを作ろうとしているため、知識レベルは少なくとも少し厄介です。

これまでのところを整理しようとすると、SkillDefinitionクラスにSkillDefinitionタイプのParentプロパティがあると思います。また、いくつかのケースをカバーするために、SkillDefinitionのサブクラス(データベースのDEF_SkillTypeテーブルのエントリになる場合があります)もあります。

「武器」、「肉体的および精神的」、および「医療的」は、タイトル(および子供のスキル)以外に何もないようです。

「One Handed」、「Strength」、および「Bind Wounds」には、コンボボックスが関連付けられているようです(つまり、データベース上のDEF_SkillChoiceテーブルのようなもので、DEF_Skillへの外部キーがあります)。 SwordとBowはユーザー定義の文字列のようです(したがって、ナレッジレベルで関連付けられたテーブルはありませんが、データはトランザクションレイヤーに格納されます)。

「生命」には整数が関連付けられているようです。整数がどのようにインクリメントされるかについての暗黙の動作があるため、整数を使用する将来の特性とこのクラスを共有できない可能性があります。いずれにせよ、現在は独自のクラスが必要です。

「剣」、「弓」、「強さ」、および「バインドの傷」はすべて、ツリー内でそれらの下にプログレッシブスキルのレベルが関連付けられているようです。 「剣」と「弓」の場合、それらのレベルは実際には親スキルに関連付けられています。正当な値の順序付けられたコレクション(DEF_Skillへの外部キーを持つDEF_SkillLevelテーブル)を備えたProgressiveSkillDefinitionクラスが必要だと思います。知識レベルでは、どのルールをモデル化しているのか完全には明確ではありません。すべての武器について、「weapons」レコードへの外部キーを持つ「proficiency」および「specialization」レコードを含むDEF_SkillLevelテーブルを作成できます。また、それを指すDEF_SkillLevelレコードを含むDEF_SkillLevelSetテーブルを作成し、外部を「リバース」することもできます。 DEF_SkillLevelからSkillDefinitionへのキーを、SkillDefinitionからDEF_SkillLevelSetへの外部キーで置き換えることによってキーを作成しますが、多くの「熟練」および「専門化」レコードが苦痛にならない限り、それを行いません(それらにのみ適用される場合は当てはまりません)とにかく「武器」)。

これは、知識レベルで知っていることをカバーしています。トランザクションレベル(おそらく「文字レベル」の方が適切な名前でしょうか?)は、適切な知識レベルを指し示すだけです。したがって、あなたの例では、スキルのコレクション-実際に持っているスキルだけを持つSkillsオブジェクトを持つCharacterオブジェクトがあります。

したがって、キャラクターは「熟練」スキルを持ち、その親は「剣」スキルであり、タイプはSkill_Levelです。データベースのTRANS_SkillDefinitionレコードには、トランザクションの「剣」スキルレコードへの外部キーと、「Proficiency」という名前の知識レベルDEF_SkillLevelレコードがあります。

熟練スキルには、Skill_UserNamedタイプの「剣」スキルの親オブジェクトがあります。データベースでは、「剣」に特別に定義されたものは何もない(ユーザーの名前です)ため、知識レベルへの外部キーはありません。ただし、親のトランザクションレコードへの外部キーも含まれているため、より多くの情報を利用できます。

ユーザーが「片手」カテゴリに「剣」を配置することを選択したため、「剣」スキルオブジェクトには「片手」の親オブジェクトがあります。これは、SkillCategoryタイプのオブジェクトです。データベースでは、「片手」レコードのDEF_SkillChoiceテーブルへの外部キーがあり、このスキルのすべての追加データは知識レベルで格納されているため、トランザクションの親はありません。

新しいキャラクターの初期ツリーを構築する場合、知識レベルのみを照会する必要があります。キャラクターに対して行われた選択を入力するには、トランザクションレベルが必要です。

オブジェクトモデルをツリーに変換して戻すコードが必要です。明確にする必要があります。何をする必要があるかを理解してください。ナレッジレイヤーの各タイプには、ツリーに関連付けられたコントロールのセットがあり、そのタイプに適したデータを取得します。

後で、SkillCategoryレコードの各選択肢のクラスが必要になる場合があります(「スペシャライゼーション」に動作が関連付けられている場合、コードはどこかに移動する必要があります)が、このツリーではまだ必要ありません。この設計は互換性がありますそれと。知識レベル情報を使用して適切なオブジェクトを構築するファクトリが必要です。

2
psr

JTreeがあなたが解決しようとしている問題を正しく表現しているとは思いません。私はあなたのウェブサイトを見ました、そして、もののリストを見ます。これは素晴らしいスタートですが、私はあなたが持っているかもしれない根本的なデータ設計があると思いますが、私は見ていません。

人生と強さは私にとってキャラクターの属性のように見えます。 Double、Triple、Quadrupleは、Strength属性の値のように見えます。次に、スキルを武器と医療に分けます。私は武器を所持品(購入、発見、またはドロップできる)と考えています。特定の武器で効果を発揮できるのはスキルだと思います。しかし、私がそれを見ると、武器と薬にはスキルがなく、キャラクターにはスキルがあります。実際、私はキャラクターがデータ設計の中心人物であると強く疑っています。

これまでの設計で私にとって際立っている3つのデータオブジェクトを次に示します。

Character:
    Life (a value: e.g. 12)
    Strength (a value: e.g. double, triple, quadruple)
    Skills (list or set of weapon-skills, healing-skills)
    Possessions (list of weapons, armor and other possessions)
    WornArmor (maybe only wear one you possess at a time?)
    WieldedWeapon (one or two of your posessions)

Skill:
    Skill-Type (healing, manufacture, or weapon)
    RelevantWeapon (for this skill)

Weapon:
    IsOneHanded (boolean)
    IsBow (boolean)

これでキャラクターは武器とスキルを持つことができますが、本当に良い攻撃には、使用している武器に固有のスキルが必要です。いずれにせよ、ここには1対多の関係があります(1人のキャラクターが多くのスキルを持つことができます)。しかし、私はまだ木を見ていません。

一枚の紙を取り、最初のページでページの中央にキャラクターを置き、その周りに5〜10個の最も重要なゲーム世界のオブジェクトをリストします。ツリーやテキストフィールド、コンボボックスを意識せずに、どのデータが別のオブジェクトの属性(ライフとストレングスがキャラクターの不可分な部分であるなど)であるか、オブジェクト間の最も重要な関係は何かを把握します。オブジェクト間に線を引き、関係を表します。次に、どの関係が1:1、1:多、多:多であるかを調べ、それらにラベルを付けます。 「has-a」、「is-a」、その他の種類の関係も存在する場合があります。

WeaponSkill対HealingSkill対ManufactureSkillの個別の表現が必要になる場合があります。または、それらが1つのスキルテーブル(上記の例では)に属していて、どのタイプのスキルであるかを決定するフィールドがあるため、それらが非常に類似していると判断する場合があります。

これは、これまでの試みに満足していないことを示す良い兆候です。つまり、選択する前に多くの可能性を検討する用意があるということです。検討するスケッチが多いほど、最終的なデザインは良くなります。最終的には、最適なものがデータダイアグラムになります。それがかなりうまくまとまったら、「コンボボックス」または「テキストフィールド」について考えることに戻ることができますが、UIの決定は最後に任せます。

JTreesではなく、データ構造、データベース設計、そしておそらくデータモデリングのトピックを検討することをお勧めします。 EDIT->またはそれ以上 エンティティ関係マッピング David Kaczynskiが提案した図表! <-EDITデータの設計が適切であれば、Javaであり、UIは明らかにそこから自然に流れます。しかし、間違った場合は、 Java-kung-fuやUI-beautyがそれを修正することはありません。

幸運を!

2
GlenPeterson

結局のところ、プログラムのクラス階層であれ、「内部世界」(GUI、DB接続、データバインドビジネスロジックなど)に接続するさまざまなモジュールから構築されたプログラム自体であれ、常に階層構造の管理を終了します。 。しかし、これは哲学です。あなたの場合、それはどのように機能しますか?

このツリーにはノードがあり、各アイテムは「オブジェクトインスタンス」です。一方、それらの動作(配置できる場所、許可された子ノードのリストなど)は、「クラス」などの一部のセットに共通です。はい、これはプログラムコードのようなものです。 Javaリフレクションを十分に理解している場合は、POJOクラスと継承階層を使用して、IoCコンテナまたはファクトリメカニズムで実際のインスタンスを構築して、このコンポーネントを構築することもできます。しかし、言語ハッキングなので、それが欲しいので...

まず、アイテムの動作を説明する「クラス」オブジェクトを作成します。これには、クラス識別子、「フィールド」名、許可されたタイプとアイテムの数などが含まれます。例:「ルート」クラスは「プレーヤーのプロパティ」で、「物理/メンタル」、「医療」、「武器」フィールドがあります。このタイプは「最終」です。現在、さまざまなタイプのプレーヤーを使用する必要はありません。ヒント:後で、同じツールを使用して「人間以外のモンスター」を処理することができます... :-)

「医療」フィールドは

  • 「シングルトン」:プレーヤーは複数の「医療」情報を持つことができません
  • 子のタイプは固定で、ここでは「医療」タイプのオブジェクトのみ使用できます
  • 必須:プレーヤーを作成するときは、「医療」フィールドが必要です

反対:Weaponsメンバーは必須ではありません。最初の武器がプレーヤーに追加されたときに作成する必要があります。つまり、「オブジェクト」(現在はプレーヤー)を「編集」し、それに新しいアイテムを追加できるようにしたい場合、インスタンスの実際のプロパティ(現在は「武器」を含まない)によって選択を制限しないでください。 ")、ただしクラス定義のすべてのフィールドを表示し、最初に使用したときに新しいフィールド(子ノード)を遅延作成します。これにより、拡張可能な環境が作成されます。後で、複数のプレーヤー... er ...参照を含む "Friends"フィールドを追加できます(後で参照)。

実際の「クラス」でプロセスを追跡します。それはあなたのようなアイデアを洗練するのに役立ちます:武器の種類(剣、短剣、弓など)を分離し、何らかの形で弾薬を処理する方がよいようです(おそらくプレイヤーには弓がないが、矢を集めることができるが、特定の武器には弾薬が必要で、弾薬を減らします。それらのいくつかは見つかり、他は失われます...) "Weapons"クラス:調査が簡単で、プレーヤーがそのアイテムのみを持っているか、それとも使用できるかを示します(スキルがあります)。一方、ゲームを開発するときに、必ずこの構造を変更します。

ゲームの開始時に初期化するグローバルに利用可能な「クラスストア」を作成し、誰かが名前を参照したときにクラス定義を提供します。この場合、クラスdefオブジェクトは不変でなければなりません。

「オブジェクト」の方が簡単です。オブジェクトは、クラス定義への参照を含む同じルートクラスから派生でき、フィールドへの一般的なアクセスも可能です。おそらくHashMapを使用して、フィールド名で識別されるそれらの子を含めます。覚えておいてください:それらのフィールドのいくつかは単一のオブジェクトを含み、他のフィールドはオブジェクトのセットを含みます。これらのインスタンスはもちろん変更可能です。

次に、インターフェースについて説明します。最初に、 JTreeチュートリアル... を確認する必要があります。各「オブジェクト」はDefaultMutableTreeNodeで表すことができます。ノードの「userObject」をオブジェクトにする必要があります(そのノードのtoString()はノードのラベルとして表示されると思いますが、カスタムセルフォーマッタを作成できます)。ノードを開くたびに、オブジェクトのフィールドを参照し、親の下に子ノードを作成します(動的に行う場合)。または、JTreeを表示するときにツリー全体を参照してTreeNode構造を構築します(ヒント: TreeNodeパラメータを持つJTreeコンスクタです)。

ツリーでノードを選択すると、Objectインスタンスが作成されます。そのクラスによって、適切なエディターパネル、またはクラス定義によって生成された一般的なパネル(フィールドを含むタブパネル、フィールド宣言による実際のフィールドのエディター:適切なタイプの子を作成するボタン)を表示できます。 ofを使用すると、使用可能なクラスの1つと、そのインスタンスの武器フィールドなどのエディタフィールドを選択できます。構造を変更したら、ツリー自体を更新する必要があります。TreeModelとそのfire ... change関数はおなじみです。

いい感じ?または複雑すぎる?まあ、これは話のほんの一部です。私は話していません

  • クラス定義階層/または分類。同じフィールドへの異なるクラスの追加(異なる種類の剣など)をサポートする場合は、そのうちの1つを使用する方がよいでしょう。カテゴリー化のプロ:クラスは複数のカテゴリーを持つことができ、固定継承ツリーではありません。XPスキルの向上に費やすときにプレーヤーの「すべてのスキル」を収集したい場合に適しています。 .. :-)
  • 永続性のサポート:プロパティやJSONファイルのように、オブジェクト階層を外部に保存するための一般的なソリューションを作成する必要があります。脳を良好な状態に保ちたい場合は、人間が読める形式、バイナリシリアル化は使用しないでください。
  • インスタンスストレージ:ゲームの「世界」は1か所に保管する方がよいことにすぐに気付くでしょう。特定の剣はプレーヤーのプロパティではありませんが、ゲーム内の世界のエンティティ(プレーヤーはそれを失う可能性があり、誰かがそれを見つける可能性があるなど)なので、ツリー内のこれらの「オブジェクト」の多くは実際にはエンティティへの参照です(一方で、プレーヤーの健康状態などは、実際には属性のみです)。 2つのタイプを分離し、参照を解決できるインスタンス用のグローバルストレージを用意する必要があります。これにより、ゲームの状態をシリアル化するときにも節約され、複数のエンティティが同じ他のエンティティを参照します(同じ寺院への複数のプレイヤーの "場所"など)。
  • (そして本当の頭脳グラインダーについて言及すると、クラスストレージとインスタンスストレージの類似性です。型宣言は、プログラムコンポーネント、アクティブウィンドウ、ユーザーセッションなどと同じように、オブジェクトインスタンスそのものになる可能性があるという事実です。私のようなマニアの)。

とにかく、このウォームアップセッションをぜひご利用ください。

1
Lorand Kedves

長い回答をするつもりはありませんが、以前にこのような状況に直面したことがあり、率直に言って、既存のデータ構造を使用することをやめました。 XMLノードのように、新しい親と子を受け入れることができる独自のオブジェクトを単に作成しました。

ただし、あなたの場合、Xmlクラスを使用すると役立つと思います。次に、クラスがスキルであるかどうかを通知できる各ノードのプロパティを設定でき、コンボボックスなどで使用するノードの親と子を簡単に取得できます。

また、たくさんのテキスト/文字列を持つという考えから逃れるべきではないことを付け加えておきます。ゲームは通常AIを含み、AIは通常多くのテキストを含みます。

1
Chibueze Opata