أكثر

الحصول على قيم من عناصر واجهة Qt واستخدامها كمخزن مؤقت

الحصول على قيم من عناصر واجهة Qt واستخدامها كمخزن مؤقت


أنا أكتب مكونًا إضافيًا بسيطًا يجد المخزن المؤقت. يحتوي واجهة المستخدم الرسومية على صندوقين تحرير وسطر واحد. سيحتوي مربع التحرير والسرد الأول على قائمة منسدلة للقيم من العمود "الولايات" وسيعرض التحرير والسرد الثاني قائمة منسدلة بالقيم من العمود "المدن". لاحظ أنه سيتم تصفية المدن في مربع التحرير والسرد وفقًا للحالات المحددة. ويحصل الخط الثالث على مسافة من المستخدم. نتيجة لذلك ، أريد مخزنًا مؤقتًا للمدن (من مربع التحرير والسرد الثاني) مع تحديد المستخدم "قيمة المسافة" الواردة في مربع تحرير السطر. لقد جربت وظيفة QgsGeometryAnalyzer (). buffer () في QGIS API. لكن الوسيطة الأولى هي طبقة للدالة المذكورة أعلاه. بدلاً من ذلك ، أريد أن يأخذ واجهة المستخدم الخاصة بي قيمة من التحرير والسرد في المدينة والعثور على المخزن المؤقت. كيف تنجز. آسف لمنصب طويلة.


أعتقد أن هذا يمكن أن يساعدك:

# احصل على المسافة العازلة وتقسيم المدينة المحدد = تعويم (myLineEdit.text ()) city = myComboBo.currentText () # احصل على الميزة المقابلة لمدينة expr المحددة = QgsExpression ('"Cities" =  "+ city +' " ) it = myLayer.getFeatures (QgsFeatureRequest (expr)) feature = it.next () # قم بإجراء مخزن مؤقت على هندسة الميزة myBufferPolygon = feature.geometry (). المخزن المؤقت (dist ، 50)

ثم يمكنك استخدامmyBufferPolygonلإنشاء ميزة جديدة وتخزينها في طبقة متجه أخرى أو شيء من هذا القبيل.


كيو تي هيكل الرسم البياني للمشهد السريع

يتكون الرسم البياني للمشهد من عدد من أنواع العقد المحددة مسبقًا ، كل منها يخدم غرضًا مخصصًا. على الرغم من أننا نشير إليها على أنها رسم بياني للمشهد ، إلا أن التعريف الأكثر دقة هو شجرة العقد. تم بناء الشجرة من أنواع QQuickItem في مشهد QML وداخليًا تتم معالجة المشهد بواسطة جهاز عرض يرسم المشهد. العقد نفسها تفعل ليس تحتوي على أي رمز رسم نشط أو وظيفة paint () الافتراضية.

على الرغم من أن شجرة العقدة يتم بناؤها في الغالب داخليًا بواسطة أنواع Qt Quick QML الحالية ، فمن الممكن أيضًا للمستخدمين إضافة أشجار فرعية كاملة مع المحتوى الخاص بهم ، بما في ذلك الأشجار الفرعية التي تمثل نماذج ثلاثية الأبعاد.

العقد

العقدة الأكثر أهمية للمستخدمين هي QSGGeometryNode. يتم استخدامه لتحديد الرسومات المخصصة من خلال تحديد هندستها والمواد. يتم تعريف الهندسة باستخدام QSGGeometry ويصف شكل أو شبكة الرسم البدائي. يمكن أن يكون خطًا أو مستطيلًا أو مضلعًا أو العديد من المستطيلات غير المتصلة أو شبكة ثلاثية الأبعاد معقدة. تحدد المادة كيفية تعبئة وحدات البكسل في هذا الشكل.

يمكن أن تحتوي العقدة على أي عدد من العناصر الفرعية وسيتم عرض العقد الهندسية بحيث تظهر بالترتيب الفرعي مع وجود الآباء خلف أطفالهم.

ملحوظة: هذا لا يقول أي شيء عن ترتيب العرض الفعلي في العارض. يتم ضمان الإخراج المرئي فقط.

تنفذ وظيفة القطع في الرسم البياني للمشهد

يستخدم لجميع المحتويات المعروضة في الرسم البياني للمشهد

الفئة الأساسية لجميع العقد في الرسم البياني للمشهد

تستخدم لتغيير عتامة العقد

ينفذ التحولات في الرسم البياني للمشهد

تتم إضافة العقد المخصصة إلى الرسم البياني للمشهد عن طريق التصنيف الفرعي QQuickItem :: updatePaintNode () وتعيين علامة QQuickItem :: ItemHasContents.

تحذير: من الأهمية بمكان أن تحدث عمليات الرسومات الأصلية (OpenGL ، و Vulkan ، و Metal ، وما إلى ذلك) والتفاعل مع الرسم البياني للمشهد حصريًا على مؤشر ترابط العرض ، بشكل أساسي أثناء استدعاء updatePaintNode (). القاعدة العامة هي استخدام الفئات ذات البادئة "QSG" داخل دالة QQuickItem :: updatePaintNode ().

المعالجة

تحتوي العقد على وظيفة QSGNode :: preprocess () ، والتي سيتم استدعاؤها قبل عرض الرسم البياني للمشهد. يمكن للفئات الفرعية للعقدة تعيين العلامة QSGNode :: UsePreprocess وتجاوز وظيفة QSGNode :: preprocess () للقيام بالإعداد النهائي للعقد الخاصة بهم. على سبيل المثال ، قسمة منحنى بيزير على المستوى الصحيح من التفاصيل لعامل القياس الحالي أو تحديث قسم من نسيج.

ملكية العقدة

تتم ملكية العقد إما صراحةً بواسطة المنشئ أو بواسطة الرسم البياني للمشهد من خلال تعيين العلامة QSGNode :: OwnedByParent. غالبًا ما يكون تعيين ملكية الرسم البياني للمشهد هو الأفضل لأنه يبسط عملية التنظيف عندما يعيش الرسم البياني للمشهد خارج مؤشر ترابط واجهة المستخدم الرسومية.

المواد

تصف المادة كيفية ملء الجزء الداخلي من الهندسة في QSGGeometryNode. يقوم بتغليف تظليل الرسومات لمراحل الذروة والجزء من خط أنابيب الرسومات ويوفر مرونة كبيرة فيما يمكن تحقيقه ، على الرغم من أن معظم عناصر Qt Quick نفسها تستخدم فقط المواد الأساسية للغاية ، مثل الألوان الصلبة وتعبئة النسيج.

بالنسبة للمستخدمين الذين يرغبون فقط في تطبيق تظليل مخصص على نوع عنصر QML ، من الممكن القيام بذلك مباشرة في QML باستخدام نوع ShaderEffect.

فيما يلي قائمة كاملة بفئات المواد:

طريقة ملائمة لتقديم هندسة ملونة صلبة في الرسم البياني للمشهد

يغلف حالة العرض لبرنامج تظليل

يمثل برنامج تظليل مستقل لواجهة برمجة تطبيقات الرسومات

يمثل برنامج تظليل OpenGL في العارض

تستخدم كنوع فريد من نوعه في تركيبة مع QSGMaterial

