JavaFX طريقة جعل المستخدم قادر على إضافة و حذف و تعديل بيانات الـTreeView

المثال التالي يعلمك طريقة جعل المستخدم قادر على إضافة و حذف و تعديل بيانات الـ TreeView بطريقة إحترافية.

ملاحظة: عليك إنشاء مجلد و وضع الصور فيه كما في الصورة التالية.

الصورة توضح أننا أضفنا مجلد إسمه images و وضعنا فيه أربع صور.

⇓ تحميل مجلد الصور


مثال

EditableItem.java
import javafx.event.ActionEvent;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;

// متطورة TreeItem و بالتالي أصبح إنشاء كائن منه يعني إنشاء TreeCell هنا قمنا بتعريف كلاس يرث من الكلاس
public class EditableItem extends TreeCell<String> {

    // يمثل قسم في الشركة TreeItem هنا قمنا بتعريف دالة ترجع الأيقونة التي سنضعها لكل كائن
    public ImageView getDepartmentIcon() {
        return new ImageView(new Image(getClass().getResourceAsStream("images/department-icon.png")));
    }
    
    // يمثل موظف في الشركة TreeItem هنا قمنا بتعريف دالة ترجع الأيقونة التي سنضعها لكل كائن
    public ImageView getUserMaleIcon() {
        return new ImageView(new Image(getClass().getResourceAsStream("images/user-male-icon.png")));
    }
    
    // يمثل موظفة في الشركة TreeItem هنا قمنا بتعريف دالة ترجع الأيقونة التي سنضعها لكل كائن
    public ImageView getUserFemaleIcon() {
        return new ImageView(new Image(getClass().getResourceAsStream("images/user-female-icon.png")));
    }
    
    // TreeItem في كل مرة يريد فيها المستخدم أن يقوم بتعديل نص TextField لأننا سنظهر textField هنا قمنا بتعريف كائن
    private TextField textField;
    
    // الذي يمثل الشركة Root Item هنا قمنا بتعريف القائمة التي سنظهرها عندما ينقر المستخدمم بزر الفأرة الأيمن على الـ
    private final ContextMenu menuForRootItem = new ContextMenu();

    // هنا قمنا بتعريف القائمة التي سنظهرها عندما ينقر المستخدمم بزر الفأرة الأيمن على أي قسم موجود في الشركة
    private final ContextMenu menuForAnyDepartment = new ContextMenu();
    
    // هنا قمنا بتعريف القائمة التي سنظهرها عندما ينقر المستخدمم بزر الفأرة الأيمن على أي مستخدم موجود بداخل قسم
    private final ContextMenu menuForAnyUser = new ContextMenu();

