Programming Basics SQL HTML CSS JavaScript React Python C++ Java JavaFX Swing Problem Solving English English Conversations Computer Fundamentals Linux Learn Typing

JavaFXطريقة إظهار قائمة ContextMenu عند النقر على زر الفأرة الأيمن

معلومة تقنية

في JavaFX لا يمكنك وضع حدود (Borders) لصورة تعرضها بالأساس بواسطة ImageView. إن أردت وضع حدود للصورة, يمكنك أنت تضع الـ ImageView الذي يمثل الصورة بداخل Pane ثم تقوم بوضع حدود لهذا الـ Pane. عندها سيظهر حول الصورة لأن الصورة موضوعة بداخله.

و طبعاً, يمكنك إستخدام أي حاوية أخرى متوفرة في JavaFX غير الـ Pane مثل StackPane, BorderPane الخ..


المثال التالي يعلمك طريقة إنشاء كائن من الكلاس ContextMenu يمثل قائمة تظهر عند النقر على زر الفأرة الأيمن ( Right Click ).
هذه القائمة تسمح للمستخدم بقلب الصورة يميناً و يساراً, إظهار خط حولها, تحديد لون الخط, إخفاء الخط.

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

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

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


مثال

Main.java
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);
        }
    }
    
    
    @Override
    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);
    }

}

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

طريقة إظهار قائمة ContextMenu عند النقر على زر الفأرة الأيمن في javafx