طريقة ملائمة لتقديم هندسة منسوجة في الرسم البياني للمشهد

طريقة ملائمة لعرض هندسة منسوجة في الرسم البياني للمشهد

طريقة ملائمة لتقديم هندسة ملونة لكل رأس في الرسم البياني للمشهد

العقد الملائمة

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

    - فئة فرعية QSGGeometryNode التي تحدد هندسة مستطيلة مع مادة صلبة اللون. - فئة فرعية QSGGeometryNode التي تحدد هندسة مستطيلة مع مادة نسيج.

توثيق نوع العضو

تعداد QWidget :: RenderFlag أعلام QWidget :: RenderFlags

يصف هذا التعداد كيفية عرض الأداة عند استدعاء QWidget :: render ().

مستمرقيمةوصف
QWidget :: DrawWindowBackground 0x1 إذا قمت بتمكين هذا الخيار ، يتم عرض خلفية عنصر واجهة المستخدم في الهدف حتى إذا لم يتم تعيين autoFillBackground. افتراضيا، يتم تمكين هذا الخيار.
QWidget :: DrawChildren 0x2 إذا قمت بتمكين هذا الخيار ، فسيتم تجسيد العناصر الفرعية لعنصر واجهة المستخدم بشكل متكرر في الهدف. افتراضيا، يتم تمكين هذا الخيار.
QWidget :: IgnoreMask 0x4 إذا قمت بتمكين هذا الخيار ، فسيتم تجاهل QWidget :: mask () الخاص بالقطعة عند التقديم إلى الهدف. افتراضيا، يتم تعطيل هذا الخيار.

تم تقديم هذا التعداد أو تعديله في Qt 4.3.

نوع RenderFlags هو نوع محرف لـ QFlags & ltRenderFlag & gt. يقوم بتخزين مجموعة OR من قيم RenderFlag.


برمجة C ++ GUI مع Qt4: إنشاء عناصر واجهة مستخدم مخصصة

التخزين المؤقت المزدوج هو تقنية برمجة واجهة المستخدم الرسومية تتكون من تقديم عنصر واجهة مستخدم إلى خريطة بيكسل خارج الشاشة ونسخ خريطة بيكسل على الشاشة. مع الإصدارات السابقة من Qt ، تم استخدام هذه التقنية بشكل متكرر للتخلص من الوميض ولتوفير واجهة مستخدم أكثر ذكاءً.

في Qt 4 ، QWidget يتعامل مع هذا تلقائيًا ، لذلك نادرًا ما نحتاج إلى القلق بشأن وميض الأدوات. ومع ذلك ، يظل التخزين المؤقت المزدوج الصريح مفيدًا إذا كان عرض عنصر واجهة المستخدم معقدًا ومطلوبًا بشكل متكرر. يمكننا بعد ذلك تخزين خريطة pixmap بشكل دائم مع الأداة ، وتكون دائمًا جاهزة لحدث الرسم التالي ، ونسخ الخريطة البيكسية إلى عنصر واجهة المستخدم كلما تلقينا حدث رسم. إنه مفيد بشكل خاص عندما نريد إجراء تعديلات صغيرة ، مثل رسم شريط مطاطي ، دون إعادة حساب عرض الأداة بالكامل مرارًا وتكرارًا.

سنختتم هذا الفصل بمراجعة متآمر عنصر واجهة مستخدم مخصص موضح في الشكلين 5.7 و 5.9. تستخدم هذه الأداة التخزين المؤقت المزدوج وتوضح بعض الجوانب الأخرى لبرمجة Qt ، بما في ذلك معالجة حدث لوحة المفاتيح والتخطيط اليدوي وأنظمة الإحداثيات.

بالنسبة إلى التطبيق الحقيقي الذي يحتاج إلى عنصر واجهة مستخدم للرسم البياني أو التخطيط ، بدلاً من إنشاء عنصر واجهة مستخدم مخصص كما نفعل هنا ، فمن المرجح أن نستخدم إحدى أدوات الطرف الثالث المتوفرة. على سبيل المثال ، قد نستخدم GraphPak من http://www.ics.com/ أو مخطط دينار كويتي من http://www.kdab.net/ أو Qwt من http://qwt.sourceforge.net/.

ال متآمر يعرض عنصر واجهة المستخدم واحدًا أو أكثر من المنحنيات المحددة كمتجهات للإحداثيات. يمكن للمستخدم رسم شريط مطاطي على الصورة ، و متآمر سيتم تكبير المنطقة المحاطة بالشريط المطاطي. يقوم المستخدم برسم الشريط المطاطي عن طريق النقر فوق نقطة على الرسم البياني ، وسحب الماوس إلى موضع آخر مع الاستمرار في الضغط على زر الماوس الأيسر ، ثم تحرير زر الماوس. يوفر كيو تي QRubberBand فصل دراسي لرسم الأربطة المطاطية ، ولكن هنا نرسمها بأنفسنا لنتمكن من التحكم بشكل أفضل في الشكل ، ولإظهار التخزين المؤقت المزدوج

يمكن للمستخدم التكبير بشكل متكرر عن طريق رسم شريط مطاطي عدة مرات ، والتصغير باستخدام تصغير الزر ثم إعادة التكبير باستخدام ملف تكبير زر. ال تكبير و تصغير تظهر الأزرار في المرة الأولى التي تصبح فيها متاحة بحيث لا تفسد العرض إذا لم يقم المستخدم بتكبير الرسم البياني.

ال متآمر القطعة يمكن أن تحتفظ بالبيانات لأي عدد من المنحنيات. كما أنها تحافظ على كومة من المؤامرة كائنات ، كل منها يتوافق مع مستوى تكبير معين.

لنراجع الفصل ، بدءًا من الراسمة:

نبدأ بتضمين ملفات الرأس لفئات Qt التي يتم استخدامها في ملف رأس الراسمة ، والإعلان عن الفئات التي تحتوي على مؤشرات أو مراجع في الرأس.

في ال متآمر فئة ، نحن نقدم ثلاث وظائف عامة لإعداد المؤامرة ، وفتحتان عامتان للتكبير والتصغير. نحن أيضا نعيد التنفيذ الحد الأدنى للحجم تلميح () و الحجم تلميح () من QWidget. نقوم بتخزين نقاط المنحنى كملف QVector & LTQPointF & GT، أين QPointF هي نسخة النقطة العائمة من QPoint.

في القسم المحمي من الفصل ، نعلن جميع ملفات QWidget معالجات الأحداث التي نريد إعادة تنفيذها.

في القسم الخاص من الفصل ، نعلن عن بعض الوظائف لطلاء عنصر واجهة المستخدم ومتغيرات ثابتة ومتغيرات متعددة للأعضاء. ال حافة ثابت يستخدم لتوفير بعض التباعد حول الرسم البياني.

من بين المتغيرات الأعضاء خريطة بكسل من النوع QPixmap. يحتفظ هذا المتغير بنسخة من عرض عنصر واجهة المستخدم بالكامل ، وهو مطابق لما يظهر على الشاشة. يتم رسم المؤامرة دائمًا على هذه الخريطة البيكسلية خارج الشاشة أولاً ، ثم يتم نسخ الخريطة البيكسلية إلى عنصر واجهة المستخدم.