	// الكونستركتور
    public EditableItem() {
        // هنا قمنا بتعريف عناصر القائمة التي تظهر عند النقر بزر الفأرة الأيمن على الشركة
        MenuItem addNewDepartment = new MenuItem("Add new department");
        MenuItem deleteAllDepartments = new MenuItem("Delete all departments");
        
        // هنا قمنا بتعريف عناصر القائمة التي تظهر عند النقر بزر الفأرة الأيمن على أي قسم
        MenuItem addNewMale = new MenuItem("Add a male employee");
        MenuItem addNewFemale = new MenuItem("Add a female employee");
        MenuItem deleteAllEmployees = new MenuItem("Delete all employees");
        MenuItem deleteDepartment = new MenuItem("Delete department");
        
        // هنا قمنا بتعريف عنصر القائمة الذي يظهر عند النقر بزر الفأرة الأيمن على أي موظف أو موظفة
        MenuItem deleteUser = new MenuItem("Delete User");
        
        // فيها menuForRootItem هنا قمنا بإضافة عناصر على القائمة
        menuForRootItem.getItems().addAll(addNewDepartment, deleteAllDepartments);
        
        // فيها menuForRootDepartment هنا قمنا بإضافة العناصر عناصر القائمة
        menuForAnyDepartment.getItems().addAll(addNewMale, addNewFemale, deleteAllEmployees, deleteDepartment);
        
        // فيها menuForRootItem هنا قمنا بإضافة عنصر على القائمة
        menuForAnyUser.getItems().addAll(deleteUser);
        
		// addNewDepartment هنا قمنا بتحديد ما سيحدث عند النقر على العنصر
        addNewDepartment.setOnAction((ActionEvent t) -> {
            TreeItem newDepartment = new TreeItem<>("New Department", getDepartmentIcon());
            getTreeItem().getChildren().add(newDepartment);
            newDepartment.setExpanded(true);
        });
        
		// deleteAllDepartments هنا قمنا بتحديد ما سيحدث عند النقر على العنصر
        deleteAllDepartments.setOnAction((ActionEvent t) -> {
            getTreeItem().getChildren().remove(0, getTreeItem().getChildren().size());
        });
        
		// addNewMale هنا قمنا بتحديد ما سيحدث عند النقر على العنصر
        addNewMale.setOnAction((ActionEvent t) -> {
            TreeItem newDepartment = new TreeItem<>("New Employee", getUserMaleIcon());
            getTreeItem().getChildren().add(newDepartment);
        });
        
		// addNewFemale هنا قمنا بتحديد ما سيحدث عند النقر على العنصر
        addNewFemale.setOnAction((ActionEvent t) -> {
            TreeItem newDepartment = new TreeItem<>("New Employee", getUserFemaleIcon());
            getTreeItem().getChildren().add(newDepartment);
        });
        
		// deleteAllEmployees هنا قمنا بتحديد ما سيحدث عند النقر على العنصر
        deleteAllEmployees.setOnAction((ActionEvent t) -> {
            getTreeItem().getChildren().remove(0, getTreeItem().getChildren().size());
        });
        
		// deleteDepartment هنا قمنا بتحديد ما سيحدث عند النقر على العنصر
        deleteDepartment.setOnAction((ActionEvent t) -> {
            getTreeItem().getParent().getChildren().remove(getTreeItem());
        });
        
		// deleteUser هنا قمنا بتحديد ما سيحدث عند النقر على العنصر
        deleteUser.setOnAction((ActionEvent t) -> {
            getTreeItem().getParent().getChildren().remove(getTreeItem());
        });
        
    }

	// بداخله بعد TreeItem أو ترجع نص فارغ في حال كان لا يحتوي على EditableItem هنا قمنا بتعريف دالة ترجع نص الـ
	// و هذا يعني أنه في حال كان قد تم إنشاؤه فإننا لن نفقد القيمة الموجودة فيه
    private String getString() {
        return getItem() == null ? "" : getItem();
    }
	
	// EditableItem عند النقر على الـ TextField هنا قمنا بتعريف الدالة التي تنشئ
    private void createTextField() {
		// getString() فيه و الذي ترجعه الدالة EditableItem و تمرير النص الذي كان ظاهراً على الـ TextField هنا سيتم إنشاء الـ
        textField = new TextField(getString());
		// EditableItem هنا قمنا بفحص كل حرف يدخله المستخدم عند تعديل نص الـ
        textField.setOnKeyReleased((KeyEvent t) -> {
			// سيتم حفظ التعديلات Enter إذا قام المستخدم بالنقر على الزر
            if (t.getCode() == KeyCode.ENTER) {
                commitEdit(textField.getText());
            }
			// سيتم إلغاء التعديلات Esc إذا قام المستخدم بالنقر على الزر
			else if (t.getCode() == KeyCode.ESCAPE) {
                cancelEdit();
            }
        });
    }

	// TextField التي تنشئ createTextField() سيتم إستدعاء الدالة EditableItem هنا قلنا أنه عند تعديل نص الـ
    @Override
    public void startEdit() {
        super.startEdit();
        if (textField == null) {
            createTextField();
        }
        setText(null);
        setGraphic(textField);
        textField.selectAll();
    }

	// سيتم إعادة النص الذي كان موجوداً من  قبل EditableItem هنا قلنا أنه عند إلغاء تعديل نص الـ
    @Override
    public void cancelEdit() {
        super.cancelEdit();
        setText((String) getItem());
        setGraphic(getTreeItem().getGraphic());
    }

