C++ بلا حواجز: كيفية جعل الكود متاحًا للجميع

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا إمكانية الوصول ليست للضعفاء، بل لجودة الكود

\n\n

عندما نكتب بلغة C++، اعتدنا التفكير في الأداء والذاكرة والسرعة. ولكن هناك جانب آخر غالبًا ما يتم تجاهله — إمكانية الوصول. هذا ليس مجرد مصطلح عصري من عالم تطوير الويب. في C++، سهولة الوصول للتطبيقات تعني إتاحة الفرصة للأشخاص ذوي الإعاقات (ضعف البصر، السمع، الحركة) لاستخدام برامجك على قدم المساواة مع الآخرين.

\n\n

تخيل: لقد أنشأت محرر رسوميات رائعًا أو أداة سطر أوامر. ولكن إذا لم يتمكن قارئ الشاشة من قراءتها أو لم يتم التحكم بها عبر لوحة المفاتيح — فأنت تستبعد 15-20% من المستخدمين. بالإضافة إلى ذلك، غالبًا ما تكون إمكانية الوصول مطلبًا قانونيًا (مثلًا، في الولايات المتحدة — القسم 508، في أوروبا — EN 301 549).

\n\n

في هذه المقالة، سنشرح كيفية دمج أفضل ممارسات a11y (a11y — اختصار عددي لكلمة accessibility) في مشاريع C++ دون التضحية بالأداء. هيا بنا!

\n\n

من أين نبدأ: المبادئ الأساسية للكود الشامل

\n\n

قبل الخوض في الكود، تذكر الركائز الثلاث:

\n\n
    \n
  • الإدراك — يجب أن تكون المعلومات متاحة عبر حاسة واحدة على الأقل (البصر، السمع، اللمس).
  • \n
  • التحكم — يجب أن تعمل الواجهة مع لوحة المفاتيح، الصوت، أو المفاتيح التبديلية.
  • \n
  • الوضوح — سلوك العناصر متوقع، والأخطاء مفهومة.
  • \n
\n\n

في C++، هذا مهم بشكل خاص لأننا غالبًا ما نعمل مع واجهات برمجة تطبيقات منخفضة المستوى حيث تُفقد الدلالات. على سبيل المثال، عند رسم زر عبر OpenGL، لن تحصل على دعم تلقائي لقارئات الشاشة — بل تحتاج إلى إضافته يدويًا.

\n\n

الترميز الدلالي في واجهات C++ الرسومية: Qt وما بعده

\n\n

الطريقة الأكثر شيوعًا لإضافة إمكانية الوصول في C++ هي استخدام إطار العمل Qt. فهو يحتوي على دعم مدمج عبر QAccessibleInterface. ولكن حتى إذا كنت تكتب باستخدام WinAPI الخالص — فهناك IAccessible.

\n\n

مثال: جعل الزر متاحًا

\n\n

لنفترض أن لديك زرًا مخصصًا مرسومًا عبر QPainter. بدون إمكانية الوصول، سيرى قارئ الشاشة مجرد "مستطيل". نصلح ذلك:

\n\n
#include <QAccessible>\n#include <QAccessibleWidget>\n#include <QPushButton>\n\nclass AccessibleButton : public QAccessibleWidget {\npublic:\n    explicit AccessibleButton(QWidget* widget)\n        : QAccessibleWidget(widget, QAccessible::Button) {}\n\n    QString text(QAccessible::Text t) const override {\n        if (t == QAccessible::Name) {\n            auto* btn = qobject_cast<QPushButton*>(widget());\n            return btn ? btn->text() : QString();\n        }\n        return QAccessibleWidget::text(t);\n    }\n};\n\n// الاستخدام:\nQPushButton* btn = new QPushButton("إرسال");\nQAccessible::registerAccessibleFactory(\n    [](QObject* obj) -> QAccessibleInterface* {\n        if (auto* btn = qobject_cast<QPushButton*>(obj)) {\n            return new AccessibleButton(btn);\n        }\n        return nullptr;\n    }\n);
\n\n

الآن سيقرأ قارئ الشاشة "إرسال، زر". سحر؟ لا، إنه مجرد كود شامل.

\n\n

إمكانية الوصول في تطبيقات سطر الأوامر C++

\n\n

قد يبدو سطر الأوامر من الماضي. لكن العديد من الأدوات وخطوط أنابيب CI/CD وتطبيقات الخادم تعمل في الطرفية. كيف نجعلها متاحة؟

\n\n

الإخراج الصحيح لقارئات الشاشة

\n\n

قارئ الشاشة (مثل NVDA، JAWS) يقرأ الطرفية سطرًا بسطر. إذا كنت تعرض جدولًا برموز ASCII — فهذا كابوس. الأفضل استخدام إخراج هيكلي:

\n\n
#include <iostream>\n#include <string>\n#include <vector>\n\nstruct User {\n    std::string name;\n    int age;\n};\n\nvoid printAccessibleTable(const std::vector<User>& users) {\n    // مناسب لقارئ الشاشة: أولاً العنوان، ثم البيانات\n    std::cout << "جدول المستخدمين:" << std::endl;\n    for (const auto&                

المدونات

توصيات الكتب