ال المؤامرة فئة تحدد نطاق x- و ذ- المحاور وعدد التكات لهذه المحاور. يوضح الشكل 5.8 المراسلات بين أ المؤامرة كائن و متآمر القطعة.

بالإقناع، numXTicks و عدد يتم إيقافه بواحد إذا numXTicks هو 5 متآمر سيرسم بالفعل ست علامات التجزئة على x-محور. هذا يبسط العمليات الحسابية في وقت لاحق.

لنراجع الآن ملف التنفيذ:

ال setBackgroundRole () يقول المكالمة QWidget لاستخدام المكون "الداكن" في اللوحة كلون لمسح عنصر واجهة المستخدم ، بدلاً من مكون "النافذة". يمنح هذا Qt لونًا افتراضيًا يمكن استخدامه لملء أي وحدات بكسل تم الكشف عنها حديثًا عند تغيير حجم الأداة إلى حجم أكبر ، قبل paintEvent () حتى أن لديه فرصة لرسم وحدات البكسل الجديدة. نحن أيضا بحاجة للاتصال setAutoFillBackground (صحيح) لتمكين هذه الآلية. (بشكل افتراضي ، ترث عناصر واجهة المستخدم الفرعية الخلفية من عنصر واجهة المستخدم الأصلي.)

ال setSizePolicy () المكالمة تعيّن سياسة حجم الأداة إلى QSizePolicy :: توسيع في كلا الاتجاهين. يخبر هذا أي مدير تخطيط مسؤول عن عنصر واجهة المستخدم أن عنصر واجهة المستخدم يرغب بشكل خاص في النمو ، ولكن يمكن أن يتقلص أيضًا. هذا الإعداد نموذجي للأدوات التي يمكن أن تشغل مساحة كبيرة على الشاشة. الافتراضي هو QSizePolicy :: المفضل في كلا الاتجاهين ، مما يعني أن الأداة تفضل أن تكون بحجم تلميح حجمها ، ولكن يمكن تصغيرها إلى الحد الأدنى لتلميح الحجم أو توسيعها إلى أجل غير مسمى إذا لزم الأمر.

ال setFocusPolicy (Qt :: StrongFocus) تجعل المكالمة الأداة تقبل التركيز عن طريق النقر أو الضغط فاتورة غير مدفوعة. عندما متآمر التركيز ، وسوف تتلقى الأحداث للمطابع الرئيسية. ال متآمر القطعة تتفهم بعض المفاتيح: + للتكبير - للتصغير ومفاتيح الأسهم للتمرير لأعلى ولأسفل ولليسار ولليمين.

ما زلنا في المنشئ ، نقوم بإنشاء اثنين QToolButtons ، كل منها برمز. تسمح هذه الأزرار للمستخدم بالتكبير والتصغير. يتم تخزين أيقونات الأزرار في ملف موارد ، لذلك فإن أي تطبيق يستخدم امتداد متآمر القطعة ستحتاج هذا الإدخال في ملف .طليعة ملف:

ملف المورد مشابه للملف الذي استخدمناه لتطبيق جدول البيانات:

ال ضبط الحجم () المكالمات على الأزرار تحدد أحجامها لتكون بنفس حجم تلميحاتها. لا يتم وضع الأزرار في تخطيط بدلاً من ذلك ، فسنقوم بوضعها يدويًا في ملف متآمرحدث تغيير الحجم. نظرًا لأننا لا نستخدم أي تخطيطات ، يجب علينا تحديد أصل الأزرار صراحة عن طريق التمرير هذه الى QToolButton البناء.

الدعوة إلى setPlotSettings () في النهاية يكمل التهيئة.

ال setPlotSettings () يتم استخدام الوظيفة لتحديد المؤامرة لاستخدامها في عرض المؤامرة. يتم استدعاؤه بواسطة متآمر المُنشئ ويمكن استدعاؤه من قبل مستخدمي الفصل. يبدأ المخطط عند مستوى التكبير الافتراضي الخاص به. في كل مرة يقوم فيها المستخدم بالتكبير ، يكون ملف المؤامرة يتم إنشاء المثيل ووضعه على مكدس التكبير. يتم تمثيل مكدس التكبير بواسطة متغيرين من الأعضاء:

  • ZoomStack يحمل إعدادات التكبير المختلفة كملف QVector & ltPlotSettings & GT.
  • curZoom يحمل التيار المؤامرةالفهرس في ZoomStack.

بعد المكالمة setPlotSettings ()، يحتوي مكدس التكبير / التصغير على إدخال واحد فقط ، و تكبير و تصغير الأزرار مخفية. لن تظهر هذه الأزرار حتى نتصل تبين() عليها في تكبير () و تصغير() فتحات. (عادة ، يكفي الاتصال تبين() على أداة المستوى الأعلى لإظهار جميع الأطفال. ولكن عندما ندعو صراحة إخفاء() على عنصر واجهة مستخدم طفل ، يتم إخفاؤه حتى ندعو تبين() عليه.)

الدعوة إلى RefreshPixmap () ضروري لتحديث العرض. عادة ، كنا نتصل تحديث()، ولكننا هنا نقوم بالأشياء بشكل مختلف قليلاً لأننا نريد الاحتفاظ بامتداد QPixmap محدثة في جميع الأوقات. بعد إعادة إنشاء الخريطة البيكسلية ، RefreshPixmap () المكالمات تحديث() لنسخ خريطة بيكسل على القطعة.

ال تصغير() يتم تصغير الفتحة إذا تم تكبير الرسم البياني. إنه يقلل من مستوى التكبير الحالي ويمكّن تصغير زر اعتمادًا على ما إذا كان يمكن تصغير الرسم البياني أكثر من ذلك أم لا. ال تكبير تم تمكين الزر وعرضه ، ويتم تحديث الشاشة بمكالمة إلى RefreshPixmap ().

إذا قام المستخدم مسبقًا بالتكبير ثم التصغير مرة أخرى ، فإن ملف المؤامرة سيكون مستوى التكبير التالي في مكدس التكبير / التصغير ، ويمكننا التكبير. (بخلاف ذلك ، لا يزال من الممكن التكبير باستخدام شريط مطاطي.)

زيادات الفتحة curZoom للانتقال إلى مستوى أعمق في مكدس التكبير / التصغير ، يعيّن تكبير تم تمكين الزر أو تعطيله اعتمادًا على ما إذا كان من الممكن التكبير بشكل أكبر ، ويمكّن ويعرض ملف تصغير زر. مرة أخرى ، نحن ندعو RefreshPixmap () لجعل الراسمة يستخدم أحدث إعدادات التكبير / التصغير.

ال setCurveData () تحدد الوظيفة بيانات المنحنى لمعرف منحنى معين. إذا كان منحنى بنفس المعرف موجودًا بالفعل في منحنى، يتم استبداله ببيانات المنحنى الجديدة وإلا يتم إدخال المنحنى الجديد ببساطة. ال منحنى متغير العضو من النوع QMap & ltint و QVector & ltQPointF & GT & GT.

ال clearCurve () تعمل الوظيفة على إزالة المنحنى المحدد من خريطة المنحنى.