	// بأي شكلٍ كان EditableItem هنا قمنا بتحديد ما سيحدث عند محاولة تعديل الـ
    @Override
    public void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
		// TreeView في حال تم إلغاؤه قلنا أنه سيتم مسحه من الـ
        if (empty) {
            setText(null);
            setGraphic(null);
        }
		// في حال تم التفاعل معه بأي طريقة
		else {
			// مكانه ثم تحديث النافذة لإظهار النص الجديد TextField في حال كان يتم تعديل نصه سيتم وضع النص الذي تم إدخاله في الـ
            if (isEditing()) {
                if (textField != null) {
                    textField.setText(getString());
                }
                setText(null);
                setGraphic(textField);
            }
			// في حال تم النقر عليه بواسطة زر الفأرة الأيمن
			else {
				// سيتم تحديث النافذة لضمان أن يتم إظهاره بشكل صحيح
                setText(getString());
                setGraphic(getTreeItem().getGraphic());
                
				// TreeView ثم سيتم إظهار القائمة الخاصة بالشركة إذا تم النقر على أول شيء في الـ
                if (getTreeItem().getParent() == null) {
                    setContextMenu(menuForRootItem);
                }
				// TreeView أو سيتم إظهار القائمة الخاصة بالأقسام إذا تم النقر على أي شيء موضوع تحت الشركة في الـ
                else if( getTreeItem().getParent().getParent() == null) {
                    setContextMenu(menuForAnyDepartment);
                }
				// TreeView أو سيتم إظهار القائمة الخاصة بالموظفين و المظفات إذا تم النقر على أي شيء موضوع تحت أي قسم في الـ
                else if( getTreeItem().getParent().getParent().getParent() == null) {
                    setContextMenu(menuForAnyUser);
                }
            }
        }
    }

}

		

Main.java
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;

public class Main extends Application {

	// و التي سنقصد بها الشركة Root Item الذي يمثل الـ TreeItem هنا قمنا بتعريف دالة ترجع الأيقونة التي سنضعها لكائن الـ
    public ImageView getRootIcon() {
        return new ImageView(new Image(getClass().getResourceAsStream("images/building-icon.png")));
    }

    @Override
    public void start(Stage stage) {

		// getRootIcon() و مررنا له أيقونة المبنى التي سترجعها الدالة TreeView في الـ Root Item و الذي سنضعه كـ TreeItem هنا قمنا بإنشاء كائن من الكلاس
        TreeItem<String> rootItem = new TreeItem<>("Root Item", getRootIcon());

        // يمثل القائمة الشجرية التي نريد إضافتها في النافذة TreeView هنا قمنا بإنشاء كائن من الكلاس
        TreeView<String> treeView = new TreeView<>(rootItem);
        
        // يظهر عند تشغيل البرنامج rootItem موضوع مباشرةً تحت الـ TreeItem هنا جعلنا كل كائن
        rootItem.setExpanded(true);

        // في النافذةView هنا قمنا بتحديد حجم الـ
        treeView.setPrefSize(400, 250);

        // في النافذةView هنا قمنا بتحديد مكان ظهور الكائن
        treeView.setTranslateX(0);
        treeView.setTranslateY(0);

		// قابل للتعديل treeView هنا جعلنا محتوى الـ
        treeView.setEditable(true);
        
		// EditableItem سيتم تعديله سيتم معاملته على أنه كائن من الكلاس treeView هنا قلنا أن أي شيء بداخل الـ
        treeView.setCellFactory( 
           (TreeView<String> p) -> new EditableItem()
        );
        
        // في النافذة Root Node لأننا ننوي جعله الـ Group هنا قمنا بإنشاء كائن من الكلاس
        Group root = new Group();

        // root في الكائنView هنا قمنا بإضافة الكائن
        root.getChildren().add(treeView);

        // فيها و تحديد حجمها Node كأول root هنا قمنا بإنشاء محتوى النافذة مع تعيين الكائن
        Scene scene = new Scene(root, 400, 250);

        // هنا وضعنا عنوان للنافذة
        stage.setTitle("JavaFX TreeView");

        // أي وضعنا محتوى النافذة الذي قمنا بإنشائه للنافذة .stage في كائن الـ scene هنا وضعنا كائن الـ
        stage.setScene(scene);

        // هنا قمنا بإظهار النافذة
        stage.show();

    }

    // هنا قمنا بتشغيل التطبيق
    public static void main(String[] args) {
        launch(args);
    }

}
		

ستظهر لك النافذة التالية عند التشغيل.

طريقة جعل المستخدم قادر على إضافة و حذف و تعديل بيانات ال TreeView في javafx

الدورات

أدوات مساعدة

أقسام الموقع

دورات
مقالات كتب مشاريع أسئلة