JavaFXطريقة إظهار قائمة ContextMenu
عند النقر على زر الفأرة الأيمن
معلومة تقنية
في JavaFX لا يمكنك وضع حدود (Borders) لصورة تعرضها بالأساس بواسطة ImageView
. إن أردت وضع حدود للصورة, يمكنك أنت تضع الـ ImageView
الذي يمثل الصورة بداخل Pane
ثم تقوم بوضع حدود لهذا الـ Pane
. عندها سيظهر حول الصورة لأن الصورة موضوعة بداخله.
و طبعاً, يمكنك إستخدام أي حاوية أخرى متوفرة في JavaFX غير الـ Pane
مثل StackPane
, BorderPane
الخ..
المثال التالي يعلمك طريقة إنشاء كائن من الكلاس ContextMenu
يمثل قائمة تظهر عند النقر على زر الفأرة الأيمن ( Right Click ).
هذه القائمة تسمح للمستخدم بقلب الصورة يميناً و يساراً, إظهار خط حولها, تحديد لون الخط, إخفاء الخط.
ملاحظة: عليك إنشاء مجلد و وضع الصورة فيه كما في الصورة التالية.
الصورة توضح أننا أضفنا مجلد إسمه images
و وضعنا فيه صورة واحدة إسمها javafx-icon.png
.
مثال
import javafx.application.Application; import javafx.beans.value.ObservableValue; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.control.CheckMenuItem; import javafx.scene.control.ContextMenu; import javafx.scene.control.MenuItem; import javafx.scene.control.RadioMenuItem; import javafx.scene.control.SeparatorMenuItem; import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.Pane; import javafx.stage.Stage; public class Main extends Application { // لأننا ننوي وضع الصورة بداخله pane هنا قمنا بإنشاء كائن من الكلاس Pane pane = new Pane(); // يمثل الصورة التي تظهر في النافذة Image هنا قمنا بإنشاء كائن من الكلاس Image image = new Image(getClass().getResourceAsStream("/images/javafx-icon.png")); // في النافذة image لعرض الصورة التي يشير لها الكائن ImageView هنا قمنا بإنشاء كائن من الكلاس ImageView imageView = new ImageView(image); // يمثل القائمة التي تظهر عن النقر بزر الفأرة الأيمن فوق الصورة ContextMenu هنا قمنا بإنشاء كائن من الكلاس ContextMenu contextMenu = new ContextMenu(); // هنا قمنا بإنشاء جميع الكائنات التي سنستخدمها كعناصر بداخل القائمة MenuItem menuItem1 = new MenuItem("Rotate Right"); MenuItem menuItem2 = new MenuItem("Rotate Left"); CheckMenuItem checkMenuItem = new CheckMenuItem("Show Border"); RadioMenuItem radioMenuItem1 = new RadioMenuItem("Black Border"); RadioMenuItem radioMenuItem2 = new RadioMenuItem("Blue Border"); // radioMenuItem2 و radioMenuItem1 لأننا ننوي وضع الكائنين toggleGroup هنا قمنا بإنشاء كائن من الكلاس // لاحقاً في مجموعة واحدة لجعل المستخدم قادر على إختيار إحداهما في كل مرة و ليس كلاهما ToggleGroup toggleGroup = new ToggleGroup(); // الذي يحتوي على الصورة pane هنا قمنا بتعريف دالة خاصة لرسم أو إخفاء حدود الكائن public void drawBorderOnDemande() { // checkMenuItem إذا كان يوجد على صح على الكائن if (checkMenuItem.isSelected()) { // pane سيتم إظهار حدود لونها أزرق للكائن radioMenuItem1 إذا كان يوجد علامة صح على الكائن if (radioMenuItem1.isSelected()) { pane.setStyle("-fx-border-style: solid; -fx-border-color: black;"); } // pane سيتم إظهار حدود لونها أسود للكائن radioMenuItem2 إذا كان يوجد علامة صح على الكائن else { pane.setStyle("-fx-border-style: solid; -fx-border-color: blue;"); } } // pane سيتم إزالة الحدود عن الكائن checkMenuItem إذا لم يكن هناك علامة صح على الكائن else { pane.setStyle("-fx-border:none;"); } } // قابلين للنقر أم لا radioMenuItem2 و radioMenuItem1 هنا قمنا بتعريف دالة خاصة لتحديد ما إذا كان يجب جعل الكائنين public void autoEnableOrDisableMenuOptions() { // قابلين للنقر radioMenuItem2 و radioMenuItem1 سيتم جعل الكائنين checkMenuItem إذا قام المستخدم بوضع علامة صح على الكائن if (checkMenuItem.isSelected()) { radioMenuItem1.setDisable(false); radioMenuItem2.setDisable(false); } // غير قابلين للنقر radioMenuItem2 و radioMenuItem1 سيتم جعل الكائنين checkMenuItem إذا قام المستخدم بإزالة علامة الصح عن الكائن else { radioMenuItem1.setDisable(true); radioMenuItem2.setDisable(true); } } public void start(Stage stage) { // في النافذة pane هنا قمنا بتحديد حجم و مكان الكائن pane.setPrefSize(202, 202); pane.setTranslateX(99); pane.setTranslateY(24); // pane في الكائن imageView هنا قمنا بوضع الكائن pane.getChildren().add(imageView); // للأننا وضعناه بداخله pane بالنسبة للكائن imageView هنا قمنا بتحديد حجم و مكان الكائن imageView.setFitWidth(200); imageView.setFitHeight(200); imageView.setTranslateX(1); imageView.setTranslateY(1); // و هكذا أصبح يمكن إختيار واحد منهم فقط في كل مرة radioMenuItem2 و radioMenuItem1 و ربطنا فيه الكائنين ToggleGroup هنا قمنا بإنشاء كائن من الكلاس radioMenuItem1.setToggleGroup(toggleGroup); radioMenuItem2.setToggleGroup(toggleGroup); // هنا قمنا بوضع كل جميع الكائنات التي أنشأناها خصيصاً لوضعها كعناصر في القائمة بداخلها contextMenu.getItems().add(menuItem1); contextMenu.getItems().add(menuItem2); contextMenu.getItems().add(new SeparatorMenuItem()); contextMenu.getItems().add(checkMenuItem); contextMenu.getItems().add(new SeparatorMenuItem()); contextMenu.getItems().add(radioMenuItem1); contextMenu.getItems().add(radioMenuItem2); // في النافذة Root Node لأننا ننوي جعله الـ Group هنا قمنا بإنشاء كائن من الكلاس Group root = new Group(); // root في الكائن datePicker هنا قمنا بإضافة الكائن root.getChildren().add(pane); // فيها و تحديد حجمها Node كأول root هنا قمنا بإنشاء محتوى النافذة مع تعيين الكائن Scene scene = new Scene(root, 400, 250); // هنا وضعنا عنوان للنافذة stage.setTitle("JavaFX ContextMenu"); // أي وضعنا محتوى النافذة الذي قمنا بإنشائه للنافذة .stage في كائن الـ scene هنا وضعنا كائن الـ stage.setScene(scene); // هنا قمنا بإظهار النافذة stage.show(); // الذي يمثل الصورة imageView هنا قمنا بتحديد ماذا سيحدث عند النقر بواسطة الفأرة على الكائن imageView.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent e) -> { // في المكان الذي تم النقر عليه (contextMenu) إذا تم النقر على الصورة من الفأرة بواسطة الزر الأيمن, سيتم إظهار القائمة if (e.getButton() == MouseButton.SECONDARY) { contextMenu.show(imageView, e.getScreenX(), e.getScreenY()); } }); // menuItem1 هنا قمنا بتحديد ماذا سيحدث عند النقر على الخيار الذي يمثل الكائن menuItem1.setOnAction((ActionEvent) -> { // سيتم جعل الصورة تدور 90 درجة باتجاه اليمين imageView.setRotate(imageView.getRotate() + 90); }); // menuItem2 هنا قمنا بتحديد ماذا سيحدث عند النقر على الخيار الذي يمثل الكائن menuItem2.setOnAction((ActionEvent) -> { // سيتم جعل الصورة تدور 90 درجة باتجاه اليسار imageView.setRotate(imageView.getRotate() - 90); }); // checkMenuItem هنا قمنا بتحديد ماذا سيحدث عند النقر على الخيار الذي يمثل الكائن checkMenuItem.setOnAction((ActionEvent) -> { // لتحديد ما إذا كان يجب رسم حدود حول الصورة أم لا autoEnableOrDisableMenuOptions() و drawBorderOnDemande() سيتم إستدعاء الدالتين // أم لا radioMenuItem2 و radioMenuItem1 و كيف يجب أن يتم تلوين هذه الحدود و لتحديد ما إذا كان يمكن النقر على الكائنين drawBorderOnDemande(); autoEnableOrDisableMenuOptions(); }); // group تابع للمجموعة RadioButton هنا قمنا بتحديد ماذا سيحدث عند النقر على أي toggleGroup.selectedToggleProperty().addListener((ObservableValue<? extends Toggle> ov, Toggle toggle, Toggle new_toggle) -> { drawBorderOnDemande(); }); // غير مختار عند تشغيل التطبيق, أي لا يوجد عليه علامة صح checkMenuItem هنا قمنا بجعل الكائن checkMenuItem.setSelected(false); // مختاراً بشكل إفتراضي عند تشغيل التطبيق, أي يوجد عليه علامة صح radioMenuItem1 هنا قمنا بجعل الكائن radioMenuItem1.setSelected(true); // أم لا radioMenuItem2 و radioMenuItem1 لتحديد ما إذا كان يمكن النقر على الكائنين autoEnableOrDisableMenuOptions() هنا قمنا باستدعاء الدالة autoEnableOrDisableMenuOptions(); } // هنا قمنا بتشغيل التطبيق public static void main(String[] args) { launch(args); } }
ستظهر لك النافذة التالية عند التشغيل.