ال الحد الأدنى للحجم تلميح () وظيفة مشابهة ل الحجم تلميح (). نحن فقط الحجم تلميح () يحدد الحجم المثالي لعنصر واجهة مستخدم ، الحد الأدنى للحجم تلميح () يحدد الحد الأدنى للحجم المثالي لعنصر واجهة مستخدم. لا يقوم التخطيط أبدًا بتغيير حجم عنصر واجهة المستخدم إلى ما دون تلميح الحجم الأدنى.

القيمة التي نرجعها هي 300 × 200 (منذ ذلك الحين حافة يساوي 50) للسماح بالهامش على الجوانب الأربعة وبعض المساحة للمخطط نفسه. أقل من هذا الحجم ، ستكون الحبكة صغيرة جدًا لتكون مفيدة.

في الحجم تلميح ()، نعيد الحجم "المثالي" بما يتناسب مع حافة ثابت وبنفس نسبة العرض إلى الارتفاع 3: 2 التي استخدمناها لـ الحد الأدنى للحجم تلميح ().

هذا ينتهي من استعراض متآمروظائف وفتحات العامة. الآن دعنا نراجع معالجات الأحداث المحمية.

إذا كان الشريط المطاطي مرئيًا ، فنحن نرسمه أعلى المؤامرة. نستخدم مكون "فاتح" من مجموعة الألوان الحالية لعنصر واجهة المستخدم كلون قلم لضمان تباين جيد مع الخلفية "الداكنة". لاحظ أننا نرسم مباشرة على الأداة ، مع ترك خريطة بيكسل خارج الشاشة دون تغيير. استخدام QRect :: عادي () يضمن أن مستطيل الشريط المطاطي له عرض وارتفاع موجبان (تبديل الإحداثيات إذا لزم الأمر) ، و تعديل () يقلل حجم المستطيل بمقدار بكسل واحد للسماح بمخطط تفصيلي بعرض 1 بكسل.

إذا كان متآمر التركيز ، يتم رسم مستطيل التركيز باستخدام نمط عنصر واجهة المستخدم drawPrimitive () تعمل مع QStyle :: PE_FrameFocusRect كحجة أولى وأ QStyleOptionFocusRect الوسيطة الثانية. تتم تهيئة خيارات رسم مستطيل التركيز بناءً على ملف متآمر القطعة (بواسطة initFrom () مكالمة). يجب تحديد لون الخلفية بشكل صريح.

عندما نريد الرسم باستخدام النمط الحالي ، يمكننا إما استدعاء a QStyle تعمل مباشرة ، على سبيل المثال ،

أو استخدم أ QStyle الرسام بدلا من العادي Q الرسام، كما فعلنا في متآمر، والطلاء بسهولة أكبر باستخدام ذلك.

ال QWidget :: style () تقوم الدالة بإرجاع النمط الذي يجب استخدامه لرسم عنصر واجهة المستخدم. في Qt ، يعد نمط عنصر واجهة المستخدم فئة فرعية من QStyle. تشمل الأنماط المضمنة QWindowsStyle, QWindowsXPStyle, QWindowsVistaStyle, QMotifStyle, QCDEle, QMacStyle, QPlastiqueStyle، و QCleanlooksStyle. كل نمط يعيد تنفيذ الوظائف الافتراضية في QStyle لأداء الرسم بالطريقة الصحيحة للنظام الأساسي الذي يحاكي النمط. QStyle الرسامdrawPrimitive () وظيفة تستدعي ال QStyle الوظيفة التي تحمل الاسم نفسه ، والتي يمكن استخدامها لرسم "العناصر البدائية" مثل اللوحات والأزرار ومستطيلات التركيز. عادة ما يكون نمط عنصر واجهة المستخدم هو نفسه لجميع عناصر واجهة المستخدم في التطبيق (QApplication :: style ()) ، ولكن يمكن تجاوزه على أساس كل عنصر واجهة مستخدم باستخدام QWidget :: setStyle ().

حسب التصنيف الفرعي QStyle، من الممكن تحديد نمط مخصص. يمكن القيام بذلك لإعطاء نظرة مميزة لتطبيق أو مجموعة من التطبيقات ، كما سنرى في الفصل 19. بينما يُنصح عمومًا باستخدام الشكل والمظهر الأصلي للنظام الأساسي المستهدف ، توفر Qt الكثير من المرونة إذا كنت تريد أن تكون مغامرًا.

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

كلما كان متآمر تم تغيير حجم القطعة ، ينشئ Qt حدث "تغيير الحجم". هنا ، نعيد التنفيذ تغيير حجم الحدث () لوضع ال تكبير و تصغير في أعلى يمين ملف متآمر القطعة.

ننقل تكبير زر و تصغير يكون الزر جنبًا إلى جنب ، مفصولة بفجوة تبلغ 5 بكسل ومع إزاحة 5 بكسل من الحواف العلوية واليمنى لعنصر واجهة المستخدم الأصلي.

إذا أردنا أن تظل الأزرار متجذرة في الزاوية العلوية اليسرى ، وإحداثياتها (0 ، 0) ، فسنقوم ببساطة بنقلها إلى هناك في متآمر البناء. لكننا نريد تتبع الزاوية العلوية اليمنى ، والتي تعتمد إحداثياتها على حجم الأداة. لهذا السبب ، من الضروري إعادة التنفيذ تغيير حجم الحدث () ولضبط موضع الأزرار هناك.

لم نضع أي مواضع للأزرار الموجودة في متآمر البناء. هذه ليست مشكلة ، حيث أن Qt تقوم دائمًا بإنشاء حدث تغيير الحجم قبل عرض عنصر واجهة المستخدم لأول مرة.

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

في النهاية نتصل RefreshPixmap () لإعادة رسم الخريطة البيكسلية بالحجم الجديد.

عندما يضغط المستخدم على زر الفأرة الأيسر ، نبدأ في عرض شريط مطاطي. هذا ينطوي على الإعداد المطاط ل حقيقية، تهيئة المطاط متغير عضو مع موضع مؤشر الماوس الحالي ، وجدولة حدث رسم لطلاء الشريط المطاطي ، وتغيير مؤشر الماوس ليكون له شكل التقاطع.

ال المطاط المتغير من النوع QRect. أ QRect يمكن تعريفها إما على أنها (x, ذ, العرض, ارتفاع) رباعي & # 8212 حيث (x, ذ) هو موضع الزاوية اليسرى العلوية و العرض x ارتفاع هو حجم المستطيل & # 8212 أو كزوج إحداثي أعلى اليسار وأسفل يمين. هنا ، استخدمنا تمثيل زوج الإحداثيات. قمنا بتعيين النقطة التي نقر فيها المستخدم على الزاوية العلوية اليسرى والزاوية اليمنى السفلية. ثم نتصل تحديث لفرض إعادة طلاء المنطقة (الصغيرة) التي يغطيها الشريط المطاطي.

