JavaFXطريقة جعل المستخدم قادر على إضافة و حذف و تعديل بيانات الـTreeView
المثال التالي يعلمك طريقة جعل المستخدم قادر على إضافة و حذف و تعديل بيانات الـ TreeView
بطريقة إحترافية.
ملاحظة: عليك إنشاء مجلد و وضع الصور فيه كما في الصورة التالية.
الصورة توضح أننا أضفنا مجلد إسمه images
و وضعنا فيه أربع صور.
مثال
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 هنا قلنا أنه عند تعديل نص الـ public void startEdit() { super.startEdit(); if (textField == null) { createTextField(); } setText(null); setGraphic(textField); textField.selectAll(); } // سيتم إعادة النص الذي كان موجوداً من قبل EditableItem هنا قلنا أنه عند إلغاء تعديل نص الـ public void cancelEdit() { super.cancelEdit(); setText((String) getItem()); setGraphic(getTreeItem().getGraphic()); } // بأي شكلٍ كان EditableItem هنا قمنا بتحديد ما سيحدث عند محاولة تعديل الـ 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); } } } } }
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"))); } 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); } }
ستظهر لك النافذة التالية عند التشغيل.