يوفر Qt آليتين للتحكم في شكل مؤشر الماوس:

  • QWidget :: setCursor () يعيّن شكل المؤشر الذي سيتم استخدامه عند تمرير الماوس فوق عنصر واجهة مستخدم معين. إذا لم يتم تعيين مؤشر لعنصر واجهة مستخدم ، فسيتم استخدام مؤشر عنصر واجهة المستخدم الأصل. الافتراضي لأدوات المستوى الأعلى هو مؤشر السهم.
  • QApplication :: setOverrideCursor () يعيّن شكل المؤشر للتطبيق بأكمله ، متجاوزًا المؤشرات التي تم تعيينها بواسطة عناصر واجهة مستخدم فردية حتى RecoveryOverrideCursor () يسمى.

في الفصل 4 ، دعونا QApplication :: setOverrideCursor () مع كيو تي :: WaitCursor لتغيير مؤشر التطبيق إلى مؤشر الانتظار القياسي.

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

إذا قام المستخدم بتحريك الماوس لأعلى أو لليسار ، فمن المحتمل أن يكون ذلك المطاطستنتهي الزاوية السفلية اليمنى الاسمية لـ أعلى أو إلى يسار الزاوية العلوية اليسرى. إذا حدث هذا ، فإن ملف QRect سيكون لها عرض أو ارتفاع سلبي. كنا QRect :: عادي () في paintEvent () لضمان تعديل الإحداثيات العلوية اليسرى والسفلية اليمنى للحصول على عرض وارتفاع غير سالبين.

عندما يحرر المستخدم زر الماوس الأيسر ، نقوم بمسح الشريط المطاطي واستعادة مؤشر السهم القياسي. إذا كان الشريط المطاطي 4 × 4 على الأقل ، فإننا نقوم بالتكبير. إذا كان الشريط المطاطي أصغر من ذلك ، فمن المحتمل أن المستخدم نقر على الأداة عن طريق الخطأ أو للتركيز عليها ، لذلك نحن لا نفعل شيئًا.

رمز إجراء التكبير / التصغير معقد بعض الشيء. هذا لأننا نتعامل مع إحداثيات عنصر واجهة المستخدم وإحداثيات الراسمة في نفس الوقت. معظم العمل الذي نقوم به هنا هو تحويل ملف المطاط من إحداثيات القطعة إلى إحداثيات الراسمة. بمجرد الانتهاء من التحويل ، ندعو PlotSettings :: ضبط () لتقريب الأرقام وإيجاد عدد معقول من العلامات لكل محور. يوضح الشكلان 5.10 و 5.11 العملية.

الشكل 5.10 تحويل الشريط المطاطي من إحداثيات القطعة إلى إحداثيات الراسمة

الشكل 5.11 ضبط إحداثيات الراسمة والتكبير على الشريط المطاطي

ثم نقوم بالتكبير. يتم تحقيق التكبير عن طريق دفع الجديد المؤامرة التي حسبناها للتو في أعلى مكدس التكبير والاستدعاء تكبير () للقيام بهذه المهمة.

عندما يضغط المستخدم على مفتاح و متآمر القطعة لديها التركيز ، و keyPressEvent () الوظيفة تسمى. نعيد تطبيقه هنا للرد على ستة مفاتيح: +, -, فوق, أسفل, متبقى، و حق. إذا ضغط المستخدم على مفتاح لا نتعامل معه ، فإننا نسمي تطبيق الفئة الأساسية. من أجل البساطة ، نتجاهل تحول, كنترول، و بديل مفاتيح التعديل المتوفرة من خلال QKeyEvent :: المعدلات ().

تحدث أحداث العجلة عند تدوير عجلة الفأرة. توفر معظم الفئران عجلة عمودية فقط ، ولكن بعضها يحتوي أيضًا على عجلة أفقية. تدعم Qt كلا النوعين من العجلات. تنتقل أحداث العجلة إلى الأداة التي تركز عليها. ال دلتا () تُرجع الدالة المسافة التي تم تدوير العجلة فيها بثمان درجة. تعمل الفئران عادة في درجات 15 درجة. هنا ، نقوم بالتمرير حسب العدد المطلوب من العلامات عن طريق تعديل العنصر الأعلى في مكدس التكبير وتحديث العرض باستخدام RefreshPixmap ().

الاستخدام الأكثر شيوعًا لعجلة الماوس هو تمرير شريط التمرير. عندما نستخدم ملفات QScrollArea (تمت تغطيته في الفصل 6) لتوفير أشرطة تمرير ، QScrollArea يتعامل مع أحداث عجلة الماوس تلقائيًا ، لذلك لا نحتاج إلى إعادة التنفيذ wheelEvent () أنفسنا.

هذا ينتهي من تنفيذ معالجات الحدث. الآن دعنا نراجع الوظائف الخاصة.

ال تحديث يتم استدعاء الوظيفة من MousePressEvent (), MouseMoveEvent ()، و MouseReleaseEvent () لمحو الشريط المطاطي أو إعادة رسمه. يتكون من أربع مكالمات إلى تحديث() هذا الجدول الزمني لحدث طلاء للمناطق المستطيلة الأربعة الصغيرة التي يغطيها الشريط المطاطي (خطان عموديان وخطان أفقيان).

ال RefreshPixmap () تعيد الوظيفة رسم المؤامرة على الخريطة البيكسلية خارج الشاشة وتقوم بتحديث العرض. نقوم بتغيير حجم الخريطة البيكسيلية ليكون لها نفس حجم القطعة ونملأها بلون محو الأداة. هذا اللون هو المكون "الداكن" في اللوحة ، بسبب استدعاء setBackgroundRole () في ال متآمر البناء. إذا كانت الخلفية عبارة عن فرشاة غير صلبة ، QPixmap :: fill () يحتاج إلى معرفة الإزاحة في عنصر واجهة المستخدم حيث سينتهي الأمر بالخريطة البيكسية لمحاذاة نمط الفرشاة بشكل صحيح. هنا ، تتوافق الخريطة البيكسية مع عنصر واجهة المستخدم بالكامل ، لذلك نحدد الموضع (0 ، 0).

ثم نقوم بإنشاء ملف Q الرسام للرسم على خريطة بيكسل. ال initFrom () تعين المكالمة قلم الرسام وخلفيته وخطه على نفس ألوان متآمر القطعة. بعد ذلك ، ندعو drawGrid () و drawCurves () لأداء الرسم. في النهاية نتصل تحديث() لجدولة حدث رسم لعنصر واجهة المستخدم بأكمله. يتم نسخ الخريطة البيكسيلية إلى عنصر واجهة المستخدم في ملف paintEvent () وظيفة (ص 128).

ال drawGrid () وظيفة ترسم الشبكة خلف المنحنيات والمحاور. يتم تحديد المنطقة التي نرسم عليها الشبكة بواسطة مستقيم. إذا لم يكن حجم الأداة كبيرًا بما يكفي لاستيعاب الرسم البياني ، فسنعود على الفور.

الأول إلى عن على حلقة ترسم الخطوط العمودية للشبكة والعلامات على طول x-محور. الثاني إلى عن على حلقة ترسم الخطوط الأفقية للشبكة والعلامات على طول ذ-محور. في النهاية ، نرسم مستطيلًا على طول الهوامش. ال drawText () يتم استخدام الوظيفة لرسم الأرقام المقابلة لعلامات التجزئة على كلا المحورين.

المكالمات إلى drawText () لديك بناء الجملة التالي:

أين ( x, ذ, العرض, ارتفاع) تحديد مستطيل ، التنضيد موضع النص داخل هذا المستطيل ، و نص النص المراد رسمه. في هذا المثال ، قمنا بحساب المستطيل الذي نرسم فيه النص يدويًا ، قد يتضمن البديل الأكثر قابلية للتكيف حساب مستطيل إحاطة النص باستخدام QFontMetrics.

ال drawCurves () دالة ترسم المنحنيات أعلى الشبكة. نبدأ بالاتصال setClipRect () لتعيين Q الرساممنطقة قص للمستطيل الذي يحتوي على المنحنيات (باستثناء الهوامش والإطار حول الرسم البياني). Q الرسام سيتجاهل بعد ذلك عمليات الرسم على وحدات البكسل خارج المنطقة.

بعد ذلك ، نقوم بتكرار جميع المنحنيات باستخدام مكرر نمط جافا ، ولكل منحنى ، نقوم بالتكرار على مكونه QPointFس. نسمي المكرر مفتاح() وظيفة لاسترداد معرف المنحنى و القيمة() وظيفة لاسترداد بيانات المنحنى المقابلة كملف QVector & LTQPointF & GT. الداخل إلى عن على حلقة تحول كل QPointF من إحداثيات الراسمة إلى إحداثيات عنصر واجهة المستخدم ويخزنها في ملف متعدد الخطوط عامل.

بمجرد تحويل جميع نقاط المنحنى إلى إحداثيات عنصر واجهة المستخدم ، نقوم بتعيين لون القلم للمنحنى (باستخدام أحد مجموعة الألوان المحددة مسبقًا) وندعو drawPolyline () لرسم خط يمر عبر جميع نقاط المنحنى.

هذا هو الكامل متآمر صف دراسي. كل ما تبقى هو بعض الوظائف في المؤامرة.

ال المؤامرة يقوم المُنشئ بتهيئة كلا المحورين إلى النطاق من 0 إلى 10 بخمس علامات تجزئة.

ال التمرير () زيادات دالة (أو إنقاص) minX, ماكس, مين، و maxY من خلال الفترة الفاصلة بين علامتين مضروبة في رقم معين. تستخدم هذه الوظيفة لتنفيذ التمرير في الراسمة :: keyPressEvent ().

ال اضبط() يتم استدعاء الوظيفة من MouseReleaseEvent () لتقريب minX, ماكس, مين، و maxY القيم لقيم "لطيفة" ولتحديد عدد العلامات المناسبة لكل محور. الوظيفة الخاصة ضبط المحور () يقوم بعمله محور واحد في كل مرة.

ال ضبط المحور () الدالة تحول دقيقة و الأعلى المعلمات إلى أرقام "لطيفة" ويضع لها numTicks معلمة لعدد العلامات التي تحسبها لتكون مناسبة لـ [دقيقة, الأعلى] نطاق. لان ضبط المحور () يحتاج إلى تعديل المتغيرات الفعلية (minX, ماكس, numXTicks، وما إلى ذلك) وليست مجرد نسخ ، فإن معاملاتها هي مراجع غير ثابتة.

معظم التعليمات البرمجية بتنسيق ضبط المحور () يحاول ببساطة تحديد قيمة مناسبة للفاصل الزمني بين علامتين ("الخطوة"). للحصول على أرقام لطيفة على طول المحور ، يجب أن نختار الخطوة بعناية. على سبيل المثال ، قد تؤدي قيمة الخطوة 3.8 إلى محور به مضاعفات 3.8 ، وهو أمر يصعب على الأشخاص الارتباط به. بالنسبة للمحاور المسماة بالتدوين العشري ، فإن قيم الخطوة "اللطيفة" هي أرقام بالشكل 10 ن و 2 و middot10 ن ، أو 5 & middot10 ن .

نبدأ بحساب "الخطوة الإجمالية" ، وهي نوع من الحد الأقصى لقيمة الخطوة. ثم نجد الرقم المقابل في الصورة 10 ن أصغر من أو يساوي الخطوة الإجمالية. نقوم بذلك عن طريق أخذ اللوغاريتم العشري للخطوة الإجمالية ، وتقريب هذه القيمة إلى عدد صحيح ، ثم رفع 10 إلى أس هذا العدد المقرب. على سبيل المثال ، إذا كانت الخطوة الإجمالية هي 236 ، فإننا نحسب log 236 = 2.37291. ثم نقربها إلى 2 ونحصل على 10 2 = 100 كقيمة الخطوة المرشحة للنموذج 10 ن .

بمجرد أن نحصل على قيمة الخطوة الأولى المرشحة ، يمكننا استخدامها لحساب المرشحين الآخرين: 2 & middot10 ن و 5 و middot10 ن . بالنسبة للمثال السابق ، المرشحان الآخران هما 200 و 500. المرشح 500 أكبر من الخطوة الإجمالية ، لذلك لا يمكننا استخدامه. لكن 200 أصغر من 236 ، لذلك نستخدم 200 لحجم الخطوة في هذا المثال.

من السهل حسابها إلى حد ما numTicks, دقيقة، و الأعلى من قيمة الخطوة. الجديد دقيقة يتم الحصول على القيمة بتقريب الأصل دقيقة وصولا إلى أقرب مضاعف للخطوة ، والجديد الأعلى يتم الحصول على القيمة بالتقريب إلى أقرب مضاعف للخطوة. الجديد numTicks هو عدد الفترات بين التقريب دقيقة و الأعلى القيم. على سبيل المثال ، إذا دقيقة هو 240 و الأعلى هو 1184 عند دخول الوظيفة ، يصبح النطاق الجديد [200 ، 1200] ، مع خمس علامات.

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

يقودنا هذا الفصل إلى نهاية الجزء الأول من الكتاب. وأوضح كيفية تخصيص عنصر واجهة مستخدم Qt موجود وكيفية إنشاء عنصر واجهة مستخدم من الألف إلى الياء باستخدام QWidget كالفئة الأساسية. لقد رأينا بالفعل كيفية تخطيط عناصر واجهة المستخدم الفرعية باستخدام مديري التخطيط في الفصل 2 ، وسوف نستكشف الموضوع بشكل أكبر في الفصل 6.

في هذه المرحلة ، نعرف ما يكفي لكتابة تطبيقات واجهة المستخدم الرسومية الكاملة باستخدام Qt. في الجزأين الثاني والثالث ، سوف نستكشف Qt بعمق أكبر حتى نتمكن من الاستفادة الكاملة من طاقة Qt.


برمجة C ++ GUI مع Qt4: إنشاء عناصر واجهة مستخدم مخصصة

العديد من الحاجيات المخصصة هي ببساطة مجموعة من الحاجيات الموجودة ، سواء كانت عناصر واجهة مستخدم Qt مضمنة أو أدوات مخصصة أخرى مثل HexSpinBox. يمكن عادةً تطوير عناصر واجهة المستخدم المخصصة التي تم إنشاؤها عن طريق إنشاء عناصر واجهة مستخدم موجودة بتنسيق كيو تي مصمم:

  1. إنشاء نموذج جديد باستخدام نموذج "القطعة".
  2. أضف الأدوات الضرورية إلى النموذج ، وقم بتخطيطها.
  3. قم بإعداد اتصالات الإشارات والفتحات.
  4. إذا كان السلوك يتجاوز ما يمكن تحقيقه من خلال الإشارات والفواصل الزمنية مطلوبًا ، فاكتب الشفرة الضرورية في فئة مشتقة من كليهما QWidget و ال uicفئة ولدت.

بطبيعة الحال ، يمكن أيضًا دمج عناصر واجهة المستخدم الموجودة بالكامل في الكود. أيًا كان النهج المتبع ، فإن الطبقة الناتجة هي أ QWidget فئة فرعية.

إذا كانت الأداة لا تحتوي على إشارات وفتحات خاصة بها ولا تعيد تنفيذ أي وظائف افتراضية ، فمن الممكن ببساطة تجميع عنصر واجهة المستخدم من خلال دمج عناصر واجهة المستخدم الحالية بدون فئة فرعية. هذا هو الأسلوب الذي استخدمناه في الفصل 1 لإنشاء تطبيق Age ، بامتداد QWidget، أ QSpinBox، وأ QSlider. على الرغم من ذلك ، كان بإمكاننا بسهولة تصنيف الفئات الفرعية QWidget and created the QSpinBox و QSlider in the subclass's constructor.

When none of Qt's widgets are suitable for the task at hand, and when there is no way to combine or adapt existing widgets to obtain the desired result, we can still create the widget we want. This is achieved by subclassing QWidget and reimplementing a few event handlers to paint the widget and to respond to mouse clicks. This approach gives us complete freedom to define and control both the appearance and the behavior of our widget. Qt's built-in widgets, such as QLabel, QPushButton، و QTableWidget, are implemented this way. If they didn't exist in Qt, it would still be possible to create them ourselves using the public functions provided by QWidget in a completely platform-independent manner.

To demonstrate how to write a custom widget using this approach, we will create the IconEditor widget shown in Figure 5.2. ال IconEditor is a widget that could be used in an icon editing program.

In practice, before diving in and creating a custom widget, it is always worth checking whether the widget is already available, either as a Qt Solution (http://www.trolltech.com/products/qt/addon/solutions/catalog/4/) or from a commercial or non-commercial third party (http://www.trolltech.com/products/qt/3rdparty/), since this could save a lot of time and effort. In this case, we will assume that no suitable widget is available, and so we will create our own.

Let's begin by reviewing the header file.

ال IconEditor class uses the Q_PROPERTY() macro to declare three custom properties: penColor, iconImage، و zoomFactor. Each property has a data type, a "read" function, and an optional "write" function. على سبيل المثال ، ملف penColor property is of type QColor and can be read and written using the penColor() و setPenColor() المهام.

When we make use of the widget in Qt Designer, custom properties appear in Qt Designer's property editor below the properties inherited from QWidget. Properties may be of any type supported by QVariant. ال Q_OBJECT macro is necessary for classes that define properties.

IconEditor reimplements three protected functions from QWidget and has a few private functions and variables. The three private variables hold the values of the three properties.

The implementation file begins with the IconEditor's constructor:

The constructor has some subtle aspects, such as the Qt::WA_StaticContents attribute and the setSizePolicy() مكالمة. We will discuss them shortly.

The pen color is set to black. The zoom factor is set to 8, meaning that each pixel in the icon will be rendered as an 8 x 8 square.

The icon data is stored in the صورة member variable and can be accessed through the setIconImage() و iconImage() المهام. An icon editor program would typically call setIconImage() when the user opens an icon file and iconImage() to retrieve the icon when the user wants to save it. ال صورة variable is of type QImage. We initialize it to 16 x 16 pixels and 32-bit ARGB format, a format that supports semi-transparency. We clear the image data by filling it with a transparent color.

ال QImage class stores an image in a hardware-independent fashion. It can be set to use a 1-bit, 8-bit, or 32-bit depth. An image with 32-bit depth uses 8 bits for each of the red, green, and blue components of a pixel. The remaining 8 bits store the pixel's alpha component (opacity). For example, a pure red color's red, green, blue, and alpha components have the values 255, 0, 0, and 255. In Qt, this color can be specified as

or, since the color is opaque, as

QRgb is simply a typedef for unsigned int، و qRgb() و qRgba() are inline functions that combine their arguments into one 32-bit ARGB integer value. It is also possible to write

where the first FF corresponds to the alpha component and the second FF to the red component. في ال IconEditor constructor, we fill the QImage with a transparent color by using 0 as the alpha component.

Qt provides two types for storing colors: QRgb و QColor. بينما QRgb is only a typedef used in QImage to store 32-bit pixel data, QColor is a class with many useful functions and is widely used in Qt to store colors. في ال IconEditor widget, we use QRgb only when dealing with the QImage we use QColor for everything else, including the penColor خاصية.

ال sizeHint() function is reimplemented from QWidget and returns the ideal size of a widget. Here, we take the image size multiplied by the zoom factor, with one extra pixel in each direction to accommodate a grid if the zoom factor is 3 or more. (We don't show a grid if the zoom factor is 2 or 1, because then the grid would leave hardly any room for the icon's pixels.)

A widget's size hint is mostly useful in conjunction with layouts. Qt's layout managers try as much as possible to respect a widget's size hint when they lay out a form's child widgets. إلى عن على IconEditor to be a good layout citizen, it must report a credible size hint.

In addition to the size hint, widgets have a size policy that tells the layout system whether they like to be stretched and shrunk. By calling setSizePolicy() in the constructor with QSizePolicy::Minimum as horizontal and vertical policies, we tell any layout manager that is responsible for this widget that the widget's size hint is really its minimum size. In other words, the widget can be stretched if required, but it should never shrink below the size hint. This can be overridden in Qt Designer by setting the widget's sizePolicy خاصية. We explain the meaning of the various size policies in Chapter 6.

ال setPenColor() function sets the current pen color. The color will be used for newly drawn pixels.

ال setIconImage() function sets the image to edit. We call convertToFormat() to make the image 32-bit with an alpha buffer, if it isn't already. Elsewhere in the code, we will assume that the image data is stored as 32-bit ARGB values.

After setting the صورة variable, we call QWidget::update() to schedule a repainting of the widget using the new image. Next, we call QWidget::updateGeometry() to tell any layout that contains the widget that the widget's size hint has changed. The layout will then automatically adapt to the new size hint.

ال setZoomFactor() function sets the zoom factor for the image. To prevent division by zero elsewhere, we correct any value below 1. Again, we call update() و updateGeometry() to repaint the widget and to notify any managing layout about the size hint change.

ال penColor(), iconImage()، و zoomFactor() functions are implemented as inline functions in the header file.

We will now review the code for the paintEvent() وظيفة. This function is IconEditor's most important function. It is called whenever the widget needs repainting. The default implementation in QWidget does nothing, leaving the widget blank.

تماما مثل closeEvent(), which we met in Chapter 3, paintEvent() is an event handler. Qt has many other event handlers, each of which corresponds to a different type of event. Chapter 7 covers event processing in depth.

There are many situations when a paint event is generated and paintEvent() يسمى. فمثلا:

  • When a widget is shown for the first time, the system automatically generates a paint event to force the widget to paint itself.
  • When a widget is resized, the system generates a paint event.
  • If the widget is obscured by another window and then revealed again, a paint event is generated for the area that was hidden (unless the window system stored the area).

We can also force a paint event by calling QWidget::update() أو QWidget::repaint(). The difference between these two functions is that repaint() forces an immediate repaint, whereas update() simply schedules a paint event for when Qt next processes events. (Both functions do nothing if the widget isn't visible on-screen.) If update() is called multiple times, Qt compresses the consecutive paint events into a single paint event to avoid flicker. في IconEditor, we always use update().

We start by constructing a QPainter object on the widget. If the zoom factor is 3 or more, we draw the horizontal and vertical lines that form the grid using the QPainter::drawLine() وظيفة.

A call to QPainter::drawLine() has the following syntax:

أين ( x1, y1) is the position of one end of the line and ( x2, y2) is the position of the other end. There is also an overloaded version of the function that takes two QPoints instead of four intس.

The top-left pixel of a Qt widget is located at position (0, 0), and the bottom-right pixel is located at (width() - 1, height() - 1). This is similar to the conventional Cartesian coordinate system, but upside down, as Figure 5.3 illustrates. We can change QPainter's coordinate system by using transformations, such as translation, scaling, rotation, and shearing. We cover these in Chapter 8.

Before we call drawLine() على ال QPainter, we set the line's color using setPen(). We could hard-code a color, such as black or gray, but a better approach is to use the widget's palette.

Every widget is equipped with a palette that specifies which colors should be used for what. For example, there is a palette entry for the background color of widgets (usually light gray) and one for the color of text on that background (usually black). By default, a widget's palette adopts the window system's color scheme. By using colors from the palette, we ensure that IconEditor respects the user's preferences.

A widget's palette consists of three color groups: active, inactive, and disabled. Which color group should be used depends on the widget's current state:

  • ال نشيط group is used for widgets in the currently active window.
  • ال غير نشط group is used for widgets in the other windows.
  • ال Disabled group is used for disabled widgets in any window.

ال QWidget::palette() function returns the widget's palette as a QPalette مفعول. Color groups are specified as enums of type QPalette::ColorGroup.

When we want to get an appropriate brush or color for drawing, the correct approach is to use the current palette, obtained from QWidget::palette(), and the required role, for example, QPalette::foreground(). Each role function returns a brush, which is normally what we want, but if we just need the color we can extract it from the brush, as we did in the paintEvent(). By default, the brushes returned are those appropriate to the widget's state, so we do not need to specify a color group.

ال paintEvent() function finishes by drawing the image itself. The call to IconEditor::pixelRect() returns a QRect that defines the region to repaint. (Figure 5.4 illustrates how a rectangle is drawn.) As an easy optimization, we don't redraw pixels that fall outside this region.

Figure 5.4 Drawing a rectangle using

We call QPainter::fillRect() to draw a zoomed pixel. QPainter::fillRect() يأخذ QRect و أ QBrush. By passing a QColor as the brush, we obtain a solid fill pattern. If the color isn't completely opaque (its alpha channel is less than 255), we draw a white background first.

ال pixelRect() function returns a QRect suitable for QPainter::fillRect(). ال أنا و ي parameters are pixel coordinates in the QImage—not in the widget. If the zoom factor is 1, the two coordinate systems coincide exactly.

ال QRect constructor has the syntax QRect( x, ذ, العرض, ارتفاع), where ( x, ذ) is the position of the top-left corner of the rectangle and العرض x ارتفاع is the size of the rectangle. If the zoom factor is 3 or more, we reduce the size of the rectangle by one pixel horizontally and vertically so that the fill does not draw over the grid lines.

When the user presses a mouse button, the system generates a "mouse press" event. By reimplementing QWidget::mousePressEvent(), we can respond to this event and set or clear the image pixel under the mouse cursor.

If the user pressed the left mouse button, we call the private function setImagePixel() مع حقيقية as the second argument, telling it to set the pixel to the current pen color. If the user pressed the right mouse button, we also call setImagePixel(), but pass خاطئة to clear the pixel.

ال mouseMoveEvent() handles "mouse move" events. By default, these events are generated only when the user is holding down a button. It is possible to change this behavior by calling QWidget::setMouseTracking(), but we don't need to do so for this example.

Just as pressing the left or right mouse button sets or clears a pixel, keeping it pressed and hovering over a pixel is also enough to set or clear a pixel. Since it's possible to hold more than one button pressed down at a time, the value returned by QMouseEvent::buttons() is a bitwise OR of the mouse buttons. We test whether a certain button is pressed down using the & operator, and if this is the case we call setImagePixel().

ال setImagePixel() function is called from mousePressEvent() و mouseMoveEvent() to set or clear a pixel. ال pos parameter is the position of the mouse on the widget.

The first step is to convert the mouse position from widget coordinates to image coordinates. This is done by dividing the x() و y() components of the mouse position by the zoom factor. Next, we check whether the point is within the correct range. The check is easily made using QImage::rect() و QRect::contains() this effectively checks that أنا is between 0 and image.width() - 1 and that ي is between 0 and image.height() - 1.

يعتمد على opaque parameter, we set or clear the pixel in the image. Clearing a pixel is really setting it to be transparent. We must convert the pen QColor to a 32-bit ARGB value for the QImage::setPixel() مكالمة. At the end, we call update() مع QRect of the area that needs to be repainted.

Now that we have reviewed the member functions, we will return to the Qt::WA_StaticContents attribute that we used in the constructor. This attribute tells Qt that the widget's content doesn't change when the widget is resized and that the content stays rooted to the widget's top-left corner. Qt uses this information to avoid needlessly repainting areas that are already shown when resizing the widget. This is illustrated by Figure 5.5.

Normally, when a widget is resized, Qt generates a paint event for the widget's entire visible area. But if the widget is created with the Qt::WA_StaticContents attribute, the paint event's region is restricted to the pixels that were not previously shown. This implies that if the widget is resized to a smaller size, no paint event is generated at all.

ال IconEditor widget is now complete. Using the information and examples from earlier chapters, we could write code that uses the IconEditor as a window in its own right, as a central widget in a QMainWindow, as a child widget inside a layout, or as a child widget inside a QScrollArea. In the next section, we will see how to integrate it with Qt Designer.


Platform Plugins for Windowing Systems on Embedded Linux Devices

This is the X11 plugin used on regular desktop Linux platforms. In some embedded environments, that provide X and the necessary development files for xcb, this plugin functions just like it does on a regular PC desktop.

ملحوظة: On some devices there is no EGL and OpenGL support available under X because the EGL implementation is not compatible with Xlib. In this case the XCB plugin is built without EGL support, meaning that Qt Quick 2 or other OpenGL-based applications does not work with this platform plugin. It can still be used however to run software-rendered applications (based on QWidget for example).

As a general rule, the usage of XCB on embedded devices is not advisable. Plugins like eglfs are likely to provide better performance, and hardware acceleration.

وايلاند

Wayland is a light-weight windowing system or more precisely, it is a protocol for clients to talk to a display server.

The Qt Wayland module provides a wayland platform plugin that allows Qt application to connect to a Wayland compositor.

ملحوظة: You may experience issues with touch screen input while using the Weston reference compositor. Refer to the Qt Wiki for further information.