أدوات المستخدم

أدوات الموقع


docs:wxpython

اختلافات

عرض الاختلافات بين النسخة المختارة و النسخة الحالية من الصفحة.

رابط إلى هذه المقارنة

جانبي المراجعة السابقة المراجعة السابقة
المراجعة التالية
المراجعة السابقة
docs:wxpython [2009/12/06 06:05]
ayoussef
docs:wxpython [2015/04/23 00:20] (حالي)
سطر 1: سطر 1:
 +{{tag>​مقالات مترجمة برمجة بايثون wx wxPython}}
 +~~ODT~~
 +
 +====== تعليم البرمجة الرسومية في wxPython ​ ======
 +  * مقالة من تأليف Jan Bodnar
 +  * المصدر http://​zetcode.com/​wxpython/​
 +  * ترجمة : حالياً //​**بدري دركوش (Free_Programmer)**//​
 +  * قيد الإنشاء
 +
 +هذا مدخل إلى wxPython وهو يعد من أكبر الشروحات المتوفرة على الإنترنت وأكثرها تقدما. وهو يناسب المبتدئين والمتوسطين.
 +
 +قد ترغب في إلقاء نظرة على المقالات
 +  * [[http://​zetcode.com/​tutorials/​pythontutorial|تعلم بايثون]]
 +  * [[pyqt4]]
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== مقدمة في wxPython =====
 +
 +
 +
 +==== التطبيق ====
 +**التطبيق** هو برنامج للكمبيوتر يقوم بمهمة معينة أو مجموعة من المهام . كمثال على التطبيق هو متصفح الويب و مشغل الوسائط و معالج النصوص . إن مصطلح **أداة** أو **البرمجية خدمية** يستخدم مع التطبيق الصغير أو البسيط و الذي يقوم بمهمة واحدة . ان برنامج cp في بيئة يونكس هو مثال على مثل هذه الأداة.
 +كل هذه الأشياء تشكل ما يسمى **برمجيات الحاسوب** . أن مصطلح برمجيات الكمبيوتر هو الاسم الشائع لوصف نظام التشغيل و البيانات و برامج الكمبيوتر و التطبيقات و ملفات mp3 و ألعاب الكمبيوتر.
 +إن التطبيقات ممكن أن تنشئ لأربع مجالات مختلفة.
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​areas.jpg |Application areas}}
 +
 +
 +
 +
 +
 +
 +
 +أن برنامج تسوق على الإنترنت و الويكي و المدونات هي مثال على تطبيقات ويب شائعة . حيث يتم الوصول إليها عن طريق متصفح الويب.
 +الأمثلة عن تطبيقات سطح المكتب تتضمن مثلاً Maya و Opera و المكتب المفتوح و Winamp. ​
 +إن حوسبة المشاريع هي مجال محدد . حيث تكون التطبيقات في هذا المجال معقدة و كبيرة . أما التطبيقات التي كتبت للأجهزة المحمولة تتضمن كل البرامج التي طُورت من أجل أجهزة الجوال و أجهزة الاتصالات و أجهزة (PDA) و ما يشبهه.
 +
 +
 +
 +
 +**لغات البرمجة**
 +
 +
 +
 +
 +هنالك حالياً العديد من لغات البرمجة المنتشرة , إن القائمة التالية تعتمد على [[http://​www.tiobe.com/​tpci.htm|TIOBE]] جدول مجتمع المبرمجين . هذه الأرقام تعود إلى شهر مايو 2007 .
 +
 +
 +
 +^  ترتيب اللغات في 2008 TIOBE  ^^^
 +^  المرتبة ​ ^  اللغة ​ ^  التقييم ​ ^
 +|  1  |  Java  |  21.571% |
 +|  2   ​| ​ C  |  16.178% ​ |
 +|  3   ​| ​ (Visual) Basic  |  10.857% ​ |
 +|  4   ​| ​ C++  |  10.057% ​ |
 +|  5   ​| ​ PHP  |  9.349% ​ |
 +|  6   ​| ​ Python ​ |  4.975% ​ |
 +|  7   ​| ​ Perl  |  4.694% ​ |
 +|  8   ​| ​ C#  |  3.697% ​ |
 +|  9   ​| ​ Ruby  |  2.920% ​ |
 +|  10   ​| ​ JavaScript ​ |  2.892% ​ |
 +
 +
 +إن لغة البرمجة جافا هي لغة البرمجة الأكثر أستخداماً , ما يميز لغة البرمجة جافا ​ انه بإمكانك كتابة تطبيقات للأجهزة المحمولة و برمجة العديد من التجهيزات و إنشاء تطبيقات المشاريع. ما يأتي في رابعاً هو كل تطبيق بُرمج باستخدام C/C++ , فهي تعتبر الاختيار الافتراضي لإنشاء أنظمة التشغيل و العديد من تطبيقات سطح المكتب , ان لغتي C/C++ هي أكثر لغات البرمجة استخداماً على مستوى النظام . أغلب تطبيقات سطح المكتب تم إنشائها باستخدام لغة سي بلس بلس . قد تكون مايكروسوفت أوفيس أو مايكروميديا فلاش أو أدوبي فوتوشوب أو ثري دي ماكس.
 +بالإضافة إلى ذلك تسيطر هاتين اللغتين على مجال برمجة الألعاب .
 +
 +
 +
 +
 +
 +
 +على مستوى آخر , تسيطر لفة PHP على الويب , بينما تستخدم الجافا في المؤسسات الكبيرة فإن لغة PHP تستخد في الشركات الصغيرة و الأشخاص , تستخدم PHP لإنشاء تطبيقات ويب ديناميكية , فيجوال بيسك تستخدم بشكل أساسي في كـ **RAD** و التي تعني تطوير السريع للتطبيقات .
 +
 +
 +
 +
 +
 +
 +الآن , إن كلاً من بيرل و بايثون و روبي عي لغات سكربت , و لديها العديد من السمات المشتركة , فهي متنافسون متقاربون.
 +
 +
 +
 +
 +
 +أما وقت لغو السي شارب لم يأتي بعد فقد كان من المخطط أن تكون لغة الضخمة التالية , أما الجافا السكريبت فهي لغة برمجة من جهة العميل و التي تعمل من خلال المنصفح , و تعتبر لغة واقعية ومسيطرة و ليس لديها أي منافس في مجالها.
 +
 +
 +
 +
 +==== بايثون ====
 +إن لغة البرمجة بايثون لغة كتابة سكربتات ناجحة , تم تطويرها بداياً من قبل **Guido van Rossum** , تم اصدارها أول مرة سنة 1991 , لقد استوحيت البايثون من لغة البرمجة ABC و لغة هاسكل . و تعتبر لغة بايثون لغة عالية المستوى و عامة الاستخدام و متعددو المنصات و هي لغة مفسَرة . يفضل البعض أن يسميها لغة ديناميكية . و هي سهلة التعلم . بايثون تعتبر لغة بسيطة , أحدى مزاياها الأكثر وضوحا هي عدم استخدام الفاصلة المنقوطة أو الأقواس . تستخدم البايثون الفراغات في أول السطر (التثليم) عوضاً عن ذلك,​أحدث نسخة من البايثون 2.5 و التي أطلقت في سبتمبر 2006 , اليوم لغة البايثون تطور من قبل مجموعة كبيرة من المتطوعين من جميع أنحاء العالم .
 +
 +من أجل أنشاء واجهة رسومية للمستخدم يستطيع المبرمجون بلغة بايثون الاخنيار بيت ثلاثة خيارات جيدة . هي PyGTK و wxPython و PyQt . أما الأداة الأساسيو مع أدوات بايثون فهي TkInter. لكنها بطيئة و سيئة المظهر على كل المنصات و لم يتم تحديثها منذ عصور . و هي تعتمد أيضاً على Tcl (أي أن لغة tcl يجب أن تكون مضمنة) , و هو أمر غريب , جميع الأدوات سابقة الذكر أفضل منها , و لا يزال سراً لماذا لم تلغى منذ سنوات سابقة .
 +
 +==== wxPython ====
 +تعرف الـ wxPython على انها مجموعة أدواة تطوير البرامج تعمل على أكثر من منصة من أجل تطبيقات ذات واجهة رسومية , باستخدام wxPython يستطيع المطورون إنشاء تطبيقات لويندوز و ماك و العديد من أنظمة يونكس .
 +نعنبر wxPython كغلاف لما يسمى wxWidgets و هي مكتبة سي بلس بلس متعددة المنصات متطورة . تتكون wxPython من خمس وحدات أساسية .
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​modules.jpg |wxPython modules}}
 +
 +
 +
 +
 +
 +
 +
 +وحدة **المتحكمات** (Controls) و التي توفر الودجات (widgets) الشائعة الإستخدام في واجهات البرامج . مثل الأزرار (Button) أو شريط الأدوات (Toolbar) أو نوتبوك (Notebook) . إن الودجات تسمى متحكمات في نظام ويندوز.
 +أما وحدة **النواة** (Core) فتتكون من الأصناف الأولية التي تستخدم في التطوير . هذه الأصناف تتضمن صتف الأغراض (Object class) و الذي يعتبر الأب لكل الأصناف , سايزر (Sizers) و التي تستخدم من أجل تنسيق الودجات و الأحداث و الأصناف الهندسية الأساسية مثل النقطة و المستطيل. أما واجهة الأداة التصويرية (Graphics Device Interface) أو (**GDI**) فهي مجموعة من الأصناف تستخدم للرسم ضمن الودجات . هذه الوحدة تحوي أصنافاً من أجل التعديل على الخطوط أو الألوان أو الفراشي أو الصور . أما وحدة **المتفرقات** (Misc) فهي تحوي مختلف الأصناف الأُخرى و و توابع الوحدات . هذه الأصناف تستخدم من أجل التسجيل (logging) أو إعداد التطبيق أو إعدادات النظام أو العمل مع الشاشة أة أداة تحكم الألعاب . الآن وحدة **نوافذ** (Windows) تتضمن العديد من النوافذ و التي تكون التطبيق . مثل صندوق الحوار و النافذة المتحركة و الإطار ..الخ .
 +
 +
 +
 +
 +==== واجهة برمجة التطبيقات لـ wxPython API) wxPython) ====
 +
 +
 +
 +إن API الخاص بـ wxPython هي مجموعة من الوظائف (functions) و الودجات (widgets) . الودجات هي كتل البناء الأساسية للواجهة التطبيق .في بيئة ويندوز الودجات تسمى متحكمات , نستطيع تقريباً أن نقسم الميرمجين إلى مجموعتين اثنين .فهم يبرمجون التطبيقات أو المكتبات (libraries) , تقنياً تعتبر wxPython كغطاء أو غلاف حول API واجهة المستخدم الرسومية المكتوبة بلغة سي بلس بلس (C++ GUI API)  و التي تسمى wxWidgets . لذلك فهي ليست API محلية . أي أنها ليست مكتوبة بشكل مباشر بلغة البايثون , أن مكتبة الواجهة الرسومية المحلية الوحيدة المكتوبة من أجل لغة مفسرة و أعلمه أنا هي مكتبة Swing للغة الجافا .
 +
 +
 +
 +
 +
 +في wxPython لدينا العديد من الودجات (وادجيت) , و لكن يمكننا أن نصنفها إلى مجموعات منطقية :
 +
 +
 +
 +** الودجات الأساسية **
 +
 +
 +توفر هذه الودجات العملانية للودجات المشتقة . و تسمى (ancestors) الأسلاف و هي لا تستخدم عادةً بشكل مباشر.
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​base.jpg |base widgets}}
 +
 +
 +
 +
 +
 +** ودجات المستوى الأعلى **
 +
 +
 +
 +هذه الودجات تتواجد بشكل مستقل عن بعضها الآخر .
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​toplevel.jpg |toplevel widgets}}
 +
 +
 +
 +
 +
 +** الحاويات Containers **
 +
 +
 +
 +أما الحاويات فوظيفتها أن تحوي أو تستوعب الودجات الأُخرى .
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​containers.jpg |containters}}
 +
 +
 +
 +
 +
 +** الودجات الديناميكية **
 +
 +
 +
 +
 +هذه الودجات يمكن التعديل عليها من قبل المستخدمين النهائيين .
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​dynamic.jpg |dynamic widgets}}
 +
 +
 +
 +
 +
 +
 +** الودجات الثابتة **
 +
 +
 +
 +هذه الودجات تظهر المعلومات و لا يمكن التعديل عليها من قبل المستخدم.
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​staticwidgets.jpg |static widgets}}
 +
 +
 +
 +
 +
 +** الودجات الأُخرى ** 
 +
 +
 +هذه الودجات تمثل شريط الحالة (statusbar) و شريط الأدوات (toolbar و شريط الأدوات (menubar) في التطبيق .
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​bars.jpg |other widgets}}
 +
 +
 +
 +
 +
 +
 +
 +** الوراثة Inheritance **
 +
 +
 +
 +هنالك علاقة معينة بين الودجات في wxPython , هذه العلاقة تتطور و تتوسع عن طريق الوراثة , إن الوراثة جزء هام جداً من البرمجة غرضية التوجه , إن الودجات تشكل هرمية و يمكن للودجات أن ترث عملانية أو وظائف من ودجات أُخرى . تسمى الأصناف القائمة بالأصناف الأساسية أو الأصناف الأباء أو الأسلاف . أما الودجات التي ترث فتسمى الودجات المشتقة أو الودجات الأبناء أو الأحفاد .إن المصطلحات مستعارة من علم الأحياء.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​inheritance.png |inheritance diagram}}
 +
 +
 +
 +
 +
 +
 +
 +
 +لنقل مثلاً أننا استخدمنا ودجة الزر (button) في تطبيقنا , أن الزر يرث من ثلاث أصناف أساسية .
 +أقرب الأصناف هو صنف //​wx.Control//​ . إن ودجة الزر نوع من النافذة الصغيرة , كل الودجات التي تظهر على الشاشة هي نوافذ , لذلك فهي ترث من صنف //​wx.Window//​ . هتالك كائنات (opjects) خفية لا تظهر بشكل مباشر , مثل sizers ​ و device context و local opject . هنالك أيضاً أيضاً أصتاف ظاهرة و لكنها ليست نوافذ مثل كائن اللون ​ و كائن caret (مؤشر الكتابة) و كائن المؤشرة (cursor).
 +ليس كل الودجات متحكمات , على سبيل المثال //​wx.Dialog//​ ليست نوع من المتحكات , المتحكمات هي الودجات التي تتوضع فوق ودجات أُخرى تسمى ** الحاويات** . لذلك لدينا صنف أساسي منفصل هو //​wx.Control//​.
 +
 +
 +
 +
 +
 +
 +
 +كل النوافذ تستطيع أن نستجيب للأحداث , و كذلك تقوم ودجة الزر , عن طريق الضغط على الزر نقوم بتشغيل حدث //​wx.EVT_COMMAND_BUTTON_CLICKED//​ . أن ودجة الزر ترث //​wx.EvtHandler//​ عبر صنف //​wx.Window//​. كل ودجة تستجيب للأحداث يجب أن ترث من صنف //​wx.EvtHandler//​ و في النهاية كل الكائنات و الأغراض ترث من صنف //​wx.Object//​ و هو الأب لكل الأغراض في wxPython .
 +
 +
 +==== إعداد wxPython ====
 +
 +
 +
 +في هذا القسم سوف نريك كيف يتم تنصيب و إعداد مكتبة wxPython , إن العملية سهلة جداً مقدمة لك حسب نظام التشغيل المناسب.
 +
 +
 +
 +
 +=== تنصيب wxPython على نظام windows XP ===
 +
 +
 +
 +نستطيع تحميل الملفات التفيذية من موقع wxPython الرسمي على الانترنت [[http://​www.wxpython.org|site]] . يجب علك أن تختار النسخة الصحيحة حسب نسخة البايثون الموجودة لدينا .
 +
 +هنالك خيارين أساسين هما :
 +
 +  * win32-unicode
 +  * win32-ansi
 +
 +عادة ما تكون نسخة اليونيكود هي الخير الأفضل حيث تدعم هذه النسخة اللغات غير الإنكليزية .
 +يقوم برنامج التنصيب يإيجاد مفسر البايثون أتوماتيكياً , كل ما علينا فعله هو التأكد من أننا نوافق على الترخيص , هذا كل شيء !
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​xpsetup.jpg |xp setup}}
 +
 +
 +
 +
 +
 +
 +هنالك أيضاً حزمة منفردة , و تسمى //​win32-docs-demos//​ و التي تحوي عينات الأمثلة الشهيرة و التوثيق و الأمثلة .
 +هذا موجه نحو المطورين .
 +ملاحظة مفيدة بخصوص مفسر البايثون في ويندوز , إذا ضغطنا على ملف سكربت بايثون فستظهر نافذة سطر أوامر , هذا هو التصرف الإفتراضي و لكن يمكننا أن نغير ذلك عن طريق إسناد برامج البايثون إلى ملف //​python.exe//​ .اضغط بزر المؤشرة اليمين على أيقونة البايثون , اختر خصائص (properties) اختر زر (change) , ثم اختر //​pythonw.exe//​ و هو موجود في مسار تنصيب بايثون , على جهازي مثلاً هو C:\Program Files\Python25\pythonw.exe .
 +
 +
 +
 +=== تنصيب wxPython على أبونتو لينوكس ===
 +
 +
 +
 +
 +إن عملية التنصيب هنا حتى أسهل منها على ويندوز XP , أن أبونتو توزيعة لينوكس رائعة ,إن تنصيب wxPython سهل جدأ نقوم بالتنصيب باستخدام مدير الحزم ساينأبتك (Synaptic) , تجدها في القائمة System - Administration.
 +نخنار حزمة wxPython و هي تسمى //​python-wxgtkx.x//​. يقوم مدير الحزم اتوماتيكياً بإختيار ​ المتطلبات , نحدد الحزمة للتنصيب و نضغط على تطبيق أو Apply , سيقوم بتحميل مكتبة wxPython و تنصيبها على نظامك , الحزم في أبونتو حديثة تماماً , هنالك توزيعات لينوكس أُخرى قد تحوي حزماً أقدم , إن wxPython أداة تتطور بشدة , حتى نحصل على أحدث التحديثات قد نضطر إلى بناء wxPython من المصدر.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== الخطوات الأُولى =====
 +
 +
 +
 +
 +==== مثال بسيط ====
 +
 +
 +
 +سنبدأ مع مثال بسيط جداً , إن سكربتنا الأول سوف يظهر نافذة صغيرة , لن تقوم بالمزيد.
 +سنقوم بتحليل السكربن سطراً سطراً . و ها هو الكود :
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# simple.py
 +
 +import wx
 +
 +app = wx.App()
 +
 +frame = wx.Frame(None,​ -1, '​simple.py'​)
 +frame.Show()
 +
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# simple.py
 +</​code>​
 +
 +
 +
 +
 +
 +السطر الأول يستورد الوحدات wxPython الأساسية هو إشارة # يليه المسار إلى مفسر البايثون . السطر الثاني تعليق , و هو يحوي اسم السكربت .
 +
 +
 +
 +
 +<code python>
 +import wx
 +</​code>​
 +
 +
 +
 +
 +هذا السطر يقوم بإستيراد وحدات wxPython الأساسية , أي الوحدات core و controls و gdi و misc و windows .
 +تقنياً تعتبر wx كفضاء تسمية , لذلك كل الوظائف و الكائنات من الوحدات الأساسية ستبدأ بالبادئة .wx .
 +السطر الثاني من الشفرة (ال.كود) سيقوم بإنشاء كائن التطبيق .
 +
 +
 +
 +
 +<code python>
 +app = wx.App()
 +</​code>​
 +
 +
 +
 +كل برنامج wxPython يجب أن يحوي كائن التطبيق واحد على الأقل.
 +
 +
 +
 +
 +<code python>
 +frame = wx.Frame(None,​ -1, '​simple.py'​)
 +frame.Show()
 +</​code>​
 +
 +
 +
 +
 +هنا قمنا بإنشاء كائن wx.Frame , إن ودجة wx.Frame تعتبر ودجة حاوية مهمة لذلك سنقوم بالتحدث عن هذه الودجة بالتفصيل بعد قليل.
 +إن ودجة wx.Frame هي الودجة الأب للودجات الأُخرى , و ليس لها أب , إذا لم نحدد أي متغير للأب فنحن نقول أنه ليس لهذه الودجة أب , فهي تعتبر ودجة عليع في هرمية الودجات .
 +بعد أن ننشئ ودجة wx.Frame ​ يجب أن نستدعي الوظيفة Show() حتى نظهرا على الشاشة .
 +
 +
 +
 +
 +<code python>
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +يقوم السطر الأخير بإدخالنا إلى الحلقة الأساسية (mainloop) , الحلقة الأساسية هي دورة لا نهائية , تقوم بإلتقاط و إرسال كل حدث يتواجد أثناء تشغيل تطبيقنا.
 +
 +
 +
 +
 +
 +
 +
 +
 +ذلك كان مثال بسيط جداً , بالرغم من هذه البساطة نستطيع القيام يالكثير بهذه النافذة , نستطيع تعديل أبعاد النافذة و ملئ النافذة و تصغير النافذة , هذه العملية العملانية (الوظيفة) تتطلب الكثير من الكود , لكن ذلك كله متوفر و مخبئ عن طريق أدوات wxPython , لا حاجة لإختراع العجلة من جديد .
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​simple.jpg |simple}}
 +
 +
 +
 +==== ودجة wx.Frame ====
 +
 +نعتبر ودجة wx.Frame من هم الودجات في wxPython , فهي ودجة حاوية , وهذا يعني أنها تحوي ودجات أُخرى . في الحقيقة هي تستطيع أن تحوي أي نافذة ليست frame أو صندوق حوار (dialog ) . تتكون wx.Frame من  شريط العنوان و الحدود و المنطقة الحاوية المركزية . إن شريط العنوان و الحدود تعتبر اختيارية و يمكن ازالتها عن طريق الخيارات المتعددة.
 +
 +
 +
 +
 +
 +
 +
 +إن لودجة wx.Frame البنية التالية , كما نرى إن لها سبعة متغيرات , لا يوجد للمتغير الأول قيمة افتراضية بينما يوجد للستة الآخرين قيمة افتراضية,​ المتغريات الثلاث الأولى إلزامية بينما الأربعة الأخرى اختيارية.
 +
 +
 +
 +
 +
 +<code python>
 +  wx.Frame(wx.Window parent, int id=-1, string title='',​ wx.Point pos = wx.DefaultPosition, ​
 +  wx.Size size = wx.DefaultSize,​ style = wx.DEFAULT_FRAME_STYLE,​ string name = "​frame"​)
 +</​code>​
 +
 +
 +
 +
 +wx.DEFAULT_FRAME_STYLE is a set of default flags. ​
 +wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN.
 +عن طريق الجمع بين الأشكال المختلفة نستطيع الحصول أن نغير في شكل ودجة wx.Frame , في يلي مثال بسيط :
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# nominimizebox.py
 +
 +import wx
 +
 +app = wx.App()
 +window = wx.Frame(None,​ style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER ​
 + | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
 +window.Show(True)
 +
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +
 +في هذه المثال نريد أن نظهر النافذة بدون زر تكبير النافذة لذلك لم نقم بتحديد هذا المتغير ضمن متغيرات الشكل.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​nominimizebox.png |A window without a minimize box}}
 +
 +
 +==== المساحة والموضع ====
 +
 +نستطيع ان نقوم بتحديد مساحة التطبيق بطريقتين
 +1- تحديد معامل المساحة فى المشيّد
 +2- استدعاء الطريقة SetSize
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# size.py
 +
 +import wx
 +
 +class Size(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 200))
 +
 +        self.Show(True)
 +
 +
 +app = wx.App()
 +Size(None, -1, '​Size'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + ​wx.Frame.__init__(self,​ parent, id, title, size=(250, 200))
 +</​code>​
 +
 +
 +فى المشيد نحدد العرض الى 250بكسل والطول الى 200 بكسل
 +
 +بطريقة مشابهة نستطيع ان نموضع التطبيق على الشاشة، افتراضيا توضع النافذة بأعلى يسار الشاشة ولكن يمكن ان يختلف هذا تبع للمنصة او مدير النوافذ.
 +يستطيع المبرمج التحكم فى الموضوع برمجيا.. لقد رأينا المعامل pos سابقا فى المشيّد للودجت wx.Frameوعبر تقدييم قيم اخرى غير الأفتراضية نستطيع التحكم فى الموضع بأنفسنا.
 +
 +
 +
 +
 +
 +
 +
 +^  Method ​ ^  Description ​ ^
 +| ‪ Move(wx.Point point) ‬ | تنقل النافذة لموضع معين (بإستخدام كائن النقطة wx.Point) |
 +| ‪ MoveXY(int x, int y) ‬ | تنقل النافذة الى موضع (س، ص) |
 +| ‪ SetPosition(wx.Point point) ‬ | تحدد موضع النافذة |
 +| ‪ SetDimensions(wx.Point point, wx.Size size) ‬ | تحديد ابعاد النافذة. |
 +
 +يوجد العديد من الطرق لفعل هذا "​القى قطعة نقود للإختيار:​d"​
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# move.py
 +
 +import wx
 +
 +class Move(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        self.Move((800,​ 250))
 +        self.Show(True)
 +
 +
 +app = wx.App()
 +Move(None, -1, '​Move'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +
 +
 +There is one particular situation. We might want to display our window maximized. In this case, the window is positioned at (0, 0) and takes the whole screen. wxPython internally calculates the screen coordinates. To maximize our wx.Frame, we call the //​Maximize()//​ method.
 +If we want to center our application on the screen, wxPython has a handy method. The //​Centre()//​ method simply centers the window on the screen. No need to calculate the width and the height of the screen. Simply call the method. ​
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# centre.py
 +
 +import wx
 +
 +class Centre(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +Centre(None,​ -1, '​Centre'​)
 +app.MainLoop()
 +</​code>​
 +
 +==== ودجات تتواصل ====
 +
 +
 +مهم ان نعرف كيف يمكن ان تتواصل الودجات سويا.. تابع المثال التالى
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# communicate.py
 +
 +import wx
 +
 +
 +class LeftPanel(wx.Panel):​
 +    def __init__(self,​ parent, id):
 +        wx.Panel.__init__(self,​ parent, id, style=wx.BORDER_SUNKEN)
 +
 +        self.text = parent.GetParent().rightPanel.text
 +
 +        button1 = wx.Button(self,​ -1, '​+',​ (10, 10))
 +        button2 = wx.Button(self,​ -1, '​-',​ (10, 60))
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnPlus,​ id=button1.GetId())
 +        self.Bind(wx.EVT_BUTTON,​ self.OnMinus,​ id=button2.GetId())
 +
 +    def OnPlus(self,​ event):
 +        value = int(self.text.GetLabel())
 +        value = value + 1
 +        self.text.SetLabel(str(value))
 +
 +    def OnMinus(self,​ event):
 +        value = int(self.text.GetLabel())
 +        value = value - 1
 +        self.text.SetLabel(str(value))
 +
 +
 +class RightPanel(wx.Panel):​
 +    def __init__(self,​ parent, id):
 +        wx.Panel.__init__(self,​ parent, id, style=wx.BORDER_SUNKEN)
 +        self.text = wx.StaticText(self,​ -1, '​0',​ (40, 60))
 +
 +
 +class Communicate(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(280, 200))
 +
 +        panel = wx.Panel(self,​ -1)
 +        self.rightPanel = RightPanel(panel,​ -1)
 +
 +        leftPanel = LeftPanel(panel,​ -1)
 +
 +        hbox = wx.BoxSizer()
 +        hbox.Add(leftPanel,​ 1, wx.EXPAND | wx.ALL, 5)
 +        hbox.Add(self.rightPanel,​ 1, wx.EXPAND | wx.ALL, 5)
 +
 +        panel.SetSizer(hbox) ​
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +Communicate(None,​ -1, '​widgets communicate'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +فى المثال لدينا 2 panels واحدة على اليسار (تحوى زرين) والأخرى على اليمين (تحوى نص ساكن static text) . والزرين سيغيران الرقم الظاهر على النص الساكن.. السؤال الآن هو كيف نحصل على مرجع "​reference"​ للنص الساكن ؟
 +
 +اذا كانت كل الويدجات فى نفس الصف.. فهذا تافة ولكن اذا كانو فى صفوف مختلفة.. فنحصل على المراجع عن طريق الهيكلية.
 +
 +<code python>
 + panel = wx.Panel(self,​ -1)
 + ​self.rightPanel = RightPanel(panel,​ -1)
 +
 + ​leftPanel = LeftPanel(panel,​ -1)
 +</​code>​
 +
 +
 +لاحظ ان ال panel اليمنى **يجب** ان تعرف قبل اليسرى.. لأننا عند انشاء اليسرى نبحث عن تعريف النص الساكن اللذى تم تعريفه فى اليمنى.
 +فمنطقيا لا نستطيع الحصول على مرجع لودجت غير موجود بعد!
 +
 +
 +<code python>
 + ​self.text = parent.GetParent().rightPanel.text
 +</​code>​
 +
 +
 +الإجابة هنا.. كل ويدجت لديه معامل للأب وفى مثالنا الأب هو panel نضع عليها ال panel اليمنى واليسرى.. بإستدعاء الطريقة GetParent نحصل على مرجع لل frame اللتى تحوى مرجع للpanel اليمنى والتى تحوى مرجع للنص الساكن.
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​communicate.jpg |how widgets communicate}}
 +
 +
 +
 +==== القوائم و أشرطة الأدوات في wxPython ====
 +
 +==== Creating a MenuBar ====
 +
 +
 +
 +
 +A menubar is one of the most visible parts of the GUI application. It is a group of commands located in various menus. ​
 + While in console applications you had to remember all those arcane commands, here we have most of the commands grouped into logical parts. ​
 +There are accepted standards that further reduce the amount of time spending to learn a new application. ​
 +To implement a menubar in wxPython we need to have three things. A //​wx.MenuBar//,​ a //wx.Menu// and a //​wx.MenuItem//​.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​menu.jpg |Menu objects}}
 +
 +
 +
 +
 +
 +=== A Simple menu example ===
 +
 +
 +
 +Creating a menubar in wxPython is very simple. Just a few lines of code. 
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# simplemenu.py
 +
 +import wx
 +
 +class SimpleMenu(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 150))
 +
 +        menubar = wx.MenuBar()
 +        file = wx.Menu()
 +        file.Append(-1,​ '​Quit',​ 'Quit application'​)
 +        menubar.Append(file,​ '&​File'​)
 +        self.SetMenuBar(menubar)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +SimpleMenu(None,​ -1, '​simple menu example'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +<code python>
 + ​menubar = wx.MenuBar()
 +</​code>​
 +
 +
 +
 +
 +First we create a menubar object. ​
 +
 +
 +
 +
 +<code python>
 + file = wx.Menu()
 +</​code>​
 +
 +
 +
 +
 +Next we create a menu object. ​
 +
 +
 +
 +
 +<code python>
 + ​file.Append(-1,​ '​Quit',​ 'Quit application'​)
 +</​code>​
 +
 +
 +
 +We append a menu item into the menu object. The first parameter is the id of the menu item. 
 +The second parameter is the name of the menu item. The last parameter defines the short helpstring that is displayed on the statusbar, when the menu item is selected. Here we did not create a //​wx.MenuItem//​ explicitely. ​
 +It was created by the //​Append()//​ method behind the scenes. Later on, we will create a //​wx.MenuItem//​ manually.
 +
 +
 +
 +
 +<code python>
 + ​menubar.Append(file,​ '&​File'​)
 + ​self.SetMenuBar(menubar)
 +</​code>​
 +
 +
 +
 +
 +After that, we append a menu into the menubar. ​
 +The &amp character creates an accelerator key. The character that follows the &amp is underlined. ​
 +This way the menu is accessible via the alt + F shortcut. In the end, we call the //​SetMenuBar()//​ method.
 +This method belongs to the wx.Frame widget. It sets up the menubar. ​
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​simplemenu.png |A simple menu example}}
 +
 +
 +=== A dockable menubar ===
 +
 +
 +
 +Under Linux, we can create a dockable menubar. This feature is not commonly seen in applications. But similar thing can be seen on Mac OS. Mac users do not have a menubar in the toplevet application window. The menubar is implemented outside the main window. ​
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# dockable.py
 +
 +import wx
 +
 +class Dockable(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        menubar = wx.MenuBar(wx.MB_DOCKABLE)
 +        file = wx.Menu()
 +        edit = wx.Menu()
 +        view = wx.Menu()
 +        insr = wx.Menu()
 +        form = wx.Menu()
 +        tool = wx.Menu()
 +        help = wx.Menu()
 +
 +        menubar.Append(file,​ '&​File'​)
 +        menubar.Append(edit,​ '&​Edit'​)
 +        menubar.Append(view,​ '&​View'​)
 +        menubar.Append(insr,​ '&​Insert'​)
 +        menubar.Append(form,​ '&​Format'​)
 +        menubar.Append(tool,​ '&​Tools'​)
 +        menubar.Append(help,​ '&​Help'​)
 +        self.SetMenuBar(menubar)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +Dockable(None,​ -1, '​Dockable menubar'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + ​menubar = wx.MenuBar(wx.MB_DOCKABLE)
 +</​code>​
 +
 +
 +
 +We create a dockable menubar by providing a wx.MB_DOCKABLE flag to the constructor.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​dockable.jpg |A dockable menubar}}
 +
 +
 +=== Icons, shortcuts, events ===
 +
 +
 +
 +In the next section we will further enhance our menu example. We will see, how we can add icons to our menus. Icons make our applications more visually attractive. Further, they help us understand the menu commands. ​
 +We will see, how we can add shortcuts to our menus. Shortcuts are not a relict from the past. They enable us to work more quickly with our applications. One of the most widely used shortcut is the Ctrl + S one. There are not many people, that would not know the meaning of this shortcut.
 +It is more handy to press this shortcut, than to move a mouse pointer to the menubar, click a File menu and select the Save commnand. Shortcuts are a productivity boost to most users.
 + 
 +We will also briely touch events. ​
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# menuexample.py
 +
 +import wx
 +
 +class MenuExample(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 150))
 +
 +        menubar = wx.MenuBar()
 +        file = wx.Menu()
 +        quit = wx.MenuItem(file,​ 1, '&​Quit\tCtrl+Q'​)
 +        quit.SetBitmap(wx.Bitmap('​icons/​exit.png'​))
 +        file.AppendItem(quit)
 +
 +        self.Bind(wx.EVT_MENU,​ self.OnQuit,​ id=1)
 +
 +        menubar.Append(file,​ '&​File'​)
 +        self.SetMenuBar(menubar)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnQuit(self,​ event):
 +        self.Close()
 +
 +app = wx.App()
 +MenuExample(None,​ -1, ''​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + quit = wx.MenuItem(file,​ 1, '&​Quit\tCtrl+Q'​)
 + ​quit.SetBitmap(wx.Bitmap('​icons/​exit.png'​))
 + ​file.AppendItem(quit)
 +</​code>​
 +
 +
 +
 +
 +If we want to add shortcuts and icons to our menus, we have to manually create a //​wx.MenuItem//​. So far we have created menuitems indirectly.
 +The &amp character specifies an accelerator key. The following character is underlined. The actual shortcut is defined by the combination of characters. We have specified Ctrl + Q characters. So if we press Ctrl + Q, we close the application. We put a tab character between the &amp character and the shortcut. This way, we manage to put some space between them. 
 +To provide an icon for a menuitem, we call a //​SetBitmap()//​ method.
 +A manually created menuitem is appended to the menu by calling the //​AppendItem()//​ method.
 +
 +
 +
 +
 +<code python>
 + ​self.Bind(wx.EVT_MENU,​ self.OnQuit,​ id=1)
 +</​code>​
 +
 +
 +
 +
 +If we select a quit menu item or press a keyboard shortcut, a //​wx.EVT_MENU//​ event is generated. ​ We bind an event handler to the event. ​
 +The event handler is a method, that is being called. In our example, the //​OnQuit()//​ method closes the application. There can be several menuitems, so we have to give a unique id to each of them.  Working with events is very easy and straightforward in wxPython. We will talk about events in a separate chapter. ​
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​menuexample.png |A menu example}}
 +
 +
 +=== Submenus ===
 +
 +
 +
 +
 +Each menu can also have a submenu. This way we can group similar commands into groups. For example we can place commands that hide/show various toolbars like personal bar, address bar, status bar or navigation bar into a submenu called toolbars. Within a menu, we can seperate commands with a separator. It is a simple line. It is common practice to separate commands like new, open, save from commands like print, print preview with a single separator. In our example we will see, how we can create submenus and menu separators. ​
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# submenu.py
 +
 +import wx
 +
 +ID_QUIT = 1
 +
 +class SubmenuExample(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(350, 250))
 +
 +        menubar = wx.MenuBar()
 +
 +        file = wx.Menu()
 +        file.Append(-1,​ '&​New'​)
 +        file.Append(-1,​ '&​Open'​)
 +        file.Append(-1,​ '&​Save'​)
 +        file.AppendSeparator()
 +
 +        imp = wx.Menu()
 +        imp.Append(-1,​ '​Import newsfeed list...'​)
 +        imp.Append(-1,​ '​Import bookmarks...'​)
 +        imp.Append(-1,​ '​Import mail...'​)
 +
 +        file.AppendMenu(-1,​ '​I&​mport',​ imp)
 +
 +        quit = wx.MenuItem(file,​ ID_QUIT, '&​Quit\tCtrl+W'​)
 +        quit.SetBitmap(wx.Bitmap('​icons/​exit.png'​))
 +        file.AppendItem(quit)
 +
 +        self.Bind(wx.EVT_MENU,​ self.OnQuit,​ id=ID_QUIT)
 +
 +        menubar.Append(file,​ '&​File'​)
 +        self.SetMenuBar(menubar)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnQuit(self,​ event):
 +        self.Close()
 +
 +app = wx.App()
 +SubmenuExample(None,​ -1, '​Submenu'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + ​file.AppendSeparator()
 +</​code>​
 +
 +
 +
 +
 + A menu separator is appended with the AppendSeparator() method.
 +
 +
 +
 +
 +<code python>
 + imp = wx.Menu()
 + ​imp.Append(-1,​ '​Import newsfeed list...'​)
 + ​imp.Append(-1,​ '​Import bookmarks...'​)
 + ​imp.Append(-1,​ '​Import mail...'​)
 +
 + ​file.AppendMenu(-1,​ '​I&​mport',​ imp)
 +</​code>​
 +
 +
 +
 +
 +Creating a submenu is trivial. First, we create a menu. Then we append menu items. A submenu is created by calling the //​AppenMenu()//​ on the menu object. ​
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​submenu.png |A submenu example}}
 +
 +
 +=== Various menu items ===
 +
 +
 +
 +There are tree kinds of menu items. ​
 +
 +  * normal item
 +  * check item
 +  * radio item
 +
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# checkmenuitem.py
 +
 +import wx
 +
 +ID_STAT = 1
 +ID_TOOL = 2
 +
 +class CheckMenuItem(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(350, 250))
 +
 +        menubar = wx.MenuBar()
 +        file = wx.Menu()
 +        view = wx.Menu()
 +        self.shst = view.Append(ID_STAT,​ 'Show statubar',​ 'Show Statusbar',​ kind=wx.ITEM_CHECK)
 +        self.shtl = view.Append(ID_TOOL,​ 'Show toolbar',​ 'Show Toolbar',​ kind=wx.ITEM_CHECK)
 +        view.Check(ID_STAT,​ True)
 +        view.Check(ID_TOOL,​ True)
 +
 +        self.Bind(wx.EVT_MENU,​ self.ToggleStatusBar,​ id=ID_STAT)
 +        self.Bind(wx.EVT_MENU,​ self.ToggleToolBar,​ id=ID_TOOL)
 +
 +        menubar.Append(file,​ '&​File'​)
 +        menubar.Append(view,​ '&​View'​)
 +        self.SetMenuBar(menubar)
 +
 +        self.toolbar = self.CreateToolBar()
 +        self.toolbar.AddLabelTool(3,​ '',​ wx.Bitmap('​icons/​quit.png'​))
 +        self.toolbar.Realize()
 +
 +        self.statusbar = self.CreateStatusBar()
 +        self.Centre()
 +        self.Show(True)
 +
 +    def ToggleStatusBar(self,​ event):
 +        if self.shst.IsChecked():​
 +            self.statusbar.Show()
 +        else:
 +            self.statusbar.Hide()
 +
 +    def ToggleToolBar(self,​ event):
 +        if self.shtl.IsChecked():​
 +            self.toolbar.Show()
 +        else:
 +            self.toolbar.Hide()
 +
 +app = wx.App()
 +CheckMenuItem(None,​ -1, 'check menu item')
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + ​self.shst = view.Append(ID_STAT,​ 'Show statubar',​ 'Show Statusbar',​ kind=wx.ITEM_CHECK)
 + ​self.shtl = view.Append(ID_TOOL,​ 'Show toolbar',​ 'Show Toolbar',​ kind=wx.ITEM_CHECK)
 +</​code>​
 +
 +
 +
 +
 +If we want to append a  check menu item, we set a //kind// parameter to //​wx.ITEM_CHECK//​. The default parameter is //​wx.ITEM_NORMAL//​.
 +The //​Append()//​ method returns a //​wx.MenuItem//​.
 +
 +
 +
 +
 +<code python>
 + ​view.Check(ID_STAT,​ True)
 + ​view.Check(ID_TOOL,​ True)
 +</​code>​
 +
 +
 +
 +
 +When the application starts, both statusbar and toolbar are visible. So we check both menu items with the //Check()// method.
 +
 +
 +
 +
 +<code python>
 + def ToggleStatusBar(self,​ event):
 +     if self.shst.IsChecked():​
 +         ​self.statusbar.Show()
 +     else:
 +         ​self.statusbar.Hide()
 +</​code>​
 +
 +
 +
 +
 +We show or hide the statusbar according to the state of the check menu item. We find out the state of the check menu item with the //​IsChecked()//​ method. ​ Same with toolbar. ​
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​checkmenuitem.png |Check menu item}}
 +
 +
 +=== Context menu ===
 +
 +
 +
 +
 +It is a list of commands that appears under some context. For example, in a Firefox web browser, when we right click on a web page, we get a context menu. Here we can reload a page, go back or view page source. If we right click on a toolbar, we get another context menu for managing toolbars. Context menus are sometimes called popup menus.
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# contextmenu.py
 +
 +import wx
 +
 +
 +class MyPopupMenu(wx.Menu):​
 +    def __init__(self,​ parent):
 +        wx.Menu.__init__(self)
 +
 +        self.parent = parent
 +
 +        minimize = wx.MenuItem(self,​ wx.NewId(), '​Minimize'​)
 +        self.AppendItem(minimize)
 +        self.Bind(wx.EVT_MENU,​ self.OnMinimize,​ id=minimize.GetId())
 +
 +        close = wx.MenuItem(self,​ wx.NewId(), '​Close'​)
 +        self.AppendItem(close)
 +        self.Bind(wx.EVT_MENU,​ self.OnClose,​ id=close.GetId())
 +
 +
 +    def OnMinimize(self,​ event):
 +        self.parent.Iconize()
 +
 +    def OnClose(self,​ event):
 +        self.parent.Close()
 +
 +
 +class ContextMenu(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 150))
 +
 +        self.Bind(wx.EVT_RIGHT_DOWN,​ self.OnRightDown)
 +
 +        self.Center()
 +        self.Show()
 +
 +    def OnRightDown(self,​ event):
 +        self.PopupMenu(MyPopupMenu(self),​ event.GetPosition())
 +
 +
 +app = wx.App()
 +frame = ContextMenu(None,​ -1, '​context menu')
 +app.MainLoop()
 +</​code>​
 +
 +
 +<code python>
 + class MyPopupMenu(wx.Menu):​
 +     def __init__(self,​ parent):
 +         ​wx.Menu.__init__(self)
 +</​code>​
 +
 +
 +
 +
 +
 +We create a separate //wx.Menu// class. Here we define two commands. Close and minimize window.
 +
 +
 +
 +
 +<code python>
 + ​self.Bind(wx.EVT_RIGHT_DOWN,​ self.OnRightDown)
 +</​code>​
 +
 +
 +
 +
 +If we right click on the frame, we call the //​OnRightDown()//​ method. For this, we use the //​wx.EVT_RIGHT_DOWN//​ event binder.
 +
 +
 +
 +
 +<code python>
 + def OnRightDown(self,​ event):
 +     ​self.PopupMenu(MyPopupMenu(self),​ event.GetPosition())
 +</​code>​
 +
 +
 +
 +
 +In the OnRightDown() method, we call the //​PopupMenu()//​ method. This method shows the context menu. The first parameter is the menu to be shown. The second parameter is the position, where the context menu appears. The context menus appear at the point of the mouse cursor. To get the actual mouse position, we call the //​GetPosition()//​ menthod.
 +
 +
 +
 +
 +
 +==== Toolbars ====
 +
 +
 +
 +
 +Menus group all commands that we can use in an application. Toolbars provide a quick access to the most frequently used commands. ​
 +
 +
 +
 +
 +<code python>
 + ​CreateToolBar(long style=-1, int winid=-1, String name=ToolBarNameStr)
 +</​code>​
 +
 +
 +
 +
 +To create a toolbar, we call the //​CreateToolBar()//​ method of the frame widget.
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# simpletoolbar.py
 +
 +import wx
 +
 +class SimpleToolbar(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(300, 200))
 +
 +        toolbar = self.CreateToolBar()
 +        toolbar.AddLabelTool(wx.ID_EXIT,​ '',​ wx.Bitmap('​../​icons/​exit.png'​))
 + toolbar.Realize()
 +
 +        self.Bind(wx.EVT_TOOL,​ self.OnExit,​ id=wx.ID_EXIT)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnExit(self,​ event):
 +        self.Close()
 +
 +
 +app = wx.App()
 +SimpleToolbar(None,​ -1, '​simple toolbar'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + ​toolbar.AddLabelTool(wx.ID_EXIT,​ '',​ wx.Bitmap('​../​icons/​exit.png'​))
 +</​code>​
 +
 +
 +
 +
 +To create a toolbar button, we call the //​AddLabelTool()//​ method.
 +
 +
 +
 +
 +<code python>
 + ​toolbar.Realize()
 +</​code>​
 +
 +
 +
 +
 +After we have put our items to the toolbar, we call the //​Realize()//​ method. Calling this method is not obligatory on Linux. On windows it is.
 +
 +
 +
 +
 +<code python>
 + ​self.Bind(wx.EVT_TOOL,​ self.OnExit,​ id=wx.ID_EXIT)
 +</​code>​
 +
 +
 +
 +
 +To handle toolbar events, we use the //​wx.EVT_TOOL//​ event binder.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​simpletoolbar.jpg |simple toolbar}}
 +
 +
 +
 +
 +
 +If we want to create more than one toolbars, we must do it differently.
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# toolbars.py
 +
 +import wx
 +
 +class Toolbars(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(300, 200))
 +
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +
 +        toolbar1 = wx.ToolBar(self,​ -1)
 +        toolbar1.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​new.png'​))
 +        toolbar1.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​open.png'​))
 +        toolbar1.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​save.png'​))
 +        toolbar1.Realize()
 +
 +        toolbar2 = wx.ToolBar(self,​ -1)
 +        toolbar2.AddLabelTool(wx.ID_EXIT,​ '',​ wx.Bitmap('​../​icons/​exit.png'​))
 +        toolbar2.Realize()
 +
 +        vbox.Add(toolbar1,​ 0, wx.EXPAND)
 +        vbox.Add(toolbar2,​ 0, wx.EXPAND)
 +
 +        self.Bind(wx.EVT_TOOL,​ self.OnExit,​ id=wx.ID_EXIT)
 +
 +        self.SetSizer(vbox)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnExit(self,​ event):
 +        self.Close()
 +
 +
 +app = wx.App()
 +Toolbars(None,​ -1, '​toolbars'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + ​toolbar1 = wx.ToolBar(self,​ -1)
 + ...
 + ​toolbar2 = wx.ToolBar(self,​ -1)
 +</​code>​
 +
 +
 +
 +
 +We create two toolbar objects. And put them into a vertical box.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​toolbars.jpg |toolbars}}
 +
 +
 +
 +
 +
 +Sometimes we need to create a vertical toolbar. Vertical toolbars are often seen in graphics applications like Inkscape or Xara Xtreme.
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# verticaltoolbar.py
 +
 +import wx
 +
 +class VerticalToolbar(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(240, 300))
 +
 +        toolbar = self.CreateToolBar(wx.TB_VERTICAL)
 +        toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​select.gif'​))
 +        toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​freehand.gif'​))
 +        toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​shapeed.gif'​))
 +        toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​pen.gif'​))
 +        toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​rectangle.gif'​))
 +        toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​ellipse.gif'​))
 +        toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​qs.gif'​))
 +        toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​text.gif'​))
 +
 +        toolbar.Realize()
 +
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnExit(self,​ event):
 +        self.Close()
 +
 +
 +app = wx.App()
 +VerticalToolbar(None,​ -1, '​vertical toolbar'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + ​toolbar = self.CreateToolBar(wx.TB_VERTICAL)
 +</​code>​
 +
 +
 +
 +
 +Here we create a vertical toolbar. ​
 +
 +
 +
 +
 +<code python>
 + ​toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​select.gif'​))
 + ​toolbar.AddLabelTool(wx.ID_ANY,​ '',​ wx.Bitmap('​../​icons/​freehand.gif'​))
 + ...
 +</​code>​
 +
 +
 +
 +
 +I have borrowed icons from the **Xara Xtreme** graphics application.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​verticaltoolbar.jpg |verticaltoolbar}}
 +
 +
 +
 +
 +
 +
 +In the following example, we will show, how we can enable and disable toolbar buttons. We will also see a separator line.
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# enabledisable.py
 +
 +import wx
 +
 +class EnableDisable(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 150))
 +
 +        self.count = 5
 +
 +        self.toolbar = self.CreateToolBar()
 +        self.toolbar.AddLabelTool(wx.ID_UNDO,​ '',​ wx.Bitmap('​../​icons/​undo.png'​))
 +        self.toolbar.AddLabelTool(wx.ID_REDO,​ '',​ wx.Bitmap('​../​icons/​redo.png'​))
 +        self.toolbar.EnableTool(wx.ID_REDO,​ False)
 +        self.toolbar.AddSeparator()
 +        self.toolbar.AddLabelTool(wx.ID_EXIT,​ '',​ wx.Bitmap('​../​icons/​exit.png'​))
 +        self.toolbar.Realize()
 +
 +        self.Bind(wx.EVT_TOOL,​ self.OnExit,​ id=wx.ID_EXIT)
 +        self.Bind(wx.EVT_TOOL,​ self.OnUndo,​ id=wx.ID_UNDO)
 +        self.Bind(wx.EVT_TOOL,​ self.OnRedo,​ id=wx.ID_REDO)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnUndo(self,​ event):
 +        if self.count > 1 and self.count <= 5:
 +            self.count = self.count - 1
 +
 +        if self.count == 1:
 +            self.toolbar.EnableTool(wx.ID_UNDO,​ False)
 +
 +        if self.count == 4:
 +            self.toolbar.EnableTool(wx.ID_REDO,​ True)
 +
 +    def OnRedo(self,​ event):
 +        if self.count < 5 and self.count >= 1:
 +            self.count = self.count + 1
 +
 +        if self.count == 5:
 +            self.toolbar.EnableTool(wx.ID_REDO,​ False)
 +
 +        if self.count == 2:
 +            self.toolbar.EnableTool(wx.ID_UNDO,​ True)
 +
 +    def OnExit(self,​ event):
 +        self.Close()
 +
 +app = wx.App()
 +EnableDisable(None,​ -1, '​enable disable'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +In our example, we have three toolbar buttons. One button is for exiting the application. The other two buttons are undo and redo buttons. They simulate undo/redo functionality in an application. (for a real example, see tips and tricks) ​ We have 4 changes. The undo and redo butons are disabled accordingly.
 +
 +
 +
 +
 +<code python>
 + ​self.toolbar.EnableTool(wx.ID_REDO,​ False)
 + ​self.toolbar.AddSeparator()
 +</​code>​
 +
 +
 +
 +
 +In the beginning, the redo button is disabled. We do it by calling the //​EnableTool()//​ method. We can create some logical groups within a toolbar. We can separate various groups of buttons by a small vertical line. To do this, we call the //​AddSeparator()//​ method.
 +
 +
 +
 +
 +<code python>
 + def OnUndo(self,​ event):
 +     if self.count > 1 and self.count <= 5:
 +         ​self.count = self.count - 1
 +
 +     if self.count == 1:
 +         ​self.toolbar.EnableTool(wx.ID_UNDO,​ False)
 +
 +     if self.count == 4:
 +         ​self.toolbar.EnableTool(wx.ID_REDO,​ True)
 +</​code>​
 +
 +
 +
 +
 +We simulate undo and redo functionality. We have 4 changes. If there is nothing left to undo, the undo button is disabled. After undoing the first change, we enable the redo button. Same logic applies for the //​OnRedo()//​ method.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​enabledisable.jpg |enabledisable example}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +</​html>​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== ادارة المخططات فى wxPython =====
 +
 +
 +إن إدارة المخطط (توزيع المساحات في واجهة البرنامج) أمر مهم، فعن طريقها نقوم بتحديد طريقة توزيع الودجات على النافذة (مكانا وحجما).
 +
 +نستطيع إدارتها بطريقين:​ الموقع المطلق أو استخدام احد صنوف التخطيط layout classes
 +
 +
 +
 +==== الموضع المطلق ====
 +
 +
 +وهي أن يحدد المبرمج مكان وحجم كل ودجة بوحدة بكسل، عند استخدامك للتحديد المطلق يجب ان تعلم عدة اشياء:
 +
 +    * عند اعادة تحجيم النافذة ، لا يغيّر مكان وحجم الودجة تبعا لذلك
 +    * التطبيق قد يختلف شكله على المنصات المختلفة
 +    * تغيّر الخطوط قد يفسد تصميم المخطط
 +    * إذا قررت تغيّر المخطط، فإنك ستحتاج الى إعادة تنظيمه بالكامل وهو أمر ممل ويأخذ وقتا
 +
 +
 +فى مثالنا ننشئ هيكل لمحرر نصوص.. اذا قمنا بإعادة تحجيم النافذة.. سنجد ان مساحة الودجت wx.TextCtrl لاتتعدل كما نتوقع
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​absolute1.png }}
 + {{ http://​zetcode.com/​wxpython/​images/​absolute2.png }}
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# absolute.py
 +
 +import wx
 +
 +class Absolute(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 180))
 +        panel = wx.Panel(self,​ -1)
 +
 +        menubar = wx.MenuBar()
 +        file = wx.Menu()
 +        edit = wx.Menu()
 +        help = wx.Menu()
 +
 +        menubar.Append(file,​ '&​File'​)
 +        menubar.Append(edit,​ '&​Edit'​)
 +        menubar.Append(help,​ '&​Help'​)
 +        self.SetMenuBar(menubar)
 +
 +        wx.TextCtrl(panel,​ -1, pos=(-1, -1), size=(250, 150))
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App(0)
 +Absolute(None,​ -1, ''​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +<code python>
 + ​wx.TextCtrl(panel,​ -1, pos=(-1, -1), size=(250, 150))
 +</​code>​
 +
 +نقوم بتحديد الموضع فى المشيدّ الخاص بالودجت wx.TextCtrl. فى حالتنا نقوم بتحديد الموقع الإفتراضى.
 +العرض 250 بكسل والإرتفاع 150 بكسل
 +
 +
 +
 +==== Using sizers ====
 +
 +
 +المحجمات تخاطب تلك المشكلات اللتى ذكرناها فى الموضع المطلق.ومنها:​
 +  * wx.BoxSizer
 +  * wx.StaticBoxSizer
 +  * wx.GridSizer
 +  * wx.FlexGridSizer
 +  * wx.GridBagSizer
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​absolute1.png }}
 + {{ http://​zetcode.com/​wxpython/​images/​sizer.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# sizer.py
 +
 +import wx
 +
 +class Sizer(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 180))
 +
 +        menubar = wx.MenuBar()
 +        file = wx.Menu()
 +        edit = wx.Menu()
 +        help = wx.Menu()
 +
 +        menubar.Append(file,​ '&​File'​)
 +        menubar.Append(edit,​ '&​Edit'​)
 +        menubar.Append(help,​ '&​Help'​)
 +        self.SetMenuBar(menubar)
 +
 +        wx.TextCtrl(self,​ -1)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App(0)
 +Sizer(None, -1, ''​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +حسنا، اتقول اننا لانرى المججمات فى المثال؟ ​
 +همم ، هذا الكود مخادع قليلا. فى الواقع لقد وضعنا اداة wx.TextCtrl داخل wx.Frame -الذى يحوى محجّم داخلى- يسمح لنا بوضع ويدجت واحد فقط ليشغل كل المساحة داخل الحاوية wx.Frame
 +
 +==== wx.BoxSizer ====
 +
 +هذا المحجّم يسمح لنا بوضح عدة ويدجات فى صف او عمود. نستطيع ايضا ان نضيف محجّم داخل محجّم اخر مما يسمح لنا بإنشاء محططات معقدة جدا.
 +<code python>
 + box = wx.BoxSizer(integer orient)
 + ​box.Add(wx.Window window, integer proportion=0,​ integer flag = 0, integer border = 0)
 +</​code>​
 +
 +الإتجاة -orientation- ربما يكون رأسى wx.VERTICAL او افقى wx.HORIZONTAL واضافة الويدجات الى المحجم يتم عن طريق الطريقة Add -واللتى لفهمها سنحتاج القاء نظره على معاملاتها
 +
 +معامل proportion بيحدد النسبة اللتى بناء عليها سيتم تقسيم المساحة. على فرض لدينا 3 ازرار بقيم 0و 1 و 2 لل proportion وسيتم اضافتهم لصندوق افقى
 +الزر صاحب القيمة 0 لن يتم حدوث اى تغيير له
 +فعند التغيير سيتغير صاحب القيمة 2 بضعف صاحب القيمة 1 فى الأفقى
 +
 +مع المعامل flag نستطيع ان نحدد سلوك الويدجات داخل المحجّم. نستطيع تحديد الحدود بين الويدجات. نضيف بعض المساحة بين الويدجات -بالبكسل- ولتطبيق الحدود يجب ان نضيفها بالمعامل | ك wx.LEFT|wx.BOTTOM
 +ونستطيع اختيار قيم من:
 +
 +
 +  * wx.LEFT
 +  * wx.RIGHT
 +  * wx.BOTTOM
 +  * wx.TOP
 +  * wx.ALL
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​border.png }}
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# border.py
 +
 +import wx
 +
 +class Border(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 200))
 +
 +        panel = wx.Panel(self,​ -1)
 +        panel.SetBackgroundColour('#​4f5049'​)
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +
 +        midPan = wx.Panel(panel,​ -1)
 +        midPan.SetBackgroundColour('#​ededed'​)
 +
 +        vbox.Add(midPan,​ 1, wx.EXPAND | wx.ALL, 20)
 +        panel.SetSizer(vbox)
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +Border(None,​ -1, ''​)
 +app.MainLoop()
 +</​code>​
 +<code python>
 +vbox.Add(midPan,​ 1, wx.EXPAND | wx.ALL, 20)
 +</​code>​
 +
 +فى المثال اضفنا حدود بمقدار 20 بكسل حول البانل midPan. وwx.ALL تطبق الحد على الأربع جوانب.
 +
 +
 +نستخدم wx.EXPAND حتى يأخذ الويدجت كل المساحة المخصصة له.
 +اخيرا نستطيع تعريف المحاذاة للويدجات عن طريق :
 +
 +  * wx.ALIGN_LEFT
 +  * wx.ALIGN_RIGHT
 +  * wx.ALIGN_TOP
 +  * wx.ALIGN_BOTTOM
 +  * wx.ALIGN_CENTER_VERTICAL
 +  * wx.ALIGN_CENTER_HORIZONTAL
 +  * wx.ALIGN_CENTER ​
 +
 +
 +
 +=== Go To Class ===
 +
 +
 +فى المثال التالى سنقدم بعض الأفكار الهامة.
 +
 +{{ http://​zetcode.com/​wxpython/​images/​gotoclass.png |}}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# gotoclass.py
 +
 +import wx
 +
 +class GoToClass(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(390, 350))
 +        panel = wx.Panel(self,​ -1)
 +
 +        font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
 +        font.SetPointSize(9)
 +
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +
 +        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
 +        st1 = wx.StaticText(panel,​ -1, 'Class Name')
 +        st1.SetFont(font)
 +        hbox1.Add(st1,​ 0, wx.RIGHT, 8)
 +        tc = wx.TextCtrl(panel,​ -1)
 +        hbox1.Add(tc,​ 1)
 +        vbox.Add(hbox1,​ 0, wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, 10)
 +
 +        vbox.Add((-1,​ 10))
 +
 +        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
 +        st2 = wx.StaticText(panel,​ -1, '​Matching Classes'​)
 +        st2.SetFont(font)
 +        hbox2.Add(st2,​ 0)
 +        vbox.Add(hbox2,​ 0, wx.LEFT | wx.TOP, 10)
 +
 +        vbox.Add((-1,​ 10))
 +
 +        hbox3 = wx.BoxSizer(wx.HORIZONTAL)
 +        tc2 = wx.TextCtrl(panel,​ -1, style=wx.TE_MULTILINE)
 +        hbox3.Add(tc2,​ 1, wx.EXPAND)
 +        vbox.Add(hbox3,​ 1, wx.LEFT | wx.RIGHT | wx.EXPAND, 10)
 +
 +        vbox.Add((-1,​ 25))
 +
 +        hbox4 = wx.BoxSizer(wx.HORIZONTAL)
 +        cb1 = wx.CheckBox(panel,​ -1, 'Case Sensitive'​)
 +        cb1.SetFont(font)
 +        hbox4.Add(cb1)
 +        cb2 = wx.CheckBox(panel,​ -1, '​Nested Classes'​)
 +        cb2.SetFont(font)
 +        hbox4.Add(cb2,​ 0, wx.LEFT, 10)
 +        cb3 = wx.CheckBox(panel,​ -1, '​Non-Project classes'​)
 +        cb3.SetFont(font)
 +        hbox4.Add(cb3,​ 0, wx.LEFT, 10)
 +        vbox.Add(hbox4,​ 0, wx.LEFT, 10)
 +
 +        vbox.Add((-1,​ 25))
 +
 +        hbox5 = wx.BoxSizer(wx.HORIZONTAL)
 +        btn1 = wx.Button(panel,​ -1, '​Ok',​ size=(70, 30))
 +        hbox5.Add(btn1,​ 0)
 +        btn2 = wx.Button(panel,​ -1, '​Close',​ size=(70, 30))
 +        hbox5.Add(btn2,​ 0, wx.LEFT | wx.BOTTOM , 5)
 +        vbox.Add(hbox5,​ 0, wx.ALIGN_RIGHT | wx.RIGHT, 10)
 +
 +        panel.SetSizer(vbox)
 +        self.Centre()
 +        self.Show(True)
 +
 +
 +app = wx.App()
 +GoToClass(None,​ -1, 'Go To Class'​)
 +app.MainLoop()
 +</​code>​
 +
 +المخطط مباشر. قمنا بإنشاء محجّم رأسى ووضعنا فيه 5 محجّمات افقية.
 +
 +<code python>
 + font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
 + ​font.SetPointSize(9)
 +</​code>​
 +
 +الخط الإفتراضى المستخدم 10 بكسل، قمت بتعديله ل 9 حتى يناسبنى اكثر
 +
 +
 +<code python>
 + ​vbox.Add(hbox3,​ 1, wx.LEFT | wx.RIGHT | wx.EXPAND, 10)
 +
 + ​vbox.Add((-1,​ 25))
 +</​code>​
 +
 +نعلم اننا نستطيع التحكم فى المسافة بين الودجات بدمج المعامل flag بمعامل الحدود border ​
 +
 +فى الطريقة Add نستطيع ان نحدد border واحد لكل الجوانب.. فى مثالنا اعطينا 10 بكسل لليسار واليمين.. ولكن لانستطيع اعطاء 25 للأسفل..
 +نستطيع استخدام الطريقة Add لإضافة ويدجات و"​مسافات"​ ايضا!
 +
 +<code python>
 +vbox.Add(hbox5,​ 0, wx.ALIGN_RIGHT | wx.RIGHT, 10)
 +</​code>​
 +We place the two buttons on the right side of the window. How do we do it? Three things are important to achieve this. The proportion, the align flag and the wx.EXPAND flag. The proportion must be zero. The buttons should not change their size, when we resize our window. We must not specify wx.EXPAND flag. The buttons occopy only the area that has been alotted to it. And finally, we must specify the wx.ALIGN_RIGHT flag. The horizontal sizer spreads from the left side of the window to the right side. So if we specify wx.ALIGN_RIGHT flag, the buttons are placed to the right side. Exactly, as we wanted.
 +
 +=== Find/​Replace Dialog ===
 +
 +
 +فى مثالنا سننشئ صندوق حوارى find/​replace --من ذلك النوع اللذى قد تجده فى Eclipse IDE
 +
 +{{ http://​zetcode.com/​wxpython/​images/​find_replace.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# Find/​Replace Dialog
 +
 +import wx
 +
 +class FindReplace(wx.Dialog):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Dialog.__init__(self,​ parent, id, title, size=(255, 365))
 +
 +        vbox_top = wx.BoxSizer(wx.VERTICAL)
 +        panel = wx.Panel(self,​ -1)
 +
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +
 +        # panel1
 +
 +        panel1 = wx.Panel(panel,​ -1)
 +        grid1 = wx.GridSizer(2,​ 2)
 +        grid1.Add(wx.StaticText(panel1,​ -1, 'Find: ', (5, 5)), 0,  wx.ALIGN_CENTER_VERTICAL)
 +        grid1.Add(wx.ComboBox(panel1,​ -1, size=(120, -1)))
 +        grid1.Add(wx.StaticText(panel1,​ -1, '​Replace with: ', (5, 5)), 0, wx.ALIGN_CENTER_VERTICAL)
 +        grid1.Add(wx.ComboBox(panel1,​ -1, size=(120, -1)))
 +
 +        panel1.SetSizer(grid1)
 +        vbox.Add(panel1,​ 0, wx.BOTTOM | wx.TOP, 9)
 +
 +        # panel2
 +
 +        panel2 = wx.Panel(panel,​ -1)
 +        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        sizer21 = wx.StaticBoxSizer(wx.StaticBox(panel2,​ -1, '​Direction'​),​ orient=wx.VERTICAL)
 +        sizer21.Add(wx.RadioButton(panel2,​ -1, '​Forward',​ style=wx.RB_GROUP))
 +        sizer21.Add(wx.RadioButton(panel2,​ -1, '​Backward'​))
 +        hbox2.Add(sizer21,​ 1, wx.RIGHT, 5)
 +
 +        sizer22 = wx.StaticBoxSizer(wx.StaticBox(panel2,​ -1, '​Scope'​),​ orient=wx.VERTICAL)
 +        # we must define wx.RB_GROUP style, otherwise all 4 RadioButtons would be mutually exclusive
 +        sizer22.Add(wx.RadioButton(panel2,​ -1, '​All',​ style=wx.RB_GROUP))
 +        sizer22.Add(wx.RadioButton(panel2,​ -1, '​Selected Lines'​))
 +        hbox2.Add(sizer22,​ 1)
 +
 +        panel2.SetSizer(hbox2)
 +        vbox.Add(panel2,​ 0, wx.BOTTOM, 9)
 +
 +        # panel3
 +
 +        panel3 = wx.Panel(panel,​ -1)
 +        sizer3 = wx.StaticBoxSizer(wx.StaticBox(panel3,​ -1, '​Options'​),​ orient=wx.VERTICAL)
 +        vbox3 = wx.BoxSizer(wx.VERTICAL)
 +        grid = wx.GridSizer(3,​ 2, 0, 5)
 +        grid.Add(wx.CheckBox(panel3,​ -1, 'Case Sensitive'​))
 +        grid.Add(wx.CheckBox(panel3,​ -1, 'Wrap Search'​))
 +        grid.Add(wx.CheckBox(panel3,​ -1, 'Whole Word'​))
 +        grid.Add(wx.CheckBox(panel3,​ -1, '​Incremental'​))
 +        vbox3.Add(grid)
 +        vbox3.Add(wx.CheckBox(panel3,​ -1, '​Regular expressions'​))
 +        sizer3.Add(vbox3,​ 0, wx.TOP, 4)
 +
 +        panel3.SetSizer(sizer3)
 +        vbox.Add(panel3,​ 0, wx.BOTTOM, 15)
 +
 +        # panel4
 +
 +        panel4 = wx.Panel(panel,​ -1)
 +        sizer4 = wx.GridSizer(2,​ 2, 2, 2)
 +        sizer4.Add(wx.Button(panel4,​ -1, '​Find',​ size=(120, -1)))
 +        sizer4.Add(wx.Button(panel4,​ -1, '​Replace/​Find',​ size=(120, -1)))
 +        sizer4.Add(wx.Button(panel4,​ -1, '​Replace',​ size=(120, -1)))
 +        sizer4.Add(wx.Button(panel4,​ -1, '​Replace All', size=(120, -1)))
 +
 +        panel4.SetSizer(sizer4)
 +        vbox.Add(panel4,​ 0, wx.BOTTOM, 9)
 +
 +        # panel5
 +
 +        panel5 = wx.Panel(panel,​ -1)
 +        sizer5 = wx.BoxSizer(wx.HORIZONTAL)
 +        sizer5.Add((191,​ -1), 1, wx.EXPAND | wx.ALIGN_RIGHT)
 +        sizer5.Add(wx.Button(panel5,​ -1, '​Close',​ size=(50, -1)))
 +
 +        panel5.SetSizer(sizer5)
 +        vbox.Add(panel5,​ 1, wx.BOTTOM, 9)
 +
 +        vbox_top.Add(vbox,​ 1, wx.LEFT, 5)
 +        panel.SetSizer(vbox_top)
 +
 +        self.Centre()
 +        self.ShowModal()
 +        self.Destroy()
 +
 +
 +app = wx.App()
 +FindReplace(None,​ -1, '​Find/​Replace'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +(Remark for Windows users, put self.SetClientSize(panel.GetBestSize()) line before the ShowModal() method.)
 +
 +
 +قبل ان نكتب المخطط، يجب ان نعرف كيف سنحقق ذلك الهدف.. رسم مبسط للنافذة او الصندوق الحوار ربما يساعد. اذا نظرنا للصندوق الحوارى نجد اننا يمكن ان نقسمه ل 5 اقسام. زر close سيكون له panel منفصلة. كل من الأجزاء هو كائن فريد من wx.Panel ومعا يكون لدينا 6 كائنات من wx.Panel اولهم هى الأب التى ستحوى باقى ال 5
 +
 +ال 5 سيقعو فى عمود واحد.. لذا الpanel الأب ستحوى محجّم رأسى. -بعيدا عن المحجّم الرأسى.. سنستخدم wx.GridSizer --سنشرحة فى القسم القادم- ​
 +ليس هناك الكثير حوله لأنه مباشر جدا
 +
 +<code python>
 + ​sizer4 = wx.GridSizer(2,​ 2, 2, 2)
 + ​sizer4.Add(wx.Button(panel4,​ -1, '​Find',​ size=(120, -1)))
 + ​sizer4.Add(wx.Button(panel4,​ -1, '​Replace/​Find',​ size=(120, -1)))
 + ​sizer4.Add(wx.Button(panel4,​ -1, '​Replace',​ size=(120, -1)))
 + ​sizer4.Add(wx.Button(panel4,​ -1, '​Replace All', size=(120, -1)))
 +</​code>​
 +
 +فى مثالنا wx.GridSizer مفيد جدا .. لدينا 4 ازرار على panel معينة ونريد تقسيمهم فى خلايا شبكة "​صفوف واعمدة"​ كل من تلك الخلايا سيكون لها نفس المساحة والعرض
 +
 +
 +==== wx.GridSizer ====
 +
 +
 +ذلك المجّم هو جدول -شبكة "​صفوف وأعمدة"​- كل خليه منه ذات حجم ثابت
 +
 +
 +<code python>
 + ​wx.GridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)
 +</​code>​
 +
 +المشيد يأخذ عدد الصفوف والأعمدة والمسافات الرأسية والأفقية بين الخلايا
 +
 +فى مثالنا ننشئ هيكل آلة حاسبة ​
 +
 +{{ http://​zetcode.com/​wxpython/​images/​gridsizer.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# gridsizer.py
 +
 +import wx
 +
 +class GridSizer(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(300, 250))
 +
 +
 +        menubar = wx.MenuBar()
 +        file = wx.Menu()
 +        file.Append(1,​ '&​Quit',​ 'Exit Calculator'​)
 +        menubar.Append(file,​ '&​File'​)
 +        self.SetMenuBar(menubar)
 +
 +        self.Bind(wx.EVT_MENU,​ self.OnClose,​ id=1)
 +
 +        sizer = wx.BoxSizer(wx.VERTICAL)
 +        self.display = wx.TextCtrl(self,​ -1, '', ​ style=wx.TE_RIGHT)
 +        sizer.Add(self.display,​ 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 4)
 +        gs = wx.GridSizer(4,​ 4, 3, 3)
 +
 +        gs.AddMany( [(wx.Button(self,​ -1, '​Cls'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​Bck'​),​ 0, wx.EXPAND),
 +            (wx.StaticText(self,​ -1, ''​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​Close'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​7'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​8'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​9'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '/'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​4'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​5'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​6'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​*'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​1'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​2'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​3'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​-'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​0'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​.'​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​='​),​ 0, wx.EXPAND),
 +            (wx.Button(self,​ -1, '​+'​),​ 0, wx.EXPAND) ])
 +
 +        sizer.Add(gs,​ 1, wx.EXPAND)
 +        self.SetSizer(sizer)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnClose(self,​ event):
 +        self.Close()
 +
 +app = wx.App()
 +GridSizer(None,​ -1, '​GridSizer'​)
 +app.MainLoop()
 +</​code>​
 +
 +لاحظ كيف وضعنا مسافة بين Bck و Close .. قمنا بوضع wx.StaticText فارغ
 +
 +فى مثالنا استخدمنا الطريقة AddMany --وهى طريقة مريحة لإضافة مجموعة من الودجات مرة واحدة.
 +
 +<code python>
 + ​AddMany(list items)
 +</​code>​
 +
 +
 +الودجات توضع فى الجدول بالترتيب.. الصف الأول يملء اولا ثم الثانى.. الخ.
 +
 +==== wx.FlexGridSizer ====
 +
 +
 +
 +
 +
 +This sizer is similar to //​wx.GridSizer//​. It does  also lay out it's widgets in a two dimensional table. It adds some flexibility to it. //​wx.GridSizer//​ cells are of the same size. All cells in //​wx.FlexGridSizer//​ have the same height in a row. All cells have the same width in a column. ​
 +But all rows and columns are not necessarily the same height or width. ​
 +
 +
 +
 +
 +<code python>
 + ​wx.FlexGridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)
 +</​code>​
 +
 +
 +
 +
 +//rows// and //cols// specify the number of rows and columns in a sizer. //vgap// and //hgap// add some space between widgets in both directions. ​
 +
 +
 +
 +
 +
 +
 +
 +Many times developers have to develop dialogs for data input and modification. I find //​wx.FlexGridSizer//​ suitable for such a task. A developer can easily set up a dialog window with this sizer. It is also possible to accomplish this with //​wx.GridSizer//,​ but it would not look nice, because of the constraint that each cell has the same size. 
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# flexgridsizer.py
 +
 +import wx
 +
 +class FlexGridSizer(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(290, 250))
 +
 +        panel = wx.Panel(self,​ -1)
 +
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        fgs = wx.FlexGridSizer(3,​ 2, 9, 25)
 +
 +        title = wx.StaticText(panel,​ -1, '​Title'​)
 +        author = wx.StaticText(panel,​ -1, '​Author'​)
 +        review = wx.StaticText(panel,​ -1, '​Review'​)
 +
 +        tc1 = wx.TextCtrl(panel,​ -1)
 +        tc2 = wx.TextCtrl(panel,​ -1)
 +        tc3 = wx.TextCtrl(panel,​ -1, style=wx.TE_MULTILINE)
 +
 +        fgs.AddMany([(title),​ (tc1, 1, wx.EXPAND), (author), (tc2, 1, wx.EXPAND),
 +            (review, 1, wx.EXPAND), (tc3, 1, wx.EXPAND)])
 +
 +        fgs.AddGrowableRow(2,​ 1)
 +        fgs.AddGrowableCol(1,​ 1)
 +
 +        hbox.Add(fgs,​ 1, wx.ALL | wx.EXPAND, 15)
 +        panel.SetSizer(hbox)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +FlexGridSizer(None,​ -1, '​FlexGridSizer'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + hbox = wx.BoxSizer(wx.HORIZONTAL)
 + ...
 + ​hbox.Add(fgs,​ 1, wx.ALL | wx.EXPAND, 15)
 +</​code>​
 +
 +
 +
 +
 +We create a horizontal box sizer in order to put some space (15px) around the table of widgets.
 +
 +
 +
 +
 +<code python>
 + ​fgs.AddMany([(title),​ (tc1, 1, wx.EXPAND), (author), (tc2, 1, wx.EXPAND),
 +      (review, 1, wx.EXPAND), (tc3, 1, wx.EXPAND)])
 +</​code>​
 +
 +
 +
 +
 +We add widgets to the sizer with the //​AddMany()//​ method. Both //​wx.FlexGridSizer//​ and //​wx.GridSizer//​ share this method.
 +
 +
 +
 +
 +<code python>
 + ​fgs.AddGrowableRow(2,​ 1)
 + ​fgs.AddGrowableCol(1,​ 1)
 +</​code>​
 +
 +
 +
 +
 +We make the third row and second column growable. This way we let the text controls grow, when the window is resized.
 +The first two text controls will grow in horizontal direction, the third one will grow in both direction. ​
 +We must not forget to make the widgets expandable (wx.EXPAND) in order to make it really work. 
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​flexgridsizer.png |}}
 +
 +
 +
 +==== wx.GridBagSizer ====
 +
 +
 +
 +
 +
 +The most complicated sizer in wxPython. Many programmer find it difficult to use. This kind of sizer is not typical only for wxPython. We can 
 +find it in other toolkits as well. There is no magic in using this sizer. Even though it is more complicated,​ it is certainly not rocket science.
 +All we have to do is to create several layouts with it. Find all the quirks. Play with it a bit. There are more difficult things in programming. Believe me.
 +
 +
 +
 +
 +
 +
 + 
 +This sizer enables explicit positioning of items. Items can also optionally span more than one row and/or column. wx.GridBagSizer has a simple constructor.
 +
 +
 +
 +
 +<code python>
 + ​wx.GridBagSizer(integer vgap, integer hgap)
 +</​code>​
 +
 +
 +
 +
 +The vertical and the horizontal gap defines the space in pixels used among all children. We add items to the grid with the Add() method.
 +
 +
 +
 +
 +<code python>
 + ​Add(self,​ item, tuple pos, tuple span=wx.DefaultSpan,​ integer flag=0, integer border=0, userData=None)
 +</​code>​
 +
 +
 +
 +
 +Item is a widget that you insert into the grid. pos specifies the position in the virtual grid. The topleft cell has pos of (0, 0). span is an optional spanning of the widget. e.g. span of (3, 2) spans a widget across 3 rows and 2 columns. flag and border were discussed earlier by wx.BoxSizer. ​
 +
 +The items in the grid can change their size or keep the default size, when the window is resized. If you want your items to grow and shrink, you can use these two methods.
 +
 +
 +
 +
 +<code python>
 + ​AddGrowableRow(integer row)
 + ​AddGrowableCol(integer col)
 +</​code>​
 +
 +
 +
 +
 +=== Rename dialog ===
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​rename.png |}}
 +
 +
 +
 +
 +
 +The first example is intentionally a very simple one. So that it could be easily understood. There is no need to be afraid of wx.GridBagSizer. Once you understand it's logic, it is quite simple to use it. In our example, we will create a rename dialog. It will have one wx.StaticText,​ one wx.TextCtrl and two wx.Button-s. ​
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# rename.py
 +
 +import wx
 +
 +class Rename(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(320, 130))
 +
 +        panel = wx.Panel(self,​ -1)
 +        sizer = wx.GridBagSizer(4,​ 4)
 +
 +        text = wx.StaticText(panel,​ -1, '​Rename To')
 +        sizer.Add(text,​ (0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
 +
 +        tc = wx.TextCtrl(panel,​ -1)
 +        sizer.Add(tc,​ (1, 0), (1, 5), wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
 +
 +        buttonOk = wx.Button(panel,​ -1, '​Ok',​ size=(90, 28))
 +        buttonClose = wx.Button(panel,​ -1, '​Close',​ size=(90, 28))
 +        sizer.Add(buttonOk,​ (3, 3))
 +        sizer.Add(buttonClose,​ (3, 4), flag=wx.RIGHT | wx.BOTTOM, border=5)
 +
 +        sizer.AddGrowableCol(1)
 +        sizer.AddGrowableRow(2)
 +        panel.SetSizerAndFit(sizer)
 +        self.Centre()
 +        self.Show(True)
 +
 +
 +app = wx.App()
 +Rename(None,​ -1, '​Rename Dialog'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +We must look at the dialog window as a one big grid table.
 +
 +
 +<code python>
 + text = wx.StaticText(panel,​ -1, '​Rename To')
 + ​sizer.Add(text,​ (0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
 +</​code>​
 +The text '​Rename to' goes to the left upper corner. So we specify the (0, 0) position. Plus we add some space to the bottom, left and bottom.
 +<code python>
 + tc = wx.TextCtrl(panel,​ -1)
 + ​sizer.Add(tc,​ (1, 0), (1, 5), wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
 +</​code>​
 +
 +
 +
 +The wx.TextCtrl goes to the beginning of the second row (1, 0). Remember, that we count from zero. It expands 1 row and 5 columns. (1, 5). Plus we put 
 +5 pixels of space to the left and to the right of the widget. ​
 +
 +
 +
 +<code python>
 + ​sizer.Add(buttonOk,​ (3, 3))
 + ​sizer.Add(buttonClose,​ (3, 4), flag=wx.RIGHT | wx.BOTTOM, border=5)
 +</​code>​
 +
 +
 +
 +We put two buttons into the fourth row. The third row is left empty, so that we have some space between the wx.TextCtrl and the buttons. We put the ok button into the fourth column and the close button into the fifth one. Notice that once we apply some space to one widget, it is applied to the whole row. That's why I did not specify bottom space for the ok button.
 +A careful reader might notice, that we did not specify any space between the two buttons. e.g. we did not put any space to the right of the ok button, or to the right of the close button. In the constructor of the wx.GridBagSizer,​ we put some space between all widgets. So there is some space already.
 +
 +
 +
 +
 +<code python>
 + ​sizer.AddGrowableCol(1)
 + ​sizer.AddGrowableRow(2)
 +</​code>​
 +
 +
 +
 +The last thing we must do, is to make our dialog resizable. We make the second column and the third row growable. Now we can expand or shrink our window. Try to comment those two lines and see what happens. ​
 +
 +
 +
 +
 +=== Open Resource ===
 +
 +
 +
 +
 +The next example will be a bit more complicated. We will create an Open Resource window. This example will show a layout of a very handy dialog which you can find in Eclipse IDE. 
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​openresource.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# openresource.py
 +
 +import wx
 +
 +class OpenResource(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(400, 500))
 +
 +        panel = wx.Panel(self,​ -1)
 +        sizer = wx.GridBagSizer(4,​ 4)
 +
 +        text1 = wx.StaticText(panel,​ -1, '​Select a resource to open')
 +        sizer.Add(text1,​ (0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
 +
 +        tc = wx.TextCtrl(panel,​ -1)
 +        sizer.Add(tc,​ (1, 0), (1, 3), wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
 +
 +        text2 = wx.StaticText(panel,​ -1, '​Matching resources'​)
 +        sizer.Add(text2,​ (2, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
 +
 +        list1 = wx.ListBox(panel,​ -1, style=wx.LB_ALWAYS_SB)
 +        sizer.Add(list1,​ (3, 0), (5, 3), wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
 +
 +        text3 = wx.StaticText(panel,​ -1, 'In Folders'​)
 +        sizer.Add(text3,​ (8, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
 +
 +        list2 = wx.ListBox(panel,​ -1, style=wx.LB_ALWAYS_SB)
 +        sizer.Add(list2,​ (9, 0), (3, 3), wx.EXPAND | wx.LEFT | wx.RIGHT, 5)
 +
 +        cb = wx.CheckBox(panel,​ -1, 'Show derived resources'​)
 +        sizer.Add(cb,​ (12, 0), flag=wx.LEFT | wx.RIGHT, border=5)
 +
 +        buttonOk = wx.Button(panel,​ -1, '​OK',​ size=(90, 28))
 +        buttonCancel = wx.Button(panel,​ -1, '​Cancel',​ size=(90, 28))
 +        sizer.Add(buttonOk,​ (14, 1))
 +        sizer.Add(buttonCancel,​ (14, 2), flag=wx.RIGHT | wx.BOTTOM, border=5)
 +
 +        help = wx.BitmapButton(panel,​ -1, wx.Bitmap('​icons/​help16.png'​),​ style=wx.NO_BORDER)
 +        sizer.Add(help,​ (14, 0), flag=wx.LEFT,​ border=5)
 +
 +        sizer.AddGrowableCol(0)
 +        sizer.AddGrowableRow(3)
 +        sizer.AddGrowableRow(9)
 +        sizer.SetEmptyCellSize((5,​ 5))
 +        panel.SetSizer(sizer)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +OpenResource(None,​ -1, 'Open Resource'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + ​sizer.AddGrowableRow(3)
 + ​sizer.AddGrowableRow(9)
 +</​code>​
 +
 +
 +
 +We want to have both wx.ListBox-es growable. So we make the first row of each wx.ListBox growable. ​
 +
 +
 +
 +
 +=== Create new class ===
 +
 +
 +
 +
 +newclass.py example is a type of a window, that I found in JDeveloper. It is a dialog window for creating a new class in Java.
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​newclass.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# newclass.py
 +
 +import wx
 +
 +class NewClass(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        panel = wx.Panel(self,​ -1)
 +        sizer = wx.GridBagSizer(0,​ 0)
 +
 +        text1 = wx.StaticText(panel,​ -1, 'Java Class'​)
 +        sizer.Add(text1,​ (0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=15)
 +
 +        icon = wx.StaticBitmap(panel,​ -1, wx.Bitmap('​icons/​exec.png'​))
 +        sizer.Add(icon,​ (0, 4), flag=wx.LEFT, ​ border=45)
 +
 +        line = wx.StaticLine(panel,​ -1 )
 +        sizer.Add(line,​ (1, 0), (1, 5), wx.TOP | wx.EXPAND, -15)
 +
 +        text2 = wx.StaticText(panel,​ -1, '​Name'​)
 +        sizer.Add(text2,​ (2, 0), flag=wx.LEFT,​ border=10)
 +
 +        tc1 = wx.TextCtrl(panel,​ -1, size=(-1, 30))
 +        sizer.Add(tc1,​ (2, 1), (1, 3), wx.TOP | wx.EXPAND, -5)
 +
 +        text3 = wx.StaticText(panel,​ -1, '​Package'​)
 +        sizer.Add(text3,​ (3, 0), flag= wx.LEFT | wx.TOP, border=10)
 +
 +        tc2 = wx.TextCtrl(panel,​ -1)
 +        sizer.Add(tc2,​ (3, 1), (1, 3), wx.TOP | wx.EXPAND, 5)
 +
 +        button1 = wx.Button(panel,​ -1, '​Browse...',​ size=(-1, 30))
 +        sizer.Add(button1,​ (3, 4), (1, 1), wx.TOP | wx.LEFT | wx.RIGHT , 5)
 +
 +        text4 = wx.StaticText(panel,​ -1, '​Extends'​)
 +        sizer.Add(text4,​ (4, 0), flag=wx.TOP | wx.LEFT, border=10)
 +
 +        combo = wx.ComboBox(panel,​ -1, )
 +        sizer.Add(combo,​ (4, 1), (1, 3), wx.TOP | wx.EXPAND, ​ 5)
 +
 +        button2 = wx.Button(panel,​ -1, '​Browse...',​ size=(-1, 30))
 +        sizer.Add(button2,​ (4, 4), (1, 1), wx.TOP | wx.LEFT | wx.RIGHT , 5)
 +
 +        sb = wx.StaticBox(panel,​ -1, '​Optional Attributes'​)
 +        boxsizer = wx.StaticBoxSizer(sb,​ wx.VERTICAL)
 +        boxsizer.Add(wx.CheckBox(panel,​ -1, '​Public'​),​ 0, wx.LEFT | wx.TOP, 5)
 +        boxsizer.Add(wx.CheckBox(panel,​ -1, '​Generate Default Constructor'​),​ 0,  wx.LEFT, 5)
 +        boxsizer.Add(wx.CheckBox(panel,​ -1, '​Generate Main Method'​),​ 0, wx.LEFT | wx.BOTTOM, 5)
 +        sizer.Add(boxsizer,​ (5, 0), (1, 5), wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT , 10)
 +        button3 = wx.Button(panel,​ -1, '​Help',​ size=(-1, 30))
 +        sizer.Add(button3,​ (7, 0), (1, 1),  wx.LEFT, 10)
 +
 +        button4 = wx.Button(panel,​ -1, '​Ok',​ size=(-1, 30))
 +        sizer.Add(button4,​ (7, 3), (1, 1),  wx.LEFT, 10)
 +
 +        button5 = wx.Button(panel,​ -1, '​Cancel',​ size=(-1, 30))
 +        sizer.Add(button5,​ (7, 4), (1, 1),  wx.LEFT | wx.BOTTOM | wx.RIGHT, 10)
 +
 +        sizer.AddGrowableCol(2)
 +        sizer.Fit(self)
 +        panel.SetSizer(sizer)
 +        self.Centre()
 +        self.Show(True)
 +
 +
 +app = wx.App()
 +NewClass(None,​ -1, '​Create Java Class'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + line = wx.StaticLine(panel,​ -1 )
 + ​sizer.Add(line,​ (1, 0), (1, 5), wx.TOP | wx.EXPAND, -15)
 +</​code>​
 +
 +
 +
 +Notice, that we have used negative number for setting the top border. We could use wx.BOTTOM with border 15. We would get the same result.
 +
 +
 +
 +<code python>
 + icon = wx.StaticBitmap(panel,​ -1, wx.Bitmap('​icons/​exec.png'​))
 + ​sizer.Add(icon,​ (0, 4), flag=wx.LEFT, ​ border=45)
 +</​code>​
 +
 +
 +
 +We put an wx.StaticBitmap into the first row of the grid. We place it on the right side of the row. By using images we can make our 
 +applications look better. ​
 +
 +
 +
 +<code python>
 +sizer.Fit(self)
 +</​code>​
 +
 +
 +
 +We did not set the size of the window explicitly. If we call Fit() method, the size of the window will exactly cover all widgets available.
 +Try to comment this line and see what happens.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +</​html>​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Events in wxPython =====
 +
 +الأحداث هى جزء هام في أي تطبيق رسومى، وهى تحدث من المستخدم او من النظام. عندما نستدعى MainLoop‎ يدخل التطبيق فى الحلقة الأساسية main loop. وهي بدورها تستخرج الأحداث وترسلها إلى الكائنات. ​
 +
 +
 +
 +Events are integral part of every GUI application. All GUI applications are event-driven. An application reacts to different event types which are generated during its life. Events are generated mainly by the user of an application. But they can be generated by other means as well. e.g. internet connection, window manager, timer. So when we call MainLoop() method, our application waits for events to be generated. The MainLoop() method ends when we exit the application. ​
 +
 +
 +
 +
 +
 +==== تعريفات ====
 +
 +**الحدث** هو جزء من المعلومات على مستوى التطبيق ​
 +**حلقة الأحداث** تنتظر لحدوث حدث او وصول رسالة للبرنامج ليتم معالجته ​
 +**التوزيع** عملية بربط الأحداث بمعالجى الأحداث
 +**معالج الحدث** هى طريقة نقوم بتعريفها للتفاعل مع حدوث حدث معين
 +**كائن الحدث** هو كائن يرتبط بالحدث وغالبا هو نافذة
 +**نوع الحدث** هو حدث فريد يتم توليده
 +**رابط الحدث** هو كائن يقوم بربط الحدث بمعالج الحدث
 +
 +
 +
 +
 +
 +==== مثال بسيط ====
 +
 +فى الجزء التالى سنتكلم عن حدث بسيط هو حدث الإنتقال move
 +
 +حدث الإنتقال move event ينتج عندما ننقل نافذة لموضع جديد وهو من النوع wx.MoveEvent ورابط الحدث له هو wx.EVT_MOVE
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# moveevent.py
 +
 +import wx
 +
 +class MoveEvent(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 180))
 +
 +        wx.StaticText(self,​ -1, '​x:',​ (10,10))
 +        wx.StaticText(self,​ -1, '​y:',​ (10,30))
 +        self.st1 = wx.StaticText(self,​ -1, '',​ (30, 10))
 +        self.st2 = wx.StaticText(self,​ -1, '',​ (30, 30))
 +
 +        self.Bind(wx.EVT_MOVE,​ self.OnMove)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnMove(self,​ event):
 +        x, y = event.GetPosition()
 +        self.st1.SetLabel(str(x))
 +        self.st2.SetLabel(str(y))
 +
 +
 +app = wx.App()
 +MoveEvent(None,​ -1, 'move event'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +المثال يعرض الموضع الحالى للنافذة.
 +
 +
 +<code python>
 + ​self.Bind(wx.EVT_MOVE,​ self.OnMove)
 +</​code>​
 +
 +
 +
 +
 +Here we bind the //​wx.EVT_MOVE//​ event binder to the //​OnMove()//​ method.
 +
 +
 +
 +
 +<code python>
 + def OnMove(self,​ event):
 +     x, y = event.GetPosition()
 +</​code>​
 +
 +المعامل event فى الطريقة OnMove هو كائن ينتمى لنوع حدث معين وفى حالتنا هذه هو wx.MoveEvent ويحمل هذا الكائن معلومات عن الحدث مثل الموضع وكائن الحدث --فى حالتنا هو wx.Frame-- ​
 +للحصول على الموضع الحالى نستدعى الطريقة GetPosition للحدث
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​moveevent.jpg }}
 +
 +
 +
 +==== ربط الحدث ====
 +
 +العمل مع الأحداث مباشر فى wxPython ويتم على 3 خطوات
 +
 +
 +1- التعرف على اسم رابط الحدث wx.EVT_SIZE او wx.EVT_CLOSE ..الخ
 +2-انشاء معالج الحدث ليتم استدعاءه عند حدوث الحدث
 +3- ربط الحدث بمعالج الحدث
 +
 +لربط الحدث نستطيع استخدام الطريقة Bind والتى تعريفها كالتالى
 +
 +<code python>
 + ​Bind(event,​ handler, source=None,​ id=wx.ID_ANY,​ id2=wx.ID_ANY)
 +</​code>​
 +حيث:
 +* ال event هو احد كائنات EVT_* لتحديد نوع الحدث
 +* ال handler وهو المعالج للحدث
 +* ال source للتفريق بين الحدث من الودجات المختلفة
 +* ال id يستخدم عندما يكون لدينا عدة ازرار، عناصر قوائم .. الخ للتفريق بينهم
 +
 +
 +الطريقة Bind معرفة فى الصف EvtHandler وهو الصف اللذى ترث منه wx.Window ​
 +لاحظ ان wx.Window هى الصف الأب لمعظم الويدجات
 +
 +هناك ايضا عملية عكسية عن طريق الطريقة Unbind ولها نفس معاملات Bind
 +
 +  * event is one of EVT_* objects. It specifies the type of the event.
 +  * handler is an object to be called. In other words, it is a method, that a programmer binds to an event. ​
 +  * source parameter is used when we want to differentiate between the same event type from different widgets. ​
 +  * id parameter is used, when we have multiple buttons, menu items etc. The id is used to differentiate among them. 
 +  * id2 is used when it is desirable to bind a handler to a range of ids, such as with EVT_MENU_RANGE. ​
 +
 +
 +
 +
 +
 +Note that method Bind() is defined in class EvtHandler. It is the class, from which wx.Window inherits. wx.Window is a base class for most widgets in wxPython. There is also a reverse process. If we want to unbind a method from an event, we call the Unbind() method. It has the same paremeters as the above one.
 +
 +
 +
 +
 +
 +==== ايقاف معالجة الحدث ====
 +
 +
 +فى بعض الأحيان نريد ايقاف معالجة حدث معين. يتم ذلك عن طريق استدعاء الطريقة Veto
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# veto.py
 +
 +import wx
 +
 +class Veto(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 200))
 +
 +
 +        self.Bind(wx.EVT_CLOSE,​ self.OnClose)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnClose(self,​ event):
 +
 +        dial = wx.MessageDialog(None,​ 'Are you sure to quit?',​ '​Question',​
 +            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
 +        ret = dial.ShowModal()
 +        if ret == wx.ID_YES:
 +            self.Destroy()
 +        else:
 +            event.Veto()
 +
 +
 +app = wx.App()
 +Veto(None, -1, '​Veto'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +فى مثالنا نعالج حدث من النوع wx.CloseEvent ويحدث عندما نغلق النافذة سواء بالضغط على علامة X فى شريط العنوان او بأى طريقة اخرى. فى كثير من التطبيقات نرغب فى منع اغلاق النافذة بالخطأ. لذا يجب علينا القيام ببعض التعديلات ، وذلك عن طريق ربط الحدث wx.EVT_CLOSE ​
 +
 +
 +<code python>
 + dial = wx.MessageDialog(None,​ 'Are you sure to quit?',​ '​Question',​
 +     ​wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
 + ret = dial.ShowModal()
 +</​code>​
 +
 +
 +عند محاولة الإغلاق نعرض صندوق استفهامى
 +
 +<code python>
 + if ret == wx.ID_YES:
 +     ​self.Destroy()
 + else:
 +     ​event.Veto()
 +</​code>​
 +
 +وبناء على القيمة العائدة نحدد اما ان ندمر النافذة او نوقف معالجة الحدث.
 +
 +لاحظ لإعلاق النافذةيجب علينا استدعاء Destroy
 +
 +لاحظ ان بإستدعاء الطريقة Close سندخل فى حلقة لانهائية :)
 +
 +
 +
 +
 +==== انتشار الحدث ====
 +
 +هناك نوعين من الأحداث، احداث اساسية او اولية واحداث الأوامر وبيختلفا فى عملية الإنتشار
 +
 +*انتشار الحدث* انتقال الأحداث من الأبناء للأباء ثم للأجداد.. الخ ​
 +الأحداث الأوليه لاتنتشر بعكس احداث الأوامر. ​
 +على سبيل المثال الحدث wx.CloseEvent هو حدث اولى لاينتشر.. ليس منطقيا ان ينتشر هذا الأحدث للأباء اليس كذلك ؟
 +
 +افتراضيا، عند معالجة حدث ما فإنه يتوقف عن الإنتشار، ولإكمال عملية الإنتشار يجب استدعاء الطريقة Skip
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# propagate.py
 +
 +import wx
 +
 +
 +class MyPanel(wx.Panel):​
 +    def __init__(self,​ parent, id):
 +        wx.Panel.__init__(self,​ parent, id)
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnClicked)
 +
 +    def OnClicked(self,​ event):
 +        print 'event reached panel class'
 +        event.Skip()
 +
 +
 +class MyButton(wx.Button):​
 +    def __init__(self,​ parent, id, label, pos):
 +        wx.Button.__init__(self,​ parent, id, label, pos)
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnClicked)
 +
 +    def OnClicked(self,​ event):
 +        print 'event reached button class'
 +        event.Skip()
 +
 +
 +class Propagate(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 150))
 +
 +        panel = MyPanel(self,​ -1)
 +
 +        MyButton(panel,​ -1, '​Ok',​ (15, 15))
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnClicked)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnClicked(self,​ event):
 +        print 'event reached frame class'
 +        event.Skip()
 +
 +
 +app = wx.App()
 +Propagate(None,​ -1, '​Propagate'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +فى مثالنا لدينا زر على بانل موضوعة على frame 
 +
 +قمنا بتعريف معالج لكل الودجات
 +
 +
 +
 +<code python>
 + event reached button class
 + event reached panel class
 + event reached frame class
 +</​code>​
 +
 +لتفهم هذا، عندما نضغط على الزر فإن الحدث ينتقل من الزر الى البانل ثم الى ال frame
 +
 +جرب حذف بعض استدعاءات Skip ولاحظ ماذا سيحدث
 +
 +
 +
 +==== Window identifiers ====
 +
 +
 +
 +Window identifiers are integers that uniquely determine the window identity in the event system. ​
 +There are three ways to create window id's.
 +
 +
 +
 +
 +
 +  * let the system automatically create an id
 +  * use standard identifiers
 +  * create your own id
 +
 +
 +
 +
 +
 +Each widget has an id parameter. This is a unique number in the event system. If we work with multiple widgets, we must differantiate among them.
 +
 +
 +
 +
 +<code python>
 + ​wx.Button(parent,​ -1)
 + ​wx.Button(parent,​ wx.ID_ANY)
 +</​code>​
 +
 +
 +
 +
 +If we provide -1 or wx.ID_ANY for the id parameter, we let the wxPython automatically create an id for us. The automatically created id's are always negative, whereas user specified id's must always be positive. We usually use this option when we do not need to change the widget state. For example a static text, that will never be changed during the life of the application. We can still get the id, if we want. There is a method //​GetId()//,​ which will determine the id for us.
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# automaticids.py
 +
 +import wx
 +
 +class AuIds(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(170, 100))
 +
 +        panel = wx.Panel(self,​ -1)
 +        exit = wx.Button(panel,​ -1, '​Exit',​ (10, 10))
 +
 +        self.Bind(wx.EVT_BUTTON, ​ self.OnExit,​ id=exit.GetId())
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnExit(self,​ event):
 +        self.Close()
 +
 +
 +app = wx.App()
 +AuIds(None, -1, ''​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +In this example, we do not care about the actual id value. ​
 +
 +
 +
 +
 +<code python>
 + ​self.Bind(wx.EVT_BUTTON, ​ self.OnExit,​ id=exit.GetId())
 +</​code>​
 +
 +
 +
 +
 +We get the automatically generated id by calling the //GetId()// method.
 +
 +
 +
 +
 +
 +
 +
 +
 +Standard identifiers should be used whenever possible. The identifiers can provide some standard graphics or behaviour on some platforms. ​
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# identifiers.py
 +
 +import wx
 +
 +class Identifiers(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(200, 150))
 +
 +        panel = wx.Panel(self,​ -1)
 +        grid = wx.GridSizer(3,​ 2)
 +
 +        grid.AddMany([(wx.Button(panel,​ wx.ID_CANCEL),​ 0, wx.TOP | wx.LEFT, 9),
 +            (wx.Button(panel,​ wx.ID_DELETE),​ 0, wx.TOP, 9),
 +            (wx.Button(panel,​ wx.ID_SAVE),​ 0, wx.LEFT, 9),
 +            (wx.Button(panel,​ wx.ID_EXIT)),​
 +            (wx.Button(panel,​ wx.ID_STOP),​ 0, wx.LEFT, 9),
 +            (wx.Button(panel,​ wx.ID_NEW))])
 +
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnQuit,​ id=wx.ID_EXIT)
 +
 +        panel.SetSizer(grid)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnQuit(self,​ event):
 +        self.Close()
 +
 +app = wx.App()
 +Identifiers(None,​ -1, ''​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +In our example we use standard identifiers on buttons. On linux, the buttons have small icons.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​identifiers.jpg }}
 +
 +
 +
 +
 +
 +
 +The last option is to use own identifiers. We define our own global ids. 
 +
 +
 +
 +
 +==== Miscellaneous events ====
 +
 +
 +=== Focus event ===
 +
 +
 +
 +
 +The focus indicates the currently selected widget in application. The text entered from the keyboard or pasted from the clipboard is sent to the widget, which has the focus. There are two event types concerning focus. The **wx.EVT_SET_FOCUS**
 +event, which is generated when a widget receives focus. The **wx.EVT_KILL_FOCUS** is generated, when the widget looses focus. The focus is changed by clicking or by a keybord key. Usually Tab/​Shift+Tab.
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# focusevent.py
 +
 +import wx
 +
 +
 +class MyWindow(wx.Panel):​
 +    def __init__(self,​ parent):
 +        wx.Panel.__init__(self,​ parent, -1)
 +
 +        self.color = '#​b3b3b3'​
 +
 +        self.Bind(wx.EVT_PAINT,​ self.OnPaint)
 +        self.Bind(wx.EVT_SIZE,​ self.OnSize)
 +        self.Bind(wx.EVT_SET_FOCUS,​ self.OnSetFocus)
 +        self.Bind(wx.EVT_KILL_FOCUS,​ self.OnKillFocus)
 +
 +    def OnPaint(self,​ event):
 +        dc = wx.PaintDC(self)
 +
 +        dc.SetPen(wx.Pen(self.color))
 +        x, y = self.GetSize()
 +        dc.DrawRectangle(0,​ 0, x, y)
 +
 +    def OnSize(self,​ event):
 +        self.Refresh()
 +
 +    def OnSetFocus(self,​ event):
 +        self.color = '#​0099f7'​
 +        self.Refresh()
 +
 +    def OnKillFocus(self,​ event):
 +        self.color = '#​b3b3b3'​
 +        self.Refresh()
 +
 +class FocusEvent(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(350, 250))
 +
 +        grid = wx.GridSizer(2,​ 2, 10, 10)
 +        grid.AddMany([(MyWindow(self),​ 1, wx.EXPAND|wx.TOP|wx.LEFT,​9),​
 +            (MyWindow(self),​ 1, wx.EXPAND|wx.TOP|wx.RIGHT,​ 9), 
 +            (MyWindow(self),​ 1, wx.EXPAND|wx.BOTTOM|wx.LEFT,​ 9), 
 +            (MyWindow(self),​ 1, wx.EXPAND|wx.BOTTOM|wx.RIGHT,​ 9)])
 +
 +
 +        self.SetSizer(grid)
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +FocusEvent(None,​ -1, 'focus event'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +In our example, we have four panels. The panel with focus is highlighted. ​
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​focusevent.jpg }}
 +
 +
 +
 +
 +=== ScrollEvent ===
 +
 +
 +
 +The following code is an example of a wx.ScrollWinEvent. This event is generated, when we click on a built in Scrollbar. Built-in Scrollbar is activated with the SetScrollbar() method call. For stand-alone Scrollbars, there is another event type, namely wx.ScrollEvent.
 +
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# myscrollwinevent.py
 +
 +import wx
 +
 +class ScrollWinEvent(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +        panel = wx.Panel(self,​ -1)
 +        self.st = wx.StaticText(panel,​ -1, '​0',​ (30,0))
 +        panel.Bind(wx.EVT_SCROLLWIN,​ self.OnScroll)
 +        panel.SetScrollbar(wx.VERTICAL,​ 0, 6, 50);
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnScroll(self,​ evt):
 +        y = evt.GetPosition()
 +        self.st.SetLabel(str(y))
 +
 +app = wx.App()
 +ScrollWinEvent(None,​ -1, '​scrollwinevent.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +=== SizeEvent ===
 +
 +
 +
 +
 +A wx.SizeEvent is generated, when our window is resized. In our example, we show the size of the window in the titlebar.
 +
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# sizeevent.py
 +
 +import wx
 +
 +class SizeEvent(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        self.Bind(wx.EVT_SIZE,​ self.OnSize)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnSize(self,​ event):
 +        self.SetTitle(str(event.GetSize()))
 +
 +
 +app = wx.App()
 +SizeEvent(None,​ 1, '​sizeevent.py'​)
 +app.MainLoop()
 +
 +</​code>​
 +
 +
 +<code python>
 + ​self.SetTitle(str(event.GetSize()))
 +</​code>​
 +
 +
 +
 +
 +To get the current size of the window, we call the //​GetSize()//​ method of the event object.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​sizeevent.png }}
 +
 +
 +
 +
 +=== PaintEvent ===
 +
 +
 +
 +A paint event is generated when a window is redrawn. This happens when we resize a window or when we maximize it. A paint event can be generated programatically as well. For example, when we call SetLabel() method to change a wx.StaticText widget. Note that when we minimize a window, no paint event is generated.
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# paintevent.py
 +
 +import wx
 +
 +class PaintEvent(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        self.count = 0
 +        self.Bind(wx.EVT_PAINT,​ self.OnPaint)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnPaint(self,​ event):
 +        self.count = self.count + 1
 +        print self.count
 +
 +
 +app = wx.App()
 +PaintEvent(None,​ -1, '​paintevent.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +In our example we print the number of paint events generated into the console.
 +
 +
 +
 +
 +
 +
 +
 +=== KeyEvent ===
 +When we press a key on our keyboard, wx.KeyEvent is generated. ​ This event is sent to the widget that has currently focus.
 +
 +There are three different key handlers: ​
 +
 +  * wx.EVT_KEY_DOWN ​
 +  * wx.EVT_KEY_UP ​
 +  * wx.EVT_CHAR ​
 +
 +A common request is to close application,​ when Esc key is pressed.
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# keyevent.py
 +
 +import wx
 +
 +class KeyEvent(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        panel = wx.Panel(self,​ -1)
 +        panel.Bind(wx.EVT_KEY_DOWN,​ self.OnKeyDown)
 +        panel.SetFocus()
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +
 +    def OnKeyDown(self,​ event):
 +        keycode = event.GetKeyCode()
 +        if keycode == wx.WXK_ESCAPE:​
 +            ret  = wx.MessageBox('​Are you sure to quit?',​ '​Question', ​
 + wx.YES_NO | wx.NO_DEFAULT,​ self)
 +            if ret == wx.YES:
 +                self.Close()
 +        event.Skip()
 +
 +
 +app = wx.App()
 +KeyEvent(None,​ -1, '​keyevent.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 + ​keycode = event.GetKeyCode()
 +</​code>​
 +
 +
 +
 +
 +Here we get the key code of the pressed key.
 +
 +
 +
 +
 +<code python>
 + if keycode == wx.WXK_ESCAPE:​
 +</​code>​
 +
 +
 +
 +
 +We check the key code. The Esc key has //​wx.WXK_ESCAPE//​ code.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +</​html>​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== صناديق الحوار =====
 +
 +نوافذ(صناديق)الحوار هى جزء مهم فى التطبيقات الرسومية، الحوار هو محادثة بين شخصين او اكثر، هنا المحادثة (المستخدم والتطبيق) وسيلة لإيصال معلومة للتطبيق. يمكن استخدامها فى اضافة بيانات ، تعديلها، او التحكم فى اعدادات البرنامج.. الخ.
 +
 +يوجد نوعان (نافذة حوار معرفة مسبقا ، او واحدة اعدّت خصيصا) ​
 +
 +
 +
 +==== رسالة بسيطة ====
 +
 +صندوق الرسالة بيقدم معلومات قصيرة للمستخدم، على سبيل المثال برنامج حرق الإسطوانات.. بعد انتهاء عملية الحرق تظهر رسالة للمستخدم تعلمه بذلك.
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# message.py
 +
 +import wx
 +
 +class MessageDialog(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        wx.FutureCall(5000,​ self.ShowMessage)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def ShowMessage(self):​
 +        wx.MessageBox('​Download completed',​ '​Info'​)
 +
 +
 +app = wx.App()
 +MessageDialog(None,​ -1, '​MessageDialog'​)
 +app.MainLoop()
 +
 +</​code>​
 +
 +
 +<code python>
 +wx.FutureCall(5000,​ self.ShowMessage)
 +</​code>​
 +
 +wx.FutureCall تستدعى دالة بعد 5 ثوانى -القيمة معطاه بالملى ثانية-.
 +
 +
 +<code python>
 + def ShowMessage(self):​
 +     ​wx.MessageBox('​Download completed',​ '​Info'​)
 +</​code>​
 +
 +
 +wx.MessageBox يعرض صندوق صغير يشمل (نص الرسالة، عنوان الرسالة، وزر)
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​messagedialog.png }}
 +
 +
 +
 +
 +
 +
 +==== صناديق حوارية جاهزة ====
 +
 +تأتى لنا wxPython بعدة صناديق حوارية جاهزة لأكثر العمليات الشائعة (عرض رسالة، ادخال قيمة، فتح وحفظ ملفات.. الخ)
 +
 +
 +
 +
 +==== Message dialogs ====
 +
 +صناديق الرسائل الحوارية تستخدم لعرض رسائل للمستخدم وهى امرن من صناديق الرسائل البسيطة ونستطيع فيها ان نغير الأيكونات والازرار المعروضة عليها.
 +
 +
 +<code python>
 + ​wx.MessageDialog(wx.Window parent, string message, string caption=wx.MessageBoxCaptionStr, ​
 +  long style=wx.OK | wx.CANCEL | wx.CENTRE, wx.Point pos=(-1, -1))
 +</​code>​
 +
 +^  flag  ^  meaning ​ ^
 +|wx.OK| تعرض زر OK |
 +|wx.CANCEL| تعرض زر Cancel |
 +|wx.YES_NO| تعرض ازرار Yes, No |
 +|wx.YES_DEFAULT| تجعل الزر Yes هو الإفتراضى |
 +|wx.NO_DEFAULT| تجعل الزر No هو الإفتراضى |
 +|wx.ICON_EXCLAMATION| تعرض ايكون الإنذار |
 +|wx.ICON_ERROR| تعرض ايكون الخطأ |
 +|wx.ICON_HAND| مثل السابقة |
 +|wx.ICON_INFORMATION| تعرض ايكون معلومات |
 +|wx.ICON_QUESTION| تعرض ايكون سؤال |
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# messages.py
 +
 +import wx
 +
 +class Messages(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 150))
 +
 +        panel = wx.Panel(self,​ -1)
 +
 +        hbox = wx.BoxSizer()
 +        sizer = wx.GridSizer(2,​ 2, 2, 2)
 +
 +        btn1 = wx.Button(panel,​ -1, '​Info'​)
 +        btn2 = wx.Button(panel,​ -1, '​Error'​)
 +        btn3 = wx.Button(panel,​ -1, '​Question'​)
 +        btn4 = wx.Button(panel,​ -1, '​Alert'​)
 +
 +        sizer.AddMany([btn1,​ btn2, btn3, btn4])
 +
 +        hbox.Add(sizer,​ 0, wx.ALL, 15)
 +        panel.SetSizer(hbox)
 +
 +
 +        btn1.Bind(wx.EVT_BUTTON,​ self.ShowMessage1)
 +        btn2.Bind(wx.EVT_BUTTON,​ self.ShowMessage2)
 +        btn3.Bind(wx.EVT_BUTTON,​ self.ShowMessage3)
 +        btn4.Bind(wx.EVT_BUTTON,​ self.ShowMessage4)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def ShowMessage1(self,​ event):
 +        dial = wx.MessageDialog(None,​ '​Download completed',​ '​Info',​ wx.OK)
 +        dial.ShowModal()
 +
 +    def ShowMessage2(self,​ event):
 +        dial = wx.MessageDialog(None,​ 'Error loading file', '​Error',​ wx.OK | 
 +            wx.ICON_ERROR)
 +        dial.ShowModal()
 +
 +    def ShowMessage3(self,​ event):
 +        dial = wx.MessageDialog(None,​ 'Are you sure to quit?',​ '​Question', ​
 +            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
 +        dial.ShowModal()
 +
 +    def ShowMessage4(self,​ event):
 +        dial = wx.MessageDialog(None,​ '​Unallowed operation',​ '​Exclamation',​ wx.OK | 
 +            wx.ICON_EXCLAMATION)
 +        dial.ShowModal()
 +
 +app = wx.App()
 +Messages(None,​ -1, '​Messages'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +فى مثالنا انشئنا 4 ازرار ووضعناهم فى شبكة، كل منها يعرض صندوق حوارى مختلف.
 +
 +
 +
 +<code python>
 + dial = wx.MessageDialog(None,​ 'Error loading file', '​Error',​ wx.OK | 
 +     ​wx.ICON_ERROR)
 + ​dial.ShowModal()
 +</​code>​
 +
 +انشاء صندوق حوارى امر سهل. نحدد ان ال dialog ليس له اب وذلك بتمرير None ويليه سلسلتين نصيتين تحويان محتوى الرسالة وعنوان الصندوق.ونعرض زر OK وايكون الخطأ وذلك عن طريق wx.OK, wx.ICON_ERROR
 +
 +ولعرض الصندوق على الشاشة نستدعى الطريقة ShowModal
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​idialog.jpg |Info dialog}}
 +
 +{{ http://​zetcode.com/​wxpython/​images/​qdialog.jpg |Question dialog}}
 +
 +{{ http://​zetcode.com/​wxpython/​images/​adialog.jpg |Alert dialog}}
 +
 +{{ http://​zetcode.com/​wxpython/​images/​edialog.jpg |Error dialog}}
 +
 +
 +
 +
 +
 +
 +
 +
 +==== About dialog box ====
 +
 +
 +
 +
 +Almost every application has a typical about dialog box. It is usually placed in the Help menu. The purpose of this dialog is to give the user the basic information about the name and the version of the application. In the past, these dialogs used to be quite brief. These days most of these boxes provide additional information about the authors. They give credits to additional programmers or documentation writers. They also provide information about the application licence. These boxes can show the logo of the company or the application logo. Some of the more capable about boxes show animation. ​
 +wxPython has a special about dialog box starting from 2.8.x series. It is not rocket science to make such a dialog manually. But it makes a programmer'​s life easier.  ​
 +
 +
 +
 +
 +
 +
 +
 +The dialog box is located in the Misc module. In order to create an about dialog box we must create two objects. A //​wx.AboutDialogInfo//​ and a //​wx.AboutBox//​. ​
 +
 +
 +
 +
 +<code python>
 + ​wx.AboutDialogInfo()
 +</​code>​
 +
 +
 +
 +
 +We will call the following methods upon a //​wx.AboutDialogInfo//​ object in our example. These methods are self-exlanatory.
 +
 +
 +
 +
 +
 +
 +
 +
 +^  Method ​ ^  Description ​ ^
 +| ‪ SetName(string name) ‬ | set the name of the program |
 +| ‪ SetVersion(string version) ‬ | set the version of the program |
 +| ‪ SetDescription(string desc) ‬ | set the description of the program |
 +| ‪ SetCopyright(string copyright) ‬ | set the copyright fo the program |
 +| ‪ SetLicence(string licence) ‬ | set the licence of the program |
 +| ‪ SetIcon(wx.Icon icon) ‬ | set the icon to be show |
 +| ‪ SetWebSite(string URL) ‬ | set the website of the program |
 +| ‪ SetLicence(string licence) ‬ | set the licence of the program |
 +| ‪ AddDeveloper(string developer) ‬ | add a developer to the developer'​s list |
 +| ‪ AddDocWriter(string docwirter) ‬ | add a docwriter to the docwriter'​s list |
 +| ‪ AddArtist(string artist) ‬ | add an artist to the artist'​s list |
 +| ‪ AddTranslator(string developer) ‬ | add a developer to the translator'​s list |
 +
 +
 +
 +
 +
 +
 +
 +
 +The constructor of the //​wx.AboutBox//​ is as follows. It takes a //​wx.AboutDialogInfo//​ as a parameter.
 +
 +
 +
 +
 +<code python>
 + ​wx.AboutBox(wx.AboutDialogInfo info)
 +</​code>​
 +
 +
 +
 +
 +
 +
 +wxPython can display two kinds of About boxes. It depends on which platform we use and which methods we call. 
 +It can be a native dialog or a wxPython generic dialog. Windows native about dialog box cannot display custom icons, licence text nor the url's. If we omit these three fields, wx.Python will show a native dialog. Otherwise it will resort to a generic one. It is advised to provide licence information in a separate menu item, if we want to stay as native as possible. ​
 +GTK+ can show all these fields.  ​
 +
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# aboutbox.py
 +
 +import wx
 +
 +ID_ABOUT = 1
 +
 +class AboutDialogBox(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(260, 200))
 +
 +        menubar = wx.MenuBar()
 +        help = wx.Menu()
 +        help.Append(ID_ABOUT,​ '&​About'​)
 +        self.Bind(wx.EVT_MENU,​ self.OnAboutBox,​ id=ID_ABOUT)
 +        menubar.Append(help,​ '&​Help'​)
 +        self.SetMenuBar(menubar)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnAboutBox(self,​ event):
 +        description = """​File Hunter is an advanced file manager for the Unix operating ​
 +system. Features include powerful built-in editor, advanced search capabilities,​
 +powerful batch renaming, file comparison, extensive archive handling and more.
 +"""​
 +
 +        licence = """​File Hunter is free software; you can redistribute it and/or modify it 
 +under the terms of the GNU General Public License as published by the Free Software Foundation; ​
 +either version 2 of the License, or (at your option) any later version.
 +
 +File Hunter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; ​
 +without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  ​
 +See the GNU General Public License for more details. You should have received a copy of 
 +the GNU General Public License along with File Hunter; if not, write to 
 +the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 ​ USA"""​
 +
 +
 +        info = wx.AboutDialogInfo()
 +
 +        info.SetIcon(wx.Icon('​icons/​hunter.png',​ wx.BITMAP_TYPE_PNG))
 +        info.SetName('​File Hunter'​)
 +        info.SetVersion('​1.0'​)
 +        info.SetDescription(description)
 +        info.SetCopyright('​(C) 2007 jan bodnar'​)
 +        info.SetWebSite('​http://​www.zetcode.com'​)
 +        info.SetLicence(licence)
 +        info.AddDeveloper('​jan bodnar'​)
 +        info.AddDocWriter('​jan bodnar'​)
 +        info.AddArtist('​The Tango crew')
 + info.AddTranslator('​jan bodnar'​)
 +
 +        wx.AboutBox(info)
 +
 +
 +app = wx.App()
 +AboutDialogBox(None,​ -1, 'About dialog box')
 +app.MainLoop()
 +</​code>​
 +
 +<code python>
 +        description = """​File Hunter is an advanced file manager for the Unix operating ​
 +system. Features include powerful built-in editor, advanced search capabilities,​
 +powerful batch renaming, file comparison, extensive archive handling and more.
 +"""​
 +</​code>​
 +
 +
 +
 +It is not the best idea to put too much text into the code of the application. I don't want to make the example too complex, so I put all the text into the code. But in real world programs, the text should be placed separately inside a file. It helps us with the maintenace of our application. For example, if we want to translate our application to other languages. ​
 +
 +
 +
 +
 +<code python>
 + info = wx.AboutDialogInfo()
 +</​code>​
 +
 +
 +
 +The first thing to do is to create a //​wx.AboutDialogInfo//​ object. The constructor is empty. It does not taky 
 +any parameters. ​
 +
 +
 +
 +<code python>
 + ​info.SetIcon(wx.Icon('​icons/​hunter.png',​ wx.BITMAP_TYPE_PNG))
 + ​info.SetName('​File Hunter'​)
 + ​info.SetVersion('​1.0'​)
 + ​info.SetDescription(description)
 + ​info.SetCopyright('​(C) 2007 jan bodnar'​)
 + ​info.SetWebSite('​http://​www.zetcode.com'​)
 + ​info.SetLicence(licence)
 + ​info.AddDeveloper('​jan bodnar'​)
 + ​info.AddDocWriter('​jan bodnar'​)
 + ​info.AddArtist('​The Tango crew')
 + ​info.AddTranslator('​jan bodnar'​)
 +</​code>​
 +
 +
 +
 +
 +The next thing to do is to call all necessary methods upon the created //​wx.AboutDialogInfo//​ object. ​
 +
 +
 +
 +
 +<code python>
 + ​wx.AboutBox(info)
 +</​code>​
 +
 +
 +
 +
 +In the end we create a //​wx.AboutBox//​ widget. The only parameter it takes is the //​wx.AboutDialogInfo//​ object. ​
 +
 +
 +
 +
 +
 +
 +
 +And of course, if we want to have an animation or some other eye candy, we must implement our about dialog manually.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​aboutbox.png |About dialog box}}
 +
 +
 +
 +
 +
 +
 +==== A custom dialog ====
 +
 +
 +
 +
 +In the next example we create a custom dialog. An image editing application can change a color depth of a picture. ​
 +To provide this funcionality,​ we could create a suitable dialog. ​
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# colordepth.py
 +
 +import wx
 +
 +ID_DEPTH = 1
 +
 +class ChangeDepth(wx.Dialog):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Dialog.__init__(self,​ parent, id, title, size=(250, 210))
 +
 +        panel = wx.Panel(self,​ -1)
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +
 +        wx.StaticBox(panel,​ -1, '​Colors',​ (5, 5), (240, 150))
 +        wx.RadioButton(panel,​ -1, '256 Colors',​ (15, 30), style=wx.RB_GROUP)
 +        wx.RadioButton(panel,​ -1, '16 Colors',​ (15, 55))
 +        wx.RadioButton(panel,​ -1, '2 Colors',​ (15, 80))
 +        wx.RadioButton(panel,​ -1, '​Custom',​ (15, 105))
 +        wx.TextCtrl(panel,​ -1, '',​ (95, 105))
 +
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +        okButton = wx.Button(self,​ -1, '​Ok',​ size=(70, 30))
 +        closeButton = wx.Button(self,​ -1, '​Close',​ size=(70, 30))
 +        hbox.Add(okButton,​ 1)
 +        hbox.Add(closeButton,​ 1, wx.LEFT, 5)
 +
 +        vbox.Add(panel)
 +        vbox.Add(hbox,​ 1, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 10)
 +
 +        self.SetSizer(vbox)
 + 
 +
 +class ColorDepth(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(350, 220))
 +
 +        toolbar = self.CreateToolBar()
 +        toolbar.AddLabelTool(ID_DEPTH,​ '',​ wx.Bitmap('​icons/​color.png'​))
 +
 +        self.Bind(wx.EVT_TOOL,​ self.OnChangeDepth,​ id=ID_DEPTH)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnChangeDepth(self,​ event):
 +        chgdep = ChangeDepth(None,​ -1, '​Change Color Depth'​)
 +        chgdep.ShowModal()
 +        chgdep.Destroy()
 +
 +app = wx.App()
 +ColorDepth(None,​ -1, ''​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +<code python>
 + class ChangeDepth(wx.Dialog):​
 +     def __init__(self,​ parent, id, title):
 +         ​wx.Dialog.__init__(self,​ parent, id, title, size=(250, 210))
 +</​code>​
 +
 +
 +
 +
 +In our code example we create a custom ChangeDepth dialog. We inherit from a //​wx.Dialog//​ widget.
 +
 +
 +
 +
 +<code python>
 + ​chgdep = ChangeDepth(None,​ -1, '​Change Color Depth'​)
 + ​chgdep.ShowModal()
 + ​chgdep.Destroy()
 +</​code>​
 +
 +
 +
 +
 +We instantiate a ChangeDepth class. Then we call the //​ShowModal()//​ dialog. We must not forget to 
 +destroy our dialog. Notice the visual difference between the dialog and the top level window. The dialog in the following figure has been activated. We cannot work with the toplevel window until the dialog is destroyed. ​
 +There is a clear difference in the titlebar of the windows.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​colordepth1.png }}
 + {{ http://​zetcode.com/​wxpython/​images/​colordepth2.png }}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +</​html>​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Core Widgets =====
 +
 +
 +
 +
 +
 +
 +
 +In this section, we will introduce basic widgets in wxPython. Each widget will have a small code example. ​
 +
 +
 +
 +
 +  * wx.Button
 +  * wx.ToggleButton
 +  * wx.BitmapButton
 +  * wx.StaticLine
 +  * wx.StaticText
 +  * wx.StaticBox
 +  * wx.ComboBox
 +  * wx.CheckBox
 +  * wx.StatusBar
 +  * wx.RadioButton
 +  * wx.Gauge
 +  * wx.Slider
 +  * wx.ListBox
 +  * wx.SpinCtrl
 +  * wx.SplitterWindow
 +  * wx.ScrolledWindow
 +  * wx.Notebook
 +  * wx.Panel
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​buttons.png }}
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# buttons.py
 +
 +import wx
 +import random
 +
 +APP_SIZE_X = 300
 +APP_SIZE_Y = 200
 +
 +class MyButtons(wx.Dialog):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Dialog.__init__(self,​ parent, id, title, size=(APP_SIZE_X,​ APP_SIZE_Y))
 +
 +        wx.Button(self,​ 1, '​Close',​ (50, 130))
 +        wx.Button(self,​ 2, '​Random Move', (150, 130), (110, -1))
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnClose,​ id=1)
 +        self.Bind(wx.EVT_BUTTON,​ self.OnRandomMove,​ id=2)
 +
 +        self.Centre()
 +        self.ShowModal()
 +        self.Destroy()
 +
 +    def OnClose(self,​ event):
 +        self.Close(True)
 +
 +    def OnRandomMove(self,​ event):
 +        screensize = wx.GetDisplaySize()
 +        randx = random.randrange(0,​ screensize.x - APP_SIZE_X)
 +        randy = random.randrange(0,​ screensize.y - APP_SIZE_Y)
 +        self.Move((randx,​ randy))
 +
 +app = wx.App(0)
 +MyButtons(None,​ -1, '​buttons.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​togglebuttons.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# togglebuttons.py
 +
 +import wx
 +
 +class ToggleButtons(wx.Dialog):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Dialog.__init__(self,​ parent, id, title, size=(300, 200))
 +
 +        self.colour = wx.Colour(0,​ 0, 0)
 +
 +        wx.ToggleButton(self,​ 1, '​red',​ (20, 25))
 +        wx.ToggleButton(self,​ 2, '​green',​ (20, 60))
 +        wx.ToggleButton(self,​ 3, '​blue',​ (20, 100))
 +
 +        self.panel ​ = wx.Panel(self,​ -1, (150, 20), (110, 110), style=wx.SUNKEN_BORDER)
 +        self.panel.SetBackgroundColour(self.colour)
 +
 +        self.Bind(wx.EVT_TOGGLEBUTTON,​ self.ToggleRed,​ id=1)
 +        self.Bind(wx.EVT_TOGGLEBUTTON,​ self.ToggleGreen,​ id=2)
 +        self.Bind(wx.EVT_TOGGLEBUTTON,​ self.ToggleBlue,​ id=3)
 +
 +        self.Centre()
 +        self.ShowModal()
 +        self.Destroy()
 +
 +    def ToggleRed(self,​ event):
 +        green = self.colour.Green()
 +        blue = self.colour.Blue()
 +        if  self.colour.Red():​
 +            self.colour.Set(0,​ green, blue)
 +        else:
 +            self.colour.Set(255,​ green, blue)
 +        self.panel.SetBackgroundColour(self.colour)
 +
 +    def ToggleGreen(self,​ event):
 +        red = self.colour.Red()
 +        blue = self.colour.Blue()
 +        if  self.colour.Green():​
 +            self.colour.Set(red,​ 0, blue)
 +        else:
 +            self.colour.Set(red,​ 255, blue)
 +        self.panel.SetBackgroundColour(self.colour)
 +
 +    def ToggleBlue(self,​ event):
 +        red = self.colour.Red()
 +        green = self.colour.Green()
 +        if  self.colour.Blue():​
 +            self.colour.Set(red,​ green, 0)
 +        else:
 +            self.colour.Set(red,​ green, 255)
 +        self.panel.SetBackgroundColour(self.colour)
 +
 +
 +app = wx.App()
 +ToggleButtons(None,​ -1, '​togglebuttons.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +{{ http://​zetcode.com/​wxpython/​images/​player.jpg }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# player.py
 +
 +import wx
 +
 +class Player(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(350, 300))
 +        panel = wx.Panel(self,​ -1)
 +
 +        pnl1 = wx.Panel(self,​ -1)
 +        pnl1.SetBackgroundColour(wx.BLACK)
 +        pnl2 = wx.Panel(self,​ -1 )
 +
 +        menubar = wx.MenuBar()
 +        file = wx.Menu()
 +        play = wx.Menu()
 +        view = wx.Menu()
 +        tools = wx.Menu()
 +        favorites = wx.Menu()
 +        help = wx.Menu()
 +        ​
 +        file.Append(101,​ '&​quit',​ 'Quit application'​)
 +
 +        menubar.Append(file,​ '&​File'​)
 +        menubar.Append(play,​ '&​Play'​)
 +        menubar.Append(view,​ '&​View'​)
 +        menubar.Append(tools,​ '&​Tools'​)
 +        menubar.Append(favorites,​ '​F&​avorites'​)
 +        menubar.Append(help,​ '&​Help'​)
 +
 +        self.SetMenuBar(menubar)
 +
 +        slider1 = wx.Slider(pnl2,​ -1, 0, 0, 1000)
 +        pause = wx.BitmapButton(pnl2,​ -1, wx.Bitmap('​icons/​stock_media-pause.png'​))
 +        play  = wx.BitmapButton(pnl2,​ -1, wx.Bitmap('​icons/​stock_media-play.png'​))
 +        next  = wx.BitmapButton(pnl2,​ -1, wx.Bitmap('​icons/​stock_media-next.png'​))
 +        prev  = wx.BitmapButton(pnl2,​ -1, wx.Bitmap('​icons/​stock_media-prev.png'​))
 +        volume = wx.BitmapButton(pnl2,​ -1, wx.Bitmap('​icons/​volume.png'​))
 +        slider2 = wx.Slider(pnl2,​ -1, 0, 0, 100, size=(120, -1))
 +
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
 +        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        hbox1.Add(slider1,​ 1)
 +        hbox2.Add(pause)
 +        hbox2.Add(play,​ flag=wx.RIGHT,​ border=5)
 +        hbox2.Add(next,​ flag=wx.LEFT,​ border=5)
 +        hbox2.Add(prev)
 +        hbox2.Add((-1,​ -1), 1)
 +        hbox2.Add(volume)
 +        hbox2.Add(slider2,​ flag=wx.TOP | wx.LEFT, border=5)
 +
 +        vbox.Add(hbox1,​ flag=wx.EXPAND | wx.BOTTOM, border=10)
 +        vbox.Add(hbox2,​ 1, wx.EXPAND)
 +        pnl2.SetSizer(vbox)
 +
 +        sizer = wx.BoxSizer(wx.VERTICAL)
 +        sizer.Add(pnl1,​ 1, flag=wx.EXPAND)
 +        sizer.Add(pnl2,​ flag=wx.EXPAND | wx.BOTTOM | wx.TOP, border=10)
 +
 +        self.SetMinSize((350,​ 300))
 +        self.CreateStatusBar()
 +        self.SetSizer(sizer)
 +
 +        self.Centre()
 +        self.Show()
 +
 +
 +app = wx.App()
 +Player(None,​ -1, '​Player'​)
 +app.MainLoop()
 +
 +</​code>​
 +
 +<code python>
 + pause = wx.BitmapButton(pnl2,​ -1, wx.Bitmap('​icons/​stock_media-pause.png'​))
 +</​code>​
 +
 +
 +
 +
 +The creation of the //​wx.BitmapButton//​ is self explanatory.
 +
 +
 +
 +
 +
 +<code python>
 + ​hbox2.Add(prev)
 + ​hbox2.Add((-1,​ -1), 1)
 + ​hbox2.Add(volume)
 +</​code>​
 +
 +
 +
 +
 +Here we put some space between the previous button and the volume button. The proportion is set to 1. This means, that the space will grow, when we resize the window.
 +
 +
 +
 +
 +<code python>
 + ​self.SetMinSize((350,​ 300))
 +</​code>​
 +
 +
 +
 +
 + Here we set the minimum size of the player. It does not make much sense to shrink the window below some value.
 +
 +
 +
 +
 +
 +=== wx.StaticLine ===
 +
 +
 +
 +This widget displays a simple line on the window. It can be horizontal or vertical. ​
 +centraleurope.py script displays central european countries and their population. The wx.StatLine makes it look more visually attractive.
 +
 +wx.StaticLine styles ​
 +
 +  * wx.LI_HORIZONTAL
 +  * wx.LI_VERTICAL
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​centraleurope.png }}
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# centraleurope.py
 +
 +import wx
 +
 +class CentralEurope(wx.Dialog):​
 +    def __init__ (self, parent, ID, title):
 +        wx.Dialog.__init__(self,​ parent, ID, title, size=(360, 370))
 +
 +        font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)
 +        heading = wx.StaticText(self,​ -1, 'The Central Europe',​ (130, 15))
 +        heading.SetFont(font)
 +
 +        wx.StaticLine(self,​ -1, (25, 50), (300,1))
 +
 +        wx.StaticText(self,​ -1, '​Slovakia',​ (25, 80))
 +        wx.StaticText(self,​ -1, '​Hungary',​ (25, 100))
 +        wx.StaticText(self,​ -1, '​Poland',​ (25, 120))
 +        wx.StaticText(self,​ -1, 'Czech Republic',​ (25, 140))
 +        wx.StaticText(self,​ -1, '​Germany',​ (25, 160))
 +        wx.StaticText(self,​ -1, '​Slovenia',​ (25, 180))
 +        wx.StaticText(self,​ -1, '​Austria',​ (25, 200))
 +        wx.StaticText(self,​ -1, '​Switzerland',​ (25, 220))
 +
 +        wx.StaticText(self,​ -1, '5 379 000', (250, 80))
 +        wx.StaticText(self,​ -1, '10 084 000', (250, 100))
 +        wx.StaticText(self,​ -1, '38 635 000', (250, 120))
 +        wx.StaticText(self,​ -1, '10 240 000', (250, 140))
 +        wx.StaticText(self,​ -1, '82 443 000', (250, 160))
 +        wx.StaticText(self,​ -1, '2 001 000', (250, 180))
 +        wx.StaticText(self,​ -1, '8 032 000', (250, 200))
 +        wx.StaticText(self,​ -1, '7 288 000', (250, 220))
 +
 +        wx.StaticLine(self,​ -1, (25, 260), (300,1))
 +
 +        sum = wx.StaticText(self,​ -1, '164 102 000', (240, 280))
 +        sum_font = sum.GetFont()
 +        sum_font.SetWeight(wx.BOLD)
 +        sum.SetFont(sum_font)
 +
 +        wx.Button(self,​ 1, '​Ok',​ (140, 310), (60, 30))
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnOk, id=1)
 +
 +        self.Centre()
 +        self.ShowModal()
 +        self.Destroy()
 +
 +    def OnOk(self, event):
 +        self.Close()
 +
 +app = wx.App()
 +CentralEurope(None,​ -1, '​centraleurope.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​statictext.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# statictext.py
 +
 +import wx
 +
 +class StaticText(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        lyrics1 = '''​I'​m giving up the ghost of love
 +in the shadows cast on devotion
 +She is the one that I adore
 +creed of my silent suffocation
 +Break this bittersweet spell on me
 +lost in the arms of destiny'''​
 +
 +        lyrics2 = '''​There is something in the way
 +You're always somewhere else
 +Feelings have deserted me
 +To a point of no return
 +I don't believe in God
 +But I pray for you'''​
 +
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        panel = wx.Panel(self,​ -1)
 +        st1 = wx.StaticText(panel,​ -1, lyrics1, style=wx.ALIGN_CENTRE)
 +        st2 = wx.StaticText(panel,​ -1, lyrics2, style=wx.ALIGN_CENTRE)
 +        vbox.Add(st1,​ 1, wx.EXPAND |  wx.TOP | wx.BOTTOM, 15)
 +        vbox.Add(st2,​ 1, wx.EXPAND |  wx.TOP | wx.BOTTOM, 15)
 +        panel.SetSizer(vbox)
 +        self.Centre()
 +        self.Show(True)
 +
 +
 +app = wx.App()
 +StaticText(None,​ -1, '​statixtext.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​staticbox.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# staticbox.py
 +
 +import wx
 +
 +class StaticBox(wx.Dialog):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Dialog.__init__(self,​ parent, id, title, size=(250, 230))
 +
 +        wx.StaticBox(self,​ -1, '​Personal Info', (5, 5), size=(240, 170))
 +        wx.CheckBox(self,​ -1 ,'​Male',​ (15, 30))
 +        wx.CheckBox(self,​ -1 ,'​Married',​ (15, 55))
 +        wx.StaticText(self,​ -1, '​Age',​ (15, 95))
 +        wx.SpinCtrl(self,​ -1, '​1',​ (55, 90), (60, -1), min=1, max=120)
 +        wx.Button(self,​ 1, '​Ok',​ (90, 185), (60, -1))
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnClose,​ id=1)
 +
 +        self.Centre()
 +        self.ShowModal()
 +        self.Destroy()
 +
 +    def OnClose(self,​ event):
 +        self.Close()
 +
 +app = wx.App()
 +StaticBox(None,​ -1, '​staticbox.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +=== wx.ComboBox ===
 +
 +
 +
 +wx.ComboBox is a combination of a single line text field, a button with a down arrow image and a listbox. When you press the button, a listbox appears. User can select only one option from the supplied string list. 
 +
 +wx.ComboBox has the following constructor: ​
 +<code python>
 + ​wx.ComboBox(int id, string value='',​ wx.Point pos=wx.DefaultPosition,​ wx.Size size=wx.DefaultSize,​
 +    wx.List choices=wx.EmptyList,​ int style=0, wx.Validator validator=wx.DefaultValidator,​
 +    string name=wx.ComboBoxNameStr)
 +</​code>​
 +
 +
 +
 +
 +wx.ComboBox styles
 +
 +  * wx.CB_DROPDOWN
 +  * wx.CB_READONLY ​
 +  * wx.CB_SORT
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​combobox.png }}
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# combobox.py
 +
 +import wx
 +
 +class ComboBox(wx.Dialog):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Dialog.__init__(self,​ parent, id, title, size=(250, 270))
 +
 +        panel = wx.Panel(self,​ -1, (75, 20), (100, 127), style=wx.SUNKEN_BORDER)
 +        self.picture = wx.StaticBitmap(panel)
 +        panel.SetBackgroundColour(wx.WHITE)
 +
 +        self.images = ['​tolstoy.jpg',​ '​feuchtwanger.jpg',​ '​balzac.jpg',​ '​pasternak.jpg',​
 +                    '​galsworthy.jpg',​ '​wolfe.jpg',​ '​zweig.jpg'​]
 +        authors = ['Leo Tolstoy',​ 'Lion Feuchtwanger',​ '​Honore de Balzac',​
 + '​Boris Pasternak',​ 'John Galsworthy',​ 'Tom Wolfe',​ '​Stefan Zweig'​]
 +
 +        wx.ComboBox(self,​ -1, pos=(50, 170), size=(150, -1), choices=authors, ​
 + style=wx.CB_READONLY)
 +        wx.Button(self,​ 1, '​Close',​ (80, 220))
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnClose,​ id=1)
 +        self.Bind(wx.EVT_COMBOBOX,​ self.OnSelect)
 +
 +        self.Centre()
 +        self.ShowModal()
 +        self.Destroy()
 +
 +    def OnClose(self,​ event):
 +        self.Close()
 +
 +    def OnSelect(self,​ event):
 +        item = event.GetSelection()
 +        self.picture.SetFocus()
 +        self.picture.SetBitmap(wx.Bitmap('​images/'​ + self.images[item]))
 +
 +
 +app = wx.App()
 +ComboBox(None,​ -1, '​combobox.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​checkbox.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# checkbox.py
 +
 +import wx
 +
 +class CheckBox(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 170))
 +
 +        panel = wx.Panel(self,​ -1)
 +        self.cb = wx.CheckBox(panel,​ -1, 'Show Title',​ (10, 10))
 +        self.cb.SetValue(True)
 +
 +        wx.EVT_CHECKBOX(self,​ self.cb.GetId(),​ self.ShowTitle)
 +
 +        self.Show()
 +        self.Centre()
 +
 +    def ShowTitle(self,​ event):
 +        if self.cb.GetValue():​
 +            self.SetTitle('​checkbox.py'​)
 +        else: self.SetTitle(''​)
 +
 +
 +app = wx.App()
 +CheckBox(None,​ -1, '​checkbox.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​statusbar.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# statusbar.py
 +
 +import wx
 +
 +class Statusbar(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 200), 
 + style=wx.CAPTION | wx.SYSTEM_MENU | wx.CLOSE_BOX)
 +
 +        panel = wx.Panel(self,​ 1)
 +
 +        button = wx.Button(panel,​ 2, '​Button',​ (20, 20))
 +        text = wx.CheckBox(panel,​ 3, '​CheckBox',​ (20, 90))
 +        combo = wx.ComboBox(panel,​ 4, '',​ (120, 22))
 +        slider = wx.Slider(panel,​ 5, 6, 1, 10, (120, 90), (110, -1))
 +
 +        panel.Bind(wx.EVT_ENTER_WINDOW,​ self.EnterPanel,​ id=1)
 +        button.Bind(wx.EVT_ENTER_WINDOW,​ self.EnterButton,​ id=2)
 +        text.Bind(wx.EVT_ENTER_WINDOW,​ self.EnterText,​ id=3)
 +        combo.Bind(wx.EVT_ENTER_WINDOW,​ self.EnterCombo,​ id=4)
 +        slider.Bind(wx.EVT_ENTER_WINDOW,​ self.EnterSlider,​ id=5)
 +
 +        self.sb = self.CreateStatusBar()
 +        self.SetMaxSize((250,​ 200))
 +        self.SetMinSize((250,​ 200))
 +        self.Show(True)
 +        self.Centre()
 +
 +    def EnterButton(self,​ event):
 +        self.sb.SetStatusText('​Button widget'​)
 +        event.Skip()
 +
 +    def EnterPanel(self,​ event):
 +        self.sb.SetStatusText('​Panel widget'​)
 +        event.Skip()
 +
 +    def EnterText(self,​ event):
 +        self.sb.SetStatusText('​CheckBox widget'​)
 +        event.Skip()
 +
 +    def EnterCombo(self,​ event):
 +        self.sb.SetStatusText('​ComboBox widget'​)
 +        event.Skip()
 +
 +    def EnterSlider(self,​ event):
 +        self.sb.SetStatusText('​Slider widget'​)
 +        event.Skip()
 +
 +app = wx.App()
 +Statusbar(None,​ -1, '​statusbar.py'​)
 +app.MainLoop()
 +
 +</​code>​
 +
 +=== wx.RadioButton ===
 +
 +
 +
 +
 +wx.RadioButton ​ is a widget that allows the user to select a single exclusive choice from a group of options. A group of radio buttons is defined by having the first RadioButton in the group contain the wx.RB_GROUP style. All other RadioButtons defined after the first RadioButton with this style flag is set will be added to the function group of the first RadioButton. Declaring another RadioButton with the wx.RB_GROUP flag will start a new radio button group. ​
 +
 +wx.RadioButton Styles ​
 +
 +  * wx.RB_GROUP
 +  * wx.RB_SINGLE ​
 +  * wx.CB_SORT
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​radiobuttons.png }}
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# radiobuttons.py
 +
 +import wx
 +
 +class RadioButtons(wx.Frame):​
 +    def __init__(self,​ parent, id, title, size=(210, 150)):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +        panel = wx.Panel(self,​ -1)
 +        self.rb1 = wx.RadioButton(panel,​ -1, 'Value A', (10, 10), style=wx.RB_GROUP)
 +        self.rb2 = wx.RadioButton(panel,​ -1, 'Value B', (10, 30))
 +        self.rb3 = wx.RadioButton(panel,​ -1, 'Value C', (10, 50))
 +
 +        self.Bind(wx.EVT_RADIOBUTTON,​ self.SetVal,​ id=self.rb1.GetId())
 +        self.Bind(wx.EVT_RADIOBUTTON,​ self.SetVal,​ id=self.rb2.GetId())
 +        self.Bind(wx.EVT_RADIOBUTTON,​ self.SetVal,​ id=self.rb3.GetId())
 +
 +        self.statusbar = self.CreateStatusBar(3)
 +        self.SetVal(True)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def SetVal(self,​ event):
 +        state1 = str(self.rb1.GetValue())
 +        state2 = str(self.rb2.GetValue())
 +        state3 = str(self.rb3.GetValue())
 +
 +        self.statusbar.SetStatusText(state1,​ 0)
 +        self.statusbar.SetStatusText(state2,​ 1)
 +        self.statusbar.SetStatusText(state3,​ 2)
 +
 +
 +app = wx.App()
 +RadioButtons(None,​ -1, '​radiobuttons.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​gauge.png }}
 +
 +
 +<code python>
 +# gauge.py
 +
 +import wx
 +
 +class Gauge(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(300, 200))
 +
 +        self.timer = wx.Timer(self,​ 1)
 +        self.count = 0
 +
 +        self.Bind(wx.EVT_TIMER,​ self.OnTimer,​ self.timer)
 +
 +        panel = wx.Panel(self,​ -1)
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
 +        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
 +        hbox3 = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        self.gauge = wx.Gauge(panel,​ -1, 50, size=(250, 25))
 +        self.btn1 = wx.Button(panel,​ wx.ID_OK)
 +        self.btn2 = wx.Button(panel,​ wx.ID_STOP)
 +        self.text = wx.StaticText(panel,​ -1, 'Task to be done')
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnOk, self.btn1)
 +        self.Bind(wx.EVT_BUTTON,​ self.OnStop,​ self.btn2)
 +
 +        hbox1.Add(self.gauge,​ 1, wx.ALIGN_CENTRE)
 +        hbox2.Add(self.btn1,​ 1, wx.RIGHT, 10)
 +        hbox2.Add(self.btn2,​ 1)
 +        hbox3.Add(self.text,​ 1)
 +        vbox.Add((0,​ 30), 0)
 +        vbox.Add(hbox1,​ 0, wx.ALIGN_CENTRE)
 +        vbox.Add((0,​ 20), 0)
 +        vbox.Add(hbox2,​ 1, wx.ALIGN_CENTRE)
 +        vbox.Add(hbox3,​ 1, wx.ALIGN_CENTRE)
 +
 +        panel.SetSizer(vbox)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnOk(self, event):
 +        if self.count >= 50:
 +            return
 +        self.timer.Start(100)
 +        self.text.SetLabel('​Task in Progress'​)
 +
 +    def OnStop(self,​ event):
 +        if self.count == 0 or self.count >= 50 or not self.timer.IsRunning():​
 +            return
 +        self.timer.Stop()
 +     self.text.SetLabel('​Task Interrupted'​)
 +        wx.Bell()
 +
 +    def OnTimer(self,​ event):
 +        self.count = self.count +1
 +        self.gauge.SetValue(self.count)
 +        if self.count == 50:
 +            self.timer.Stop()
 +            self.text.SetLabel('​Task Completed'​)
 +
 +app = wx.App()
 +Gauge(None, -1, '​gauge.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​slider.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# slider.py
 +
 +import wx
 +
 +class Slider(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(300, 150))
 +
 +        panel = wx.Panel(self,​ -1)
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        self.sld = wx.Slider(panel,​ -1, 200, 150, 500, (-1, -1), (250, -1), 
 + wx.SL_AUTOTICKS | wx.SL_HORIZONTAL | wx.SL_LABELS)
 +        btn1 = wx.Button(panel,​ 1, '​Adjust'​)
 +        btn2 = wx.Button(panel,​ 2,  '​Close'​)
 +
 +        wx.EVT_BUTTON(self,​ 1, self.OnOk)
 +        wx.EVT_BUTTON(self,​ 2, self.OnClose)
 +
 +        vbox.Add(self.sld,​ 1, wx.ALIGN_CENTRE)
 +        hbox.Add(btn1,​ 1, wx.RIGHT, 10)
 +        hbox.Add(btn2,​ 1)
 +        vbox.Add(hbox,​ 0, wx.ALIGN_CENTRE | wx.ALL, 20)
 +        panel.SetSizer(vbox)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnOk(self, event):
 +        val = self.sld.GetValue()
 +        self.SetSize((val*2,​ val))
 +
 +    def OnClose(self,​ event):
 +        self.Close()
 +
 +app = wx.App()
 +Slider(None,​ -1, '​slider.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +=== wx.ListBox ===
 +
 +
 +
 +wx.Listbox is a widget that consists of a scrolling box and a list of items. User can select one or more items from that list. It depends on whether it is created as a single or multiple selection box. Selected items are marked.
 +
 +
 +
 +
 +
 +
 +listbox.py example consists of four different widgets. wx.Listbox, wx.TextCtrl,​ wx.StaticText and wx.Button. Widgets are organized with sizer-s. wx.Listbox has a list of six different world times. These abbreviations are explained in the second wx.TextCtrl. Current time is displayed in the wx.StaticText widget. wx.Timer widget is used to update the time every 100 miliseconds.
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​listbox.png }}
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# listbox.py
 +
 +import wx
 +from time import *
 +
 +class Listbox(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(550, 350))
 +
 +        zone_list = ['​CET',​ '​GMT',​ '​MSK',​ '​EST',​ '​PST',​ '​EDT'​]
 +
 +        self.full_list = {
 +            '​CET':​ '​Central European Time',
 +            '​GMT':​ '​Greenwich Mean Time',
 +            '​MSK':​ '​Moscow Time',
 +            '​EST':​ '​Eastern Standard Time',
 +            '​PST':​ '​Pacific Standard Time',
 +            '​EDT':​ '​Eastern Daylight Time'
 +        }
 +
 +        self.time_diff = {
 +            '​CET'​ : 1,
 +            '​GMT'​ : 0,
 +            '​MSK':​ 3,
 +            '​EST':​ -5,
 +            '​PST':​ -8,
 +            '​EDT':​ -4
 +        }
 +
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
 +        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
 +        hbox3 = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        self.timer = wx.Timer(self,​ 1)
 +        self.diff = 0
 +
 +        panel = wx.Panel(self,​ -1)
 +
 +        self.time_zones = wx.ListBox(panel,​ 26, (-1, -1), (170, 130), 
 + zone_list,​ wx.LB_SINGLE)
 +        self.time_zones.SetSelection(0)
 +        self.text = wx.TextCtrl(panel,​ -1, '​Central European Time', ​
 + size=(200,​ 130), style=wx.TE_MULTILINE)
 +        self.time = wx.StaticText(panel,​ -1, ''​)
 +        btn = wx.Button(panel,​ wx.ID_CLOSE,​ '​Close'​)
 +        hbox1.Add(self.time_zones,​ 0, wx.TOP, 40)
 +        hbox1.Add(self.text,​ 1, wx.LEFT | wx.TOP, 40)
 +        hbox2.Add(self.time,​ 1, wx.ALIGN_CENTRE)
 +        hbox3.Add(btn,​ 0, wx.ALIGN_CENTRE)
 +        vbox.Add(hbox1,​ 0, wx.ALIGN_CENTRE)
 +        vbox.Add(hbox2,​ 1, wx.ALIGN_CENTRE)
 +        vbox.Add(hbox3,​ 1, wx.ALIGN_CENTRE)
 +
 +        panel.SetSizer(vbox)
 +
 +        self.timer.Start(100)
 +
 +        wx.EVT_BUTTON(self,​ wx.ID_CLOSE,​ self.OnClose)
 +        wx.EVT_LISTBOX(self,​ 26, self.OnSelect)
 +        wx.EVT_TIMER(self,​ 1, self.OnTimer)
 +
 +        self.Show(True)
 +        self.Centre()
 +
 +    def OnClose(self,​ event):
 +        self.Close()
 +
 +    def OnSelect(self,​ event):
 +        index = event.GetSelection()
 +        time_zone = self.time_zones.GetString(index)
 +        self.diff = self.time_diff[time_zone]
 +        self.text.SetValue(self.full_list[time_zone])
 +
 +    def OnTimer(self,​ event):
 +        ct = gmtime()
 +        print_time = (ct[0], ct[1], ct[2], ct[3]+self.diff, ​
 + ct[4], ct[5], ct[6], ct[7], -1)
 +        self.time.SetLabel(strftime("​%H:​%M:​%S",​ print_time))
 +
 +
 +app = wx.App()
 +Listbox(None,​ -1, '​listbox.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​spinctrl.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# spinctrl.py
 +
 +import wx
 +
 +class Converter(wx.Dialog):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Dialog.__init__(self,​ parent, id, title, size=(350, 310))
 +
 +        wx.StaticText(self,​ -1, '​Convert Fahrenheit temperature to Celsius',​ (20,20))
 +        wx.StaticText(self,​ -1, '​Fahrenheit:​ ', (20, 80))
 +        wx.StaticText(self,​ -1, '​Celsius:​ ', (20, 150))
 +        self.celsius =  wx.StaticText(self,​ -1, '',​ (150, 150))
 +        self.sc = wx.SpinCtrl(self,​ -1, '', ​ (150, 75), (60, -1))
 +        self.sc.SetRange(-459,​ 1000)
 +        self.sc.SetValue(0)
 +        compute_btn = wx.Button(self,​ 1, '​Compute',​ (70, 250))
 +        compute_btn.SetFocus()
 +        clear_btn = wx.Button(self,​ 2, '​Close',​ (185, 250))
 +
 +        wx.EVT_BUTTON(self,​ 1, self.OnCompute)
 +        wx.EVT_BUTTON(self,​ 2, self.OnClose)
 +        wx.EVT_CLOSE(self,​ self.OnClose)
 +
 +        self.Centre()
 +        self.ShowModal()
 +        self.Destroy()
 +
 +    def OnCompute(self,​ event):
 +        fahr = self.sc.GetValue()
 +        cels = round((fahr-32)*5/​9.0,​ 2)
 +        self.celsius.SetLabel(str(cels))
 +
 +    def OnClose(self,​ event):
 +        self.Destroy()
 +
 +app = wx.App()
 +Converter(None,​ -1, '​Converter'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​splitterwindow.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# splitterwindow.py
 +
 +import wx
 +
 +class Splitterwindow(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(350, 300))
 +
 +        quote = '''​Whether you think that you can, or that you can't, you are
 +usually right'''​
 +
 +        splitter = wx.SplitterWindow(self,​ -1)
 +        panel1 = wx.Panel(splitter,​ -1)
 +        wx.StaticText(panel1,​ -1, quote, (100, 100), style=wx.ALIGN_CENTRE)
 +
 +        panel1.SetBackgroundColour(wx.LIGHT_GREY)
 +        panel2 = wx.Panel(splitter,​ -1)
 +        panel2.SetBackgroundColour(wx.WHITE)
 +        splitter.SplitVertically(panel1,​ panel2)
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +Splitterwindow(None,​ -1, '​splitterwindow.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +=== wx.ScrolledWindow ===
 +
 +
 +
 +This is one of the container widgets. It can be useful, when we have a larger area than a window can display. In our example, we demonstrate such a case. We place a large image into our window. When the window is smaller than our image, Scrollbars are displayed automatically.
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​scrolledwindow.jpg }}
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# scrolledwindow.py
 +
 +import wx
 +
 +class ScrolledWindow(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(500, 400))
 +
 +        sw = wx.ScrolledWindow(self)
 +        bmp = wx.Image('​images/​aliens.jpg',​wx.BITMAP_TYPE_JPEG).ConvertToBitmap()
 +        wx.StaticBitmap(sw,​ -1, bmp)
 +        sw.SetScrollbars(20,​ 20, 55, 40)
 +        sw.Scroll(50,​10)
 +        self.Centre()
 +        self.Show()
 +
 +app = wx.App()
 +ScrolledWindow(None,​ -1, '​Aliens'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​notebook.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# notebook.py
 +
 +import wx
 +import wx.lib.sheet as sheet
 +
 +
 +class MySheet(sheet.CSheet):​
 +    def __init__(self,​ parent):
 +        sheet.CSheet.__init__(self,​ parent)
 +        self.SetNumberRows(50)
 +        self.SetNumberCols(50)
 +
 +class Notebook(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(600, 500))
 +        menubar = wx.MenuBar()
 +        file = wx.Menu()
 +        file.Append(101,​ '​Quit',​ ''​ )
 +        menubar.Append(file,​ '&​File'​)
 +        self.SetMenuBar(menubar)
 +
 +        wx.EVT_MENU(self,​ 101, self.OnQuit)
 +
 +        nb = wx.Notebook(self,​ -1, style=wx.NB_BOTTOM)
 +        self.sheet1 = MySheet(nb)
 +        self.sheet2 = MySheet(nb)
 +        self.sheet3 = MySheet(nb)
 +
 +        nb.AddPage(self.sheet1,​ '​Sheet1'​)
 +        nb.AddPage(self.sheet2,​ '​Sheet2'​)
 +        nb.AddPage(self.sheet3,​ '​Sheet3'​)
 +
 +        self.sheet1.SetFocus()
 +        self.StatusBar()
 +        self.Centre()
 +        self.Show()
 +
 +    def StatusBar(self):​
 +        self.statusbar = self.CreateStatusBar()
 +
 +    def OnQuit(self,​ event):
 +        self.Close()
 +
 +app = wx.App()
 +Notebook(None,​ -1, '​notebook.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​panels.png }}
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# panels.py
 +
 +import wx
 +
 +
 +class Panels(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +        splitter = wx.SplitterWindow(self,​ -1)
 +
 +        vbox1 = wx.BoxSizer(wx.VERTICAL)
 +        panel1 = wx.Panel(splitter,​ -1)
 +        panel11 = wx.Panel(panel1,​ -1, size=(-1, 40))
 +        panel11.SetBackgroundColour('#​53728c'​)
 +        st1 = wx.StaticText(panel11,​ -1, '​Feeds',​ (5, 5))
 +        st1.SetForegroundColour('​WHITE'​)
 +
 +        panel12 = wx.Panel(panel1,​ -1, style=wx.BORDER_SUNKEN)
 +        panel12.SetBackgroundColour('​WHITE'​)
 +
 +        vbox1.Add(panel11,​ 0, wx.EXPAND)
 +        vbox1.Add(panel12,​ 1, wx.EXPAND)
 +
 +        panel1.SetSizer(vbox1)
 +
 +        vbox2 = wx.BoxSizer(wx.VERTICAL)
 +        panel2 = wx.Panel(splitter,​ -1)
 +        panel21 = wx.Panel(panel2,​ -1, size=(-1, 40), style=wx.NO_BORDER)
 +        st2 = wx.StaticText(panel21,​ -1, '​Articles',​ (5, 5))
 +        st2.SetForegroundColour('​WHITE'​)
 +
 +        panel21.SetBackgroundColour('#​53728c'​)
 +        panel22 = wx.Panel(panel2,​ -1, style=wx.BORDER_RAISED)
 +
 +        panel22.SetBackgroundColour('​WHITE'​)
 +        vbox2.Add(panel21,​ 0, wx.EXPAND)
 +        vbox2.Add(panel22,​ 1, wx.EXPAND)
 +
 +        panel2.SetSizer(vbox2)
 +
 +        toolbar = self.CreateToolBar()
 +        toolbar.AddLabelTool(1,​ '​Exit',​ wx.Bitmap('​icons/​stock_exit.png'​))
 +        toolbar.Realize()
 +        self.Bind(wx.EVT_TOOL,​ self.ExitApp,​ id=1)
 +
 +        hbox.Add(splitter,​ 1, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
 +        self.SetSizer(hbox)
 +        self.CreateStatusBar()
 +        splitter.SplitVertically(panel1,​ panel2)
 +        self.Centre()
 +        self.Show(True)
 +
 +
 +    def ExitApp(self,​ event):
 +        self.Close()
 +
 +
 +app = wx.App()
 +Panels(None,​ -1, '​Panels'​)
 +app.MainLoop()
 +
 +</​code>​
 +
 +
 +<code python>
 + hbox = wx.BoxSizer(wx.HORIZONTAL)
 + ​splitter = wx.SplitterWindow(self,​ -1)
 +</​code>​
 +
 +
 +
 +
 +The //​wx.SplitterWindow//​ will split our window into two parts. ​
 +
 +
 +
 +
 +
 +
 +
 +One panel will be placed on the left and one on the right side. Each one will have other two panels. One will create a header and the other one will take up the rest of the parent panel. Together we will use six panels. ​
 +
 +
 +
 +
 +<code python>
 + ​panel11 = wx.Panel(panel1,​ -1, size=(-1, 40))
 + ​panel11.SetBackgroundColour('#​53728c'​)
 + st1 = wx.StaticText(panel11,​ -1, '​Feeds',​ (5, 5))
 + ​st1.SetForegroundColour('​WHITE'​)
 + ​... ​
 + ​vbox1.Add(panel11,​ 0, wx.EXPAND)
 +</​code>​
 +
 +
 +
 +
 +Here we create the header panel. The header height is 40px. The color is set to dark blue. (#53728c) We put a //​wx.StaticText//​ inside the header panel. The position is 5px from left and 5px from top so that we have some space between the panel and the static text. The color of the static text is set to white. ​
 +In the end, we make the panel11 expandable and set the proportion to 0. 
 +
 +
 +
 +
 +<code python>
 + ​panel12 = wx.Panel(panel1,​ -1, style=wx.BORDER_SUNKEN)
 + ​panel12.SetBackgroundColour('​WHITE'​)
 + ...
 + ​vbox1.Add(panel12,​ 1, wx.EXPAND)
 +</​code>​
 +
 +
 +
 +
 +The bottom panel is created with //​wx.BORDER_SUNKEN//​ style. The color is set to white. We make it expandable and set the proportion parameter to 1. 
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +</​html>​
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Advanced widgets in wxPython =====
 +
 +
 +
 +
 +
 +
 +In the following chapters we will talk about advanced widgets. A big advantage of wxPython over a competing PyGTK is the availability of a huge amount of advanced widgets. PyGTK is a layer over a C based GKT+ toolkit. It does not provide new widgets. In contrast, wxPython is a layer over wxWidgets a C++ based toolkit. wxWidgets consists of a large group of widgets. All this widgets are created in C++. wxPython is a glue that combines python language with this toolkit. If we want to have a grid widget in our application using PyGTK, we have to create it ourselves. Such a widget is quite complicated. Not to mention the speed penalty. Dynamic languages like Python, PERL or Ruby are not suitable for such tasks.
 +Dynamic languages are great in various areas. They are simple to use. They are great for prototyping,​ in house developing or for studying computer programming. If we need a quick solution or we need an application,​ that will change rapidly over a short period of time, dynamic languages are superior to compiled languages. ​
 +On the other hand, if we develop resource intensive applications,​ games, high quality multimedia applications,​ there is no competition to C++.
 +
 +
 +
 +
 +
 +
 +wxPython has several well known advanced widgets. For example a tree widget, an html window, a grid widget, a listbox widget, a list widget or an editor with advanced styling capabilities. ​
 +wxPython and wxWidgets are being developed all the time. New widgets and features emerge with every 
 +major release. At the time when I write these words a wxPython 2.8.3.0 has been released just two days ago.
 +(22-Mar-2007). ​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +A //​wx.ListBox//​ widget is used for displaying and working with a list of items. As it's name indicates, it is a rectangle that has a list of strings inside. We could use it for displaying a list of mp3 files, book names, module names of a larger project or names of our friends. ​ A //​wx.ListBox//​ can be created in two different states. In a single selection state or a multiple selection state. The single selection state is the default state. ​
 +There are two significant events in //​wx.ListBox//​. The first one is the //​wx.EVT_COMMAND_LISTBOX_SELECTED//​ event. This event is generated when we select a string in a //​wx.ListBox//​. The second one is the //​wx.EVT_COMMAND_LISTBOX_DOUBLE_CLICKED//​ event. It is generated when we double click an item in a //​wx.ListBox//​. ​
 +The number of elements inside a wx.ListBox is limited on GTK platform. According to the documentation,​ it is currently around 2000
 +elements. Quite enough, I think. The elements are numbered from zero. Scrollbars are displayed automatically if needed. ​
 +
 +
 +
 +
 +
 +
 +
 +The constructor of a wx.ListBox widget is as follows:
 +
 +
 +
 +<code python>
 + ​wx.ListBox(wx.Window parent, int id=-1, wx.Point pos=wx.DefaultPosition,​ wx.Size size=wx.DefaultSize, ​
 +  list choices=[], long style=0, wx.Validator validator=wx.DefaultValidator, ​
 + string name=wx.ListBoxNameStr)
 +</​code>​
 +
 +
 +
 +There is a choices parameter. If we put some values there, they will be displayed from the construction of the widget. ​
 +This parameter is empty by default. ​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +In our code example we have a listbox and four buttons. Each of them calls a different method of our listbox. ​
 +If we want to append a new item, we call the //​Append()//​ method. If we want to delete an item, we call the //​Delete()//​
 +method. To clear all strings in a listbox, we call the Clear() method. ​
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# listbox.py
 +
 +import wx
 +
 +ID_NEW = 1
 +ID_RENAME = 2
 +ID_CLEAR = 3
 +ID_DELETE = 4
 +
 +
 +class ListBox(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(350, 220))
 +
 +        panel = wx.Panel(self,​ -1)
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        self.listbox = wx.ListBox(panel,​ -1)
 +        hbox.Add(self.listbox,​ 1, wx.EXPAND | wx.ALL, 20)
 +
 +        btnPanel = wx.Panel(panel,​ -1)
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        new = wx.Button(btnPanel,​ ID_NEW, '​New',​ size=(90, 30))
 +        ren = wx.Button(btnPanel,​ ID_RENAME, '​Rename',​ size=(90, 30))
 +        dlt = wx.Button(btnPanel,​ ID_DELETE, '​Delete',​ size=(90, 30))
 +        clr = wx.Button(btnPanel,​ ID_CLEAR, '​Clear',​ size=(90, 30))
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.NewItem,​ id=ID_NEW)
 +        self.Bind(wx.EVT_BUTTON,​ self.OnRename,​ id=ID_RENAME)
 +        self.Bind(wx.EVT_BUTTON,​ self.OnDelete,​ id=ID_DELETE)
 +        self.Bind(wx.EVT_BUTTON,​ self.OnClear,​ id=ID_CLEAR)
 +        self.Bind(wx.EVT_LISTBOX_DCLICK,​ self.OnRename)
 +
 +        vbox.Add((-1,​ 20))
 +        vbox.Add(new)
 +        vbox.Add(ren,​ 0, wx.TOP, 5)
 +        vbox.Add(dlt,​ 0, wx.TOP, 5)
 +        vbox.Add(clr,​ 0, wx.TOP, 5)
 +
 +        btnPanel.SetSizer(vbox)
 +        hbox.Add(btnPanel,​ 0.6, wx.EXPAND | wx.RIGHT, 20)
 +        panel.SetSizer(hbox)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def NewItem(self,​ event):
 +        text = wx.GetTextFromUser('​Enter a new item', '​Insert dialog'​)
 +        if text != '':​
 +            self.listbox.Append(text)
 +
 +    def OnRename(self,​ event):
 +        sel = self.listbox.GetSelection()
 +        text = self.listbox.GetString(sel)
 +        renamed = wx.GetTextFromUser('​Rename item', '​Rename dialog',​ text)
 +        if renamed != '':​
 +            self.listbox.Delete(sel)
 +            self.listbox.Insert(renamed,​ sel)
 +
 +
 +    def OnDelete(self,​ event):
 +        sel = self.listbox.GetSelection()
 +        if sel != -1:
 +            self.listbox.Delete(sel)
 +
 +    def OnClear(self,​ event):
 +        self.listbox.Clear()
 +
 +
 +app = wx.App()
 +ListBox(None,​ -1, '​ListBox'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +<code python>
 + ​self.listbox = wx.ListBox(panel,​ -1)
 + ​hbox.Add(self.listbox,​ 1, wx.EXPAND | wx.ALL, 20)
 +</​code>​
 +
 +
 +
 +We create an empty //​wx.ListBox//​. We put a 20px border around the listbox. ​
 +
 +
 +
 +
 +<code python>
 + ​self.Bind(wx.EVT_LISTBOX_DCLICK,​ self.OnRename)
 +</​code>​
 +
 +
 +
 +We bind a //​wx.EVT_COMMAND_LISTBOX_DOUBLE_CLICKED//​ event type with the //​OnRename()//​ method using the //​wx.EVT_LISTBOX_DCLICK//​ event binder. This way we show a rename dialog if we double click on a specific element
 +in the listbox. ​
 +
 +
 +
 +
 +<code python>
 + def NewItem(self,​ event):
 +     text = wx.GetTextFromUser('​Enter a new item', '​Insert dialog'​)
 +     if text != '':​
 +         ​self.listbox.Append(text)
 +</​code>​
 +
 +
 +
 +We call the //​NewItem()//​ method by clicking on the New button. This method shows a //​wx.GetTextFromUser//​ dialog window.
 +The text that we enter is returned to the text variable. If the text is not empty, we append it to the listbox with 
 +the //​Append()//​ method.
 +
 +
 +
 +
 +<code python>
 +def OnDelete(self,​ event):
 +    sel = self.listbox.GetSelection()
 +    if sel != -1:
 +        self.listbox.Delete(sel)
 +</​code>​
 +
 +
 +
 +Deleting an item is done in two steps. First we find the index of the selected item by calling the //​GetSelection()//​ method.
 +Then we delete the item with the //​Delete()//​ method. The parametor to the //​Delete()//​ method is the selected index.
 +
 +
 +
 +
 +<code python>
 + ​self.listbox.Delete(sel)
 + ​self.listbox.Insert(renamed,​ sel)
 +</​code>​
 +
 +
 +
 +Notice, how we managed to rename a string. //​wx.ListBox//​ widget has no Rename() method. We did this functionality by deleting the previously selected string and inserting a new string into the predecessor'​s position. ​
 +
 +
 +
 +
 +<code python>
 + def OnClear(self,​ event):
 +     ​self.listbox.Clear()
 +</​code>​
 +
 +
 +
 +The easiest thing is to clear the whole listbox. We simply call the //Clear()// method. ​
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​listbox2.png }}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +The //​wx.html.HtmlWindow//​ widget displays html pages. It is not a full-fledged browser. We can do
 +interesting things with //​wx.html.HtmlWindow//​ widget.
 +
 +
 +
 +
 +**Special formatting**
 +
 +
 +
 +
 +For example in the following script we will create a window, that will display basic statistics.
 +This formatting would be very hard if possible to create without //​wx.html.HtmlWindow//​ widget.
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +import wx
 +import wx.html as html
 +
 +ID_CLOSE = 1
 +
 +page = '&​lt;​html&​gt;&​lt;​body bgcolor="#​8e8e95"&​gt;&​lt;​table cellspacing="​5"​ border="​0"​ width="​250">​ \
 +&lt;tr width="​200"​ align="​left"&​gt;​ \
 +&lt;td bgcolor="#​e7e7e7">&​amp;​nbsp;&​amp;​nbsp;​Maximum&​lt;/​td&​gt;​ \
 +&lt;td bgcolor="#​aaaaaa"&​gt;&​amp;​nbsp;&​amp;​nbsp;&​lt;​b&​gt;​9000&​lt;/​b&​gt;&​lt;/​td&​gt;​ \
 +&​lt;/​tr&​gt;​ \
 +&lt;tr align="​left"&​gt;​ \
 +&lt;td bgcolor="#​e7e7e7"&​gt;&​amp;​nbsp;&​amp;​nbsp;​Mean&​lt;/​td&​gt;​ \
 +&lt;td bgcolor="#​aaaaaa">&​amp;​nbsp;&​amp;​nbsp;&​lt;​b&​gt;​6076&​lt;/​b&​gt;&​lt;/​td&​gt;​ \
 +&​lt;/​tr&​gt;​ \
 +&lt;tr align="​left">​ \
 +&lt;td bgcolor="#​e7e7e7">&​amp;​nbsp;&​amp;​nbsp;​Minimum&​lt;/​td&​gt;​ \
 +&lt;td bgcolor="#​aaaaaa"&​gt;&​amp;​nbsp;&​amp;​nbsp;&​lt;​b&​gt;​3800&​lt;/​b&​gt;&​lt;/​td&​gt;​ \
 +&​lt;/​tr&​gt;​ \
 +&lt;tr align="​left"&​gt;​ \
 +&lt;td bgcolor="#​e7e7e7"&​gt;&​amp;​nbsp;&​amp;​nbsp;​Median&​lt;/​td&​gt;​ \
 +&lt;td bgcolor="#​aaaaaa"&​gt;&​amp;​nbsp;&​amp;​nbsp;&​lt;​b&​gt;​6000&​lt;/​b&​gt;&​lt;/​td&​gt;​ \
 +&​lt;/​tr&​gt;​ \
 +&lt;tr align="​left"&​gt;​ \
 +&lt;td bgcolor="#​e7e7e7"&​gt;&​amp;​nbsp;&​amp;​nbsp;​Standard Deviation&​lt;/​td&​gt;​ \
 +&lt;td bgcolor="#​aaaaaa"&​gt;&​amp;​nbsp;&​amp;​nbsp;&​lt;​b&​gt;​6076&​lt;/​b&​gt;&​lt;/​td&​gt;​ \
 +&​lt;/​tr&​gt;​ \
 +&​lt;/​body&​gt;&​lt;/​table&​gt;&​lt;/​html&​gt;'​
 +
 +
 +class MyFrame(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(400, 290))
 +
 +        panel = wx.Panel(self,​ -1)
 +
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        htmlwin = html.HtmlWindow(panel,​ -1, style=wx.NO_BORDER)
 +        htmlwin.SetBackgroundColour(wx.RED)
 +        htmlwin.SetStandardFonts()
 +        htmlwin.SetPage(page)
 +
 +        vbox.Add((-1,​ 10), 0)
 +        vbox.Add(htmlwin,​ 1, wx.EXPAND | wx.ALL, 9)
 +
 +        bitmap = wx.StaticBitmap(panel,​ -1, wx.Bitmap('​images/​newt.png'​))
 +        hbox.Add(bitmap,​ 1, wx.LEFT | wx.BOTTOM | wx.TOP, 10)
 +        buttonOk = wx.Button(panel,​ ID_CLOSE, '​Ok'​)
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnClose,​ id=ID_CLOSE)
 +
 +        hbox.Add((100,​ -1), 1, wx.EXPAND | wx.ALIGN_RIGHT)
 +        hbox.Add(buttonOk,​ flag=wx.TOP | wx.BOTTOM | wx.RIGHT, border=10)
 +        vbox.Add(hbox,​ 0, wx.EXPAND)
 +
 +        panel.SetSizer(vbox)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnClose(self,​ event):
 +        self.Close()
 +
 +app = wx.App(0)
 +MyFrame(None,​ -1, 'Basic Statistics'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​basicw.jpg }}
 +
 +
 +
 +
 +
 +**Help window**
 +
 +
 +
 +
 +We can use //​wx.html.HtmlWindow//​ to provide help in our application. We can create a standalone window or we can create a window, that is going to be a part of the application. ​ The following script will create a help window using the latter idea. 
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# helpwindow.py
 +
 +import wx
 +import wx.html as html
 +
 +class HelpWindow(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(570, 400))
 +
 +        toolbar = self.CreateToolBar()
 +        toolbar.AddLabelTool(1,​ '​Exit',​ wx.Bitmap('​icons/​exit.png'​))
 +        toolbar.AddLabelTool(2,​ '​Help',​ wx.Bitmap('​icons/​help.png'​))
 +        toolbar.Realize()
 +
 +        self.splitter = wx.SplitterWindow(self,​ -1)
 +        self.panelLeft = wx.Panel(self.splitter,​ -1, style=wx.BORDER_SUNKEN)
 +
 +        self.panelRight = wx.Panel(self.splitter,​ -1)
 +        vbox2 = wx.BoxSizer(wx.VERTICAL)
 +        header = wx.Panel(self.panelRight,​ -1, size=(-1, 20))
 +        header.SetBackgroundColour('#​6f6a59'​)
 +        header.SetForegroundColour('​WHITE'​)
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        st = wx.StaticText(header,​ -1, '​Help',​ (5, 5))
 +        font = st.GetFont()
 +        font.SetPointSize(9)
 +        st.SetFont(font)
 +        hbox.Add(st,​ 1, wx.TOP | wx.BOTTOM | wx.LEFT, 5)
 +
 +        close = wx.BitmapButton(header,​ -1, wx.Bitmap('​icons/​fileclose.png',​ wx.BITMAP_TYPE_PNG), ​
 + style=wx.NO_BORDER)
 +        close.SetBackgroundColour('#​6f6a59'​)
 +        hbox.Add(close,​ 0)
 +        header.SetSizer(hbox)
 +
 +        vbox2.Add(header,​ 0, wx.EXPAND)
 +
 +        help = html.HtmlWindow(self.panelRight,​ -1, style=wx.NO_BORDER)
 +        help.LoadPage('​help.html'​)
 +        vbox2.Add(help,​ 1, wx.EXPAND)
 +        self.panelRight.SetSizer(vbox2)
 +        self.panelLeft.SetFocus()
 +
 +        self.splitter.SplitVertically(self.panelLeft,​ self.panelRight)
 +        self.splitter.Unsplit()
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.CloseHelp,​ id=close.GetId())
 +        self.Bind(wx.EVT_TOOL,​ self.OnClose,​ id=1)
 +        self.Bind(wx.EVT_TOOL,​ self.OnHelp,​ id=2)
 +
 +        self.Bind(wx.EVT_KEY_DOWN,​ self.OnKeyPressed)
 +
 +        self.CreateStatusBar()
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnClose(self,​ event):
 +        self.Close()
 +
 +    def OnHelp(self,​ event):
 +        self.splitter.SplitVertically(self.panelLeft,​ self.panelRight)
 +        self.panelLeft.SetFocus()
 +
 +    def CloseHelp(self,​ event):
 +        self.splitter.Unsplit()
 +        self.panelLeft.SetFocus()
 +
 +    def OnKeyPressed(self,​ event):
 +        keycode = event.GetKeyCode()
 +        if keycode == wx.WXK_F1:
 +            self.splitter.SplitVertically(self.panelLeft,​ self.panelRight)
 +            self.panelLeft.SetFocus()
 +
 +
 +app = wx.App()
 +HelpWindow(None,​ -1, '​HelpWindow'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +The help window is hidden in the beginning. We can show it by clicking on the help button on the toolbar or by pressing F1.
 +The help window appears on the right side of the application. To hide the help window, we click on the close button.
 +
 +
 +
 +
 +<code python>
 + ​self.splitter.SplitVertically(self.panelLeft,​ self.panelRight)
 + ​self.splitter.Unsplit()
 +</​code>​
 +
 +
 +
 +
 +We create left a right panels and split them vertically. After that, we call the //​Unsplit()//​ method. By default the method hides the right or bottom panes. ​
 +
 +
 +
 +
 +
 +
 +
 +We divide the right panel into two parts. The header and the body of the panel. The header is an adjusted //​wx.Panel//​. The header consists of a static text and a bitmap button. We put //​wx.html.Window//​ into the body of the panel. ​
 +
 +
 +
 +
 +<code python>
 + close = wx.BitmapButton(header,​ -1, wx.Bitmap('​icons/​fileclose.png',​ wx.BITMAP_TYPE_PNG), ​
 + style=wx.NO_BORDER)
 + ​close.SetBackgroundColour('#​6f6a59'​)
 +</​code>​
 +
 +
 +
 +
 +The bitmap button style is set to //​wx.NO_BORDER//​. The background color is set to the color of the header panel. This is done in order to make the button appear as a part of the header.
 +
 +
 +
 +
 +
 +<code python>
 + help = html.HtmlWindow(self.panelRight,​ -1, style=wx.NO_BORDER)
 + ​help.LoadPage('​help.html'​)
 +</​code>​
 +
 +
 +
 +
 +We create a <​a>​wx.html.HtmlWindow</​a>​ widget on the right panel. We have our html code in a separate file. This time we call the //​LoadPage()//​ method to obtain the html code.  ​
 +
 +
 +
 +
 +<code python>
 + ​self.panelLeft.SetFocus()
 +</​code>​
 +
 +
 +
 +
 +We set focus on the left panel. We can launch the help window with the F1 key. In order to control a window with a keyboard, it must have the focus. If we did not set the focus, we would have to first click on the panel and only then we could launch the help window with the F1 key press. ​
 +
 +
 +
 +
 +<code python>
 +    def OnHelp(self,​ event):
 +        self.splitter.SplitVertically(self.panelLeft,​ self.panelRight)
 +        self.panelLeft.SetFocus()
 +</​code>​
 +
 +
 +
 +
 +To show the help window, we call the //​OnHelp()//​ method. It splits the two panels vertically. We must not forget to 
 +set the focus again, because the initial focus is lost by splitting. ​
 +
 +
 +
 +
 +
 +
 +
 +The following is the html file, that we load in our application.
 +
 +
 +
 +
 +<code python>
 +&​lt;​html&​gt;​
 +
 +&​lt;​body bgcolor="#​ababab"&​gt;​
 +&​lt;​h4&​gt;​Table of Contents&​lt;/​h4&​gt;​
 +
 +&​lt;​ul&​gt;​
 +&​lt;​li&​gt;&​lt;​a href="#​basic"&​gt;​Basic statistics&​lt;/​a&​gt;&​lt;/​li&​gt;​
 +&​lt;​li&​gt;&​lt;​a href="#​advanced"&​gt;​Advanced statistics&​lt;/​a&​gt;&​lt;/​li&​gt;​
 +&​lt;​li&​gt;&​lt;​a href="#​intro"&​gt;​Introducing Newt&​lt;/​a&​gt;&​lt;/​li&​gt;​
 +&​lt;​li&​gt;&​lt;​a href="#​charts"&​gt;​Working with charts&​lt;/​a&​gt;&​lt;/​li&​gt;​
 +&​lt;​li&​gt;&​lt;​a href="#​pred"&​gt;​Predicting values&​lt;/​a&​gt;&​lt;/​li&​gt;​
 +&​lt;​li&​gt;&​lt;​a href="#​neural"&​gt;​Neural networks&​lt;/​a&​gt;&​lt;/​li&​gt;​
 +&​lt;​li&​gt;&​lt;​a href="#​glos"&​gt;​Glossary&​lt;/​a&​gt;&​lt;/​li&​gt;​
 +&​lt;/​ul&​gt;​
 +
 +&​lt;​p&​gt;​
 +&lt;a name="​basic"&​gt;​
 +&​lt;​h6&​gt;​Basic Statistics&​lt;/​h6&​gt;​
 +Overview of elementary concepts in statistics.
 +Variables. Correlation. Measurement scales. Statistical significance. ​
 +Distributions. Normality assumption.
 +&​lt;/​a&​gt;​
 +&​lt;/​p&​gt;​
 +
 +&​lt;​p&​gt;​
 +&lt;a name="​advanced"&​gt;​
 +&​lt;​h6&​gt;​Advanced Statistics&​lt;/​h6&​gt;​
 +Overview of advanced concepts in statistics. Anova. Linear regression. ​
 +Estimation and  hypothesis testing.
 +Error terms.
 +&​lt;/​a&​gt;​
 +&​lt;/​p&​gt;​
 +
 +&​lt;​p&​gt;​
 +&lt;a name="​intro"&​gt;​
 +&​lt;​h6&​gt;​Introducing Newt&​lt;/​h6&​gt;​
 +Introducing the basic functionality of the Newt application. Creating sheets. ​
 +Charts. Menus and Toolbars. Importing data. Saving data in various formats. ​
 +Exporting data. Shortcuts. List of methods.
 +&​lt;/​a&​gt;​
 +&​lt;/​p&​gt;​
 +
 +&​lt;​p&​gt;​
 +&lt;a name="​charts"&​gt;​
 +&​lt;​h6&​gt;​Charts&​lt;/​h6&​gt;​
 +Working with charts. 2D charts. 3D charts. Bar, line, box, pie, range charts. ​
 +Scatterplots. Histograms.
 +&​lt;/​a&​gt;​
 +&​lt;/​p&​gt;​
 +
 +&​lt;​p&​gt;​
 +&lt;a name="​pred"&​gt;​
 +&​lt;​h6&​gt;​Predicting values&​lt;/​h6&​gt;​
 +Time series and forecasting. Trend Analysis. Seasonality. Moving averages. ​
 +Univariate methods. Multivariate methods. Holt-Winters smoothing. ​
 +Exponential smoothing. ARIMA. Fourier analysis.
 +&​lt;/​a&​gt;​
 +&​lt;/​p&​gt;​
 +
 +&​lt;​p&​gt;​
 +&lt;a name="​neural"&​gt;​
 +&​lt;​h6&​gt;​Neural networks&​lt;/​h6&​gt;​
 +Overview of neural networks. Biology behind neural networks.
 +Basic artificial Model. Training. Preprocessing. Postprocessing. ​
 +Types of neural networks.
 +&​lt;/​a&​gt;​
 +&​lt;/​p&​gt;​
 +
 +&​lt;​p&​gt;​
 +&lt;a name="​glos"&​gt;​
 +&​lt;​h6&​gt;​Glossary&​lt;/​h6&​gt;​
 +Terms and definitions in statistics.
 +&​lt;/​a&​gt;​
 +&​lt;/​p&​gt;​
 +
 +&​lt;/​body&​gt;​
 +&​lt;/​html&​gt;​
 +</​code>​
 +
 +
 +<code python>
 + &​lt;​li&​gt;&​lt;​a href="#​basic"&​gt;​Basic statistics&​lt;/​a&​gt;&​lt;/​li&​gt;​
 + ...
 + &​lt;​a name="​basic"&​gt;​
 +</​code>​
 +
 +
 +
 +
 +Normally I would write &lt;div id="​basic"&​gt;​ ... &​lt;/​div&​gt;​. Both are correct html notations. But //​wx.html.HtmlWindow//​ supports only the first one. //​wx.html.HtmlWindow//​ supports only a subset of the html markup language.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​helpwindow.png }}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +A //​wx.ListCtrl//​ is a graphical representation of a list of items. A //​wx.ListBox//​ can only have one column. //​wx.ListCtrl//​ can have more than one column. ​
 +//​wx.ListCtrl//​ is a very common and useful widget.
 +For example a file manager uses a //​wx.ListCtrl//​ to display directories and files on the file system. A cd burner application displays files to be burned inside a //​wx.ListCtrl//​. ​
 +
 +
 +
 +
 +
 +
 +
 +A //​wx.ListCtrl//​ can be used in three different formats. In a list view, report view or a icon view. These formats are controled by the //​wx.ListCtrl//​ window styles. //​wx.LC_REPORT//,​ //​wx.LC_LIST//​ and //​wx.LC_ICON//​.
 +
 +
 +
 +
 +<code python>
 + ​wx.ListCtrl(wx.Window parent, int id, wx.Point pos = (-1, -1), wx.Size size = (-1, -1), 
 + int style = wx.LC_ICON, wx.Validator validator = wx.DefaultValidator,​ string name = wx.ListCtrlNameStr)
 +</​code>​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +**wx.ListCtrl styles **
 +
 +
 +  * wx.LC_LIST
 +  * wx.LC_REPORT
 +  * wx.LC_VIRTUAL
 +  * wx.LC_ICON
 +  * wx.LC_SMALL_ICON
 +  * wx.LC_ALIGN_LEFT
 +  * wx.LC_EDIT_LABELS
 +  * wx.LC_NO_HEADER
 +  * wx.LC_SORT_ASCENDING
 +  * wx.LC_SORT_DESCENDING
 +  * wx.LC_HRULES ​
 +  * wx.LC_VRULES
 +
 +
 +
 +
 +
 +
 +**Simple example**
 +
 +
 +
 +
 +In the first example we will introduce basic functionality of a //​wx.ListCtrl//​. ​
 +
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# actresses.py
 +
 +import wx
 +import sys
 +
 +packages = [('​jessica alba', '​pomona',​ '​1981'​),​ ('​sigourney weaver',​ 'new york', '​1949'​),​
 +    ('​angelina jolie',​ 'los angeles',​ '​1975'​),​ ('​natalie portman',​ '​jerusalem',​ '​1981'​),​
 +    ('​rachel weiss',​ '​london',​ '​1971'​),​ ('​scarlett johansson',​ 'new york', '​1984'​ )]
 +
 +
 +
 +class Actresses(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(380, 230))
 +
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +        panel = wx.Panel(self,​ -1)
 +
 +        self.list = wx.ListCtrl(panel,​ -1, style=wx.LC_REPORT)
 +        self.list.InsertColumn(0,​ '​name',​ width=140)
 +        self.list.InsertColumn(1,​ '​place',​ width=130)
 +        self.list.InsertColumn(2,​ '​year',​ wx.LIST_FORMAT_RIGHT,​ 90)
 +
 +        for i in packages:
 +            index = self.list.InsertStringItem(sys.maxint,​ i[0])
 +            self.list.SetStringItem(index,​ 1, i[1])
 +            self.list.SetStringItem(index,​ 2, i[2])
 +
 +        hbox.Add(self.list,​ 1, wx.EXPAND)
 +        panel.SetSizer(hbox)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +Actresses(None,​ -1, '​actresses'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +<code python>
 + ​self.list = wx.ListCtrl(panel,​ -1, style=wx.LC_REPORT)
 +</​code>​
 +
 +
 +
 +
 +We create a //​wx.ListCtrl//​ with a wx.LC_REPORT style.
 +
 +
 +
 +
 +<code python>
 + ​self.list.InsertColumn(0,​ '​name',​ width=140)
 + ​self.list.InsertColumn(1,​ '​place',​ width=130)
 + ​self.list.InsertColumn(2,​ '​year',​ wx.LIST_FORMAT_RIGHT,​ 90)
 +</​code>​
 +
 +
 +
 +
 +We insert three columns. We can specify the //width// of the column and the //format// of the column. The default format is //​wx.LIST_FORMAT_LEFT//​.
 +
 +
 +
 +
 +<code python>
 + for i in packages:
 +     index = self.list.InsertStringItem(sys.maxint,​ i[0])
 +     ​self.list.SetStringItem(index,​ 1, i[1])
 +     ​self.list.SetStringItem(index,​ 2, i[2])
 +</​code>​
 +
 +
 +
 +
 +We insert data into the //​wx.ListCtrl//​ using two methods. Each row begins with a //​InsertStringItem()//​ method. The first parameter of the method specifies the row number. By giving a sys.maxint we ensure, that each call will insert data after the last row. The method returns the row index. The //​SetStringItem()//​ method adds data to the consecutive columns of the current row.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +**Mixins**
 +
 +
 +
 +
 +Mixins are classes that further enhance the functionality of a //​wx.ListCtrl//​. Mixin classes are so called helper classes. They are located in //​wx.lib.mixins.listctrl//​ module. In order to use them, the programmer has to inherit from these classes.
 +
 +
 +
 +
 +
 +
 +
 +There are five available mixins. As of 2.8.1.1.
 +
 +
 +
 +
 +
 +  * wx.ColumnSorterMixin
 +  * wx.ListCtrlAutoWidthMixin
 +  * wx.ListCtrlSelectionManagerMix
 +  * wx.TextEditMixin
 +  * wx.CheckListCtrlMixin
 +
 +
 +
 +
 +
 +
 +
 +//​wx.ColumnSorterMixin//​ is a mixin that enables sorting of columns in a report view. //​wx.ListCtrlAutoWidthMixin//​ class automatically resizes the last column to the end of the //​wx.ListCtrl//​. By default, the last column does not take the remaining space. See the previous example. //​wx.ListCtrlSelectionManagerMix//​ defines platform independent selection policy. //​wx.TextEditMixin//​ enables text to be edited. //​wx.CheckListCtrlMixin//​ adds a check box to each row. This way we can control rows. We can set every row to be checked or unchecked. ​
 +
 +
 +
 +
 +
 +
 +The following code shows, how we can use //​ListCtrlAutoWidthMixin// ​
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# autowidth.py
 +
 +import wx
 +import sys
 +from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin
 +
 +actresses = [('​jessica alba', '​pomona',​ '​1981'​),​ ('​sigourney weaver',​ 'new york', '​1949'​),​
 +    ('​angelina jolie',​ 'los angeles',​ '​1975'​),​ ('​natalie portman',​ '​jerusalem',​ '​1981'​),​
 +    ('​rachel weiss',​ '​london',​ '​1971'​),​ ('​scarlett johansson',​ 'new york', '​1984'​ )]
 +
 +
 +class AutoWidthListCtrl(wx.ListCtrl,​ ListCtrlAutoWidthMixin):​
 +    def __init__(self,​ parent):
 +        wx.ListCtrl.__init__(self,​ parent, -1, style=wx.LC_REPORT)
 +        ListCtrlAutoWidthMixin.__init__(self)
 +
 +
 +class Actresses(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(380, 230))
 +
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        panel = wx.Panel(self,​ -1)
 +
 +        self.list = AutoWidthListCtrl(panel)
 +        self.list.InsertColumn(0,​ '​name',​ width=140)
 +        self.list.InsertColumn(1,​ '​place',​ width=130)
 +        self.list.InsertColumn(2,​ '​year',​ wx.LIST_FORMAT_RIGHT,​ 90)
 +
 +        for i in actresses:
 +            index = self.list.InsertStringItem(sys.maxint,​ i[0])
 +            self.list.SetStringItem(index,​ 1, i[1])
 +            self.list.SetStringItem(index,​ 2, i[2])
 +
 +        hbox.Add(self.list,​ 1, wx.EXPAND)
 +        panel.SetSizer(hbox)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +Actresses(None,​ -1, '​actresses'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +We change the previous example a bit.
 +
 +
 +
 +<code python>
 +from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin
 +</​code>​
 +
 +
 +
 +
 +Here we import the mixin.
 +
 +
 +
 +
 +
 +<code python>
 + class AutoWidthListCtrl(wx.ListCtrl,​ ListCtrlAutoWidthMixin):​
 +     def __init__(self,​ parent):
 +         ​wx.ListCtrl.__init__(self,​ parent, -1, style=wx.LC_REPORT)
 +         ​ListCtrlAutoWidthMixin.__init__(self)
 +</​code>​
 +
 +
 +
 +
 +We create a new //​AutoWidthListCtrl//​ class. This class will inherit from //​wx.ListCtrl//​ and //​ListCtrlAutoWidthMixin//​. This is called **multiple inheritance**.
 +The last column will automatically resize to take up the remaining width of a //​wx.ListCtrl//​. ​
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​autowidthl.jpg }}
 + {{ http://​zetcode.com/​wxpython/​images/​autowidthw.jpg }}
 +
 +
 +
 +
 +
 +
 +In the following example we will show, how we can create sortable columns. If we click on the column header, ​
 +the corresponding rows in a column are sorted.
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# sorted.py
 +
 +import wx
 +import sys
 +from wx.lib.mixins.listctrl import ColumnSorterMixin
 +
 +actresses = {
 +1 : ('​jessica alba', '​pomona',​ '​1981'​), ​
 +2 : ('​sigourney weaver',​ 'new york', '​1949'​),​
 +3 : ('​angelina jolie',​ 'los angeles',​ '​1975'​), ​
 +4 : ('​natalie portman',​ '​jerusalem',​ '​1981'​),​
 +5 : ('​rachel weiss',​ '​london',​ '​1971'​), ​
 +6 : ('​scarlett johansson',​ 'new york', '​1984'​) ​
 +}
 +
 +
 +class SortedListCtrl(wx.ListCtrl,​ ColumnSorterMixin):​
 +    def __init__(self,​ parent):
 +        wx.ListCtrl.__init__(self,​ parent, -1, style=wx.LC_REPORT)
 +        ColumnSorterMixin.__init__(self,​ len(actresses))
 +        self.itemDataMap = actresses
 +
 +    def GetListCtrl(self):​
 +        return self
 +
 +class Actresses(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(380, 230))
 +
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        panel = wx.Panel(self,​ -1)
 +
 +        self.list = SortedListCtrl(panel)
 +        self.list.InsertColumn(0,​ '​name',​ width=140)
 +        self.list.InsertColumn(1,​ '​place',​ width=130)
 +        self.list.InsertColumn(2,​ '​year',​ wx.LIST_FORMAT_RIGHT,​ 90)
 +
 +        items = actresses.items()
 +
 +        for key, data in items:
 +            index = self.list.InsertStringItem(sys.maxint,​ data[0])
 +            self.list.SetStringItem(index,​ 1, data[1])
 +            self.list.SetStringItem(index,​ 2, data[2])
 +            self.list.SetItemData(index,​ key)
 +
 +        hbox.Add(self.list,​ 1, wx.EXPAND)
 +        panel.SetSizer(hbox)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +Actresses(None,​ -1, '​actresses'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +We will again use the example with actresses.
 +
 +
 +
 +
 +<code python>
 + ​ColumnSorterMixin.__init__(self,​ len(actresses))
 +</​code>​
 +
 +
 +
 +
 +The //​ColumnSorterMixin//​ accepts one argument. It is the number of columns to be sorted. ​
 +
 +
 +
 +
 +<code python>
 + ​self.itemDataMap = actresses
 +</​code>​
 +
 +
 +
 +
 +We must map our data to be displayed in a list control to the //​itemDataMap//​ attribute. The data must be in a dictionary data type.
 +
 +
 +
 +
 +<code python>
 + def GetListCtrl(self):​
 +     ​return self
 +</​code>​
 +
 +
 +
 +
 +We must create a //​GetListCtrl()//​ method. This method returns the //​wx.ListCtrl//​ widget that is going to be sorted.
 +
 +
 +
 +
 +<code python>
 + ​self.list.SetItemData(index,​ key)
 +</​code>​
 +
 +
 +
 +
 + We must assosiate each row with a special index. This is done with the //​SetItemData//​ method. ​
 +
 +
 +
 +
 +
 +
 +
 +**Reader**
 +
 +
 +
 +
 +A reader is a complex example showing two list controls in a report view.
 +
 +
 +
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# reader.py
 +
 +
 +import wx
 +
 +articles = [['​Mozilla rocks',​ 'The year of the Mozilla',​ 'Earth on Fire'​],​
 +            ['​Gnome pretty, Gnome Slow', '​Gnome,​ KDE, Icewm, XFCE', 'Where is Gnome heading?'​],​
 +            ['Java number one language',​ '​Compiled languages, intrepreted Languages',​ 'Java on Desktop?'​]]
 +
 +
 +
 +class ListCtrlLeft(wx.ListCtrl):​
 +    def __init__(self,​ parent, id):
 +        wx.ListCtrl.__init__(self,​ parent, id, style=wx.LC_REPORT | wx.LC_HRULES | 
 + wx.LC_NO_HEADER | wx.LC_SINGLE_SEL)
 +        images = ['​icons/​java.png',​ '​icons/​gnome.png',​ '​icons/​mozilla.png'​]
 +
 +        self.parent = parent
 +
 +        self.Bind(wx.EVT_SIZE,​ self.OnSize)
 +        self.Bind(wx.EVT_LIST_ITEM_SELECTED,​ self.OnSelect)
 +
 +        self.il = wx.ImageList(32,​ 32)
 +        for i in images:
 +            self.il.Add(wx.Bitmap(i))
 +
 +        self.SetImageList(self.il,​ wx.IMAGE_LIST_SMALL)
 +        self.InsertColumn(0,​ ''​)
 +
 +        for i in range(3):
 +            self.InsertStringItem(0,​ ''​)
 +            self.SetItemImage(0,​ i)
 +
 +    def OnSize(self,​ event):
 +        size = self.parent.GetSize()
 +        self.SetColumnWidth(0,​ size.x-5)
 +        event.Skip()
 +
 +    def OnSelect(self,​ event):
 +        window = self.parent.GetGrandParent().FindWindowByName('​ListControlOnRight'​)
 +        index = event.GetIndex()
 +        window.LoadData(index)
 +
 +    def OnDeSelect(self,​ event):
 +        index = event.GetIndex()
 +        self.SetItemBackgroundColour(index,​ '​WHITE'​)
 +
 +    def OnFocus(self,​ event):
 +        self.SetItemBackgroundColour(0,​ '​red'​)
 +
 +class ListCtrlRight(wx.ListCtrl):​
 +    def __init__(self,​ parent, id):
 +        wx.ListCtrl.__init__(self,​ parent, id, style=wx.LC_REPORT | wx.LC_HRULES | 
 + wx.LC_NO_HEADER | wx.LC_SINGLE_SEL)
 +
 +        self.parent = parent
 +
 +        self.Bind(wx.EVT_SIZE,​ self.OnSize)
 +
 +        self.InsertColumn(0,​ ''​)
 +
 +
 +    def OnSize(self,​ event):
 +        size = self.parent.GetSize()
 +        self.SetColumnWidth(0,​ size.x-5)
 +        event.Skip()
 +
 +    def LoadData(self,​ index):
 +        self.DeleteAllItems()
 +        for i in range(3):
 +            self.InsertStringItem(0,​ articles[index][i])
 +
 +
 +class Reader(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title)
 +
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +        splitter = wx.SplitterWindow(self,​ -1, style=wx.SP_LIVE_UPDATE|wx.SP_NOBORDER)
 +
 +        vbox1 = wx.BoxSizer(wx.VERTICAL)
 +        panel1 = wx.Panel(splitter,​ -1)
 +        panel11 = wx.Panel(panel1,​ -1, size=(-1, 40))
 +        panel11.SetBackgroundColour('#​53728c'​)
 +        st1 = wx.StaticText(panel11,​ -1, '​Feeds',​ (5, 5))
 +        st1.SetForegroundColour('​WHITE'​)
 +
 +        panel12 = wx.Panel(panel1,​ -1, style=wx.BORDER_SUNKEN)
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        list1 = ListCtrlLeft(panel12,​ -1)
 +
 +        vbox.Add(list1,​ 1, wx.EXPAND)
 +        panel12.SetSizer(vbox)
 +        panel12.SetBackgroundColour('​WHITE'​)
 +
 +
 +        vbox1.Add(panel11,​ 0, wx.EXPAND)
 +        vbox1.Add(panel12,​ 1, wx.EXPAND)
 +
 +        panel1.SetSizer(vbox1)
 +
 +        vbox2 = wx.BoxSizer(wx.VERTICAL)
 +        panel2 = wx.Panel(splitter,​ -1)
 +        panel21 = wx.Panel(panel2,​ -1, size=(-1, 40), style=wx.NO_BORDER)
 +        st2 = wx.StaticText(panel21,​ -1, '​Articles',​ (5, 5))
 +        st2.SetForegroundColour('​WHITE'​)
 +
 +        panel21.SetBackgroundColour('#​53728c'​)
 +        panel22 = wx.Panel(panel2,​ -1, style=wx.BORDER_RAISED)
 +        vbox3 = wx.BoxSizer(wx.VERTICAL)
 +        list2 = ListCtrlRight(panel22,​ -1)
 +        list2.SetName('​ListControlOnRight'​)
 +        vbox3.Add(list2,​ 1, wx.EXPAND)
 +        panel22.SetSizer(vbox3)
 +
 +
 +        panel22.SetBackgroundColour('​WHITE'​)
 +        vbox2.Add(panel21,​ 0, wx.EXPAND)
 +        vbox2.Add(panel22,​ 1, wx.EXPAND)
 +
 +        panel2.SetSizer(vbox2)
 +
 +        toolbar = self.CreateToolBar()
 +        toolbar.AddLabelTool(1,​ '​Exit',​ wx.Bitmap('​icons/​stock_exit.png'​))
 +        toolbar.Realize()
 +
 +        self.Bind(wx.EVT_TOOL,​ self.ExitApp,​ id=1)
 +
 +        hbox.Add(splitter,​ 1, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
 +        self.SetSizer(hbox)
 +        self.CreateStatusBar()
 +        splitter.SplitVertically(panel1,​ panel2)
 +        self.Centre()
 +        self.Show(True)
 +
 +
 +    def ExitApp(self,​ event):
 +        self.Close()
 +
 +
 +app = wx.App()
 +Reader(None,​ -1, '​Reader'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +The previous example showed a //​wx.ListCtrl//​ in a report view. With no headers. We shall create our own headers. We show two //​wx.ListCtrl//​ widgets. One is on the right side and the other one on the left side of the application. ​
 +
 +
 +
 +
 +<code python>
 + ​splitter = wx.SplitterWindow(self,​ -1, style=wx.SP_LIVE_UPDATE|wx.SP_NOBORDER)
 + ...
 + ​splitter.SplitVertically(panel1,​ panel2)
 +</​code>​
 +
 +
 +
 +
 +The splitter will split the main window into two vertical parts. The splitter will show two panels. Those two panels will have another ​ two panels. They create //Feeds// and //​Articles//​ headers. The rest of the space will be occupied by our two //​wx.ListCtrl//​ widgets.
 +
 +
 +
 +
 +<code python>
 + list2 = ListCtrlRight(panel22,​ -1)
 + ​list2.SetName('​ListControlOnRight'​)
 +</​code>​
 +
 +
 +
 +
 +When we create //​ListCtrlRight//​ object, we  give it a name //​ListControlOnRight//​. This is because we need //​ListCtrlRight// ​ and //​ListCtrlLeft//​ two widgets to communicate. ​
 +
 +
 +
 +
 +<code python>
 + def OnSelect(self,​ event):
 +     ​window = self.parent.GetGrandParent().FindWindowByName('​ListControlOnRight'​)
 +     index = event.GetIndex()
 +     ​window.LoadData(index)
 +</​code>​
 +
 +
 +
 +
 +This code is in  //​ListCtrlLeft//​ class. Here we locate the //​ListCtrlRight//​ object and call it's //​LoadData()//​ method.
 +
 +
 +
 +
 +<code python>
 + def LoadData(self,​ index):
 +     ​self.DeleteAllItems()
 +     for i in range(3):
 +         ​self.InsertStringItem(0,​ articles[index][i])
 +</​code>​
 +
 +
 +
 +
 +The //​LoadData()//​ method first clears all items. Then it inserts the article names from the globally defined articles list. The index has been passed. ​
 +
 +
 +
 +
 +<code python>
 + def OnSize(self,​ event):
 +     size = self.parent.GetSize()
 +     ​self.SetColumnWidth(0,​ size.x-5)
 +     ​event.Skip()
 +</​code>​
 +
 +
 +
 +
 +Both //​wx.ListCtrl//​s have only one column. Here we ensure that the size of the column equals to size of the parent panel. ​
 +The application would not look nice otherwise. Why do we extract 5px? This number is a kind of magic number. If we extract exactly 5px, the horizotal scrollbars do not appear. On other platforms, the number might be different.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​reader.png }}
 +
 +
 +
 +
 +
 +
 +**CheckListCtrl**
 +
 +
 +
 +
 +It is quite common to see applications having check boxes inside list controls. For example a packaging application like Synaptic or KYUM.
 +
 +
 +
 +
 +
 +
 +
 +From the programmer'​s point of view, those checkboxes are simple images. There are two states. Checked and unchecked. For both situations we have a unique image. We do not have to implement the functionality. It has been already coded. The code is in //​CheckListCtrlMixin//​. ​
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# repository.py
 +
 +import wx
 +import sys
 +from wx.lib.mixins.listctrl import CheckListCtrlMixin,​ ListCtrlAutoWidthMixin
 +
 +packages = [('​abiword',​ '​5.8M',​ '​base'​),​ ('​adie',​ '​145k',​ '​base'​),​
 +    ('​airsnort',​ '​71k',​ '​base'​),​ ('​ara',​ '​717k',​ '​base'​),​ ('​arc',​ '​139k',​ '​base'​),​
 +    ('​asc',​ '​5.8M',​ '​base'​),​ ('​ascii',​ '​74k',​ '​base'​),​ ('​ash',​ '​74k',​ '​base'​)]
 +
 +class CheckListCtrl(wx.ListCtrl,​ CheckListCtrlMixin,​ ListCtrlAutoWidthMixin):​
 +    def __init__(self,​ parent):
 +        wx.ListCtrl.__init__(self,​ parent, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
 +        CheckListCtrlMixin.__init__(self)
 +        ListCtrlAutoWidthMixin.__init__(self)
 +
 +
 +class Repository(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(450, 400))
 +
 +        panel = wx.Panel(self,​ -1)
 +
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        leftPanel = wx.Panel(panel,​ -1)
 +        rightPanel = wx.Panel(panel,​ -1)
 +
 +        self.log = wx.TextCtrl(rightPanel,​ -1, style=wx.TE_MULTILINE)
 +        self.list = CheckListCtrl(rightPanel)
 +        self.list.InsertColumn(0,​ '​Package',​ width=140)
 +        self.list.InsertColumn(1,​ '​Size'​)
 +        self.list.InsertColumn(2,​ '​Repository'​)
 +
 +        for i in packages:
 +            index = self.list.InsertStringItem(sys.maxint,​ i[0])
 +            self.list.SetStringItem(index,​ 1, i[1])
 +            self.list.SetStringItem(index,​ 2, i[2])
 +
 +        vbox2 = wx.BoxSizer(wx.VERTICAL)
 +
 +        sel = wx.Button(leftPanel,​ -1, '​Select All', size=(100, -1))
 +        des = wx.Button(leftPanel,​ -1, '​Deselect All', size=(100, -1))
 +        apply = wx.Button(leftPanel,​ -1, '​Apply',​ size=(100, -1))
 +
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnSelectAll,​ id=sel.GetId())
 +        self.Bind(wx.EVT_BUTTON,​ self.OnDeselectAll,​ id=des.GetId())
 +        self.Bind(wx.EVT_BUTTON,​ self.OnApply,​ id=apply.GetId())
 +
 +        vbox2.Add(sel,​ 0, wx.TOP, 5)
 +        vbox2.Add(des)
 +        vbox2.Add(apply)
 +
 +        leftPanel.SetSizer(vbox2)
 +
 +        vbox.Add(self.list,​ 1, wx.EXPAND | wx.TOP, 3)
 +        vbox.Add((-1,​ 10))
 +        vbox.Add(self.log,​ 0.5, wx.EXPAND)
 +        vbox.Add((-1,​ 10))
 +
 +        rightPanel.SetSizer(vbox)
 +
 +        hbox.Add(leftPanel,​ 0, wx.EXPAND | wx.RIGHT, 5)
 +        hbox.Add(rightPanel,​ 1, wx.EXPAND)
 +        hbox.Add((3,​ -1))
 +
 +        panel.SetSizer(hbox)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnSelectAll(self,​ event):
 +        num = self.list.GetItemCount()
 +        for i in range(num):
 +            self.list.CheckItem(i)
 +
 +    def OnDeselectAll(self,​ event):
 +        num = self.list.GetItemCount()
 +        for i in range(num):
 +            self.list.CheckItem(i,​ False)
 +
 +    def OnApply(self,​ event):
 +        num = self.list.GetItemCount()
 +        for i in range(num):
 +            if i == 0: self.log.Clear()
 +            if self.list.IsChecked(i):​
 +                self.log.AppendText(self.list.GetItemText(i) + '​\n'​)
 +
 +app = wx.App()
 +Repository(None,​ -1, '​Repository'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​repository.png }}
 +
 +
 +
 +
 +
 +<code python>
 + class CheckListCtrl(wx.ListCtrl,​ CheckListCtrlMixin,​ ListCtrlAutoWidthMixin):​
 +     def __init__(self,​ parent):
 +         ​wx.ListCtrl.__init__(self,​ parent, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
 +         ​CheckListCtrlMixin.__init__(self)
 +         ​ListCtrlAutoWidthMixin.__init__(self)
 +</​code>​
 +
 +
 +
 +
 +wxPython enables multiple inheritance. Here we inherit from three different classes.
 +
 +
 +
 +
 +<code python>
 + def OnSelectAll(self,​ event):
 +     num = self.list.GetItemCount()
 +     for i in range(num):
 +         ​self.list.CheckItem(i)
 +</​code>​
 +
 +
 +
 +
 +Here we can see multiple inheritance in action. We can call two methods from two different classes on our //​self.list//​ object. The //​GetItemCount()//​ method is located in //​CheckListCtrl//​ class and the //​CheckItem()//​ method is in // CheckListCtrlMixin//​ class.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +</​html>​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Drag and drop in wxPython =====
 +
 +
 +
 +
 +
 +
 +Wikipedia: ​
 +
 +In computer graphical user interfaces, drag-and-drop is the action of (or support for the action of) clicking on a virtual object and dragging it to a different location or onto another virtual object. In general, it can be used to invoke many kinds of actions, or create various types of associations between two abstract objects. ​
 +
 +
 +
 +
 +
 +
 +Drag and drop functionality is one of the most visible aspects of the graphical user interface. ​
 +Drag and drop operation enables you to do complex things intuitively. ​
 +
 +
 +
 +
 +
 +
 +
 +
 +In drag and drop we basically drag some data from a data source to a data target. ​
 +So we must have:
 +
 +
 +  * Some data
 +  * A data source
 +  * A data target
 +
 +
 +In wxPython we have two predefined data targets. **wx.TextDropTarget** and **wx.FileDropTarget**.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# dragdrop.py
 +
 +import os
 +import wx
 +
 +class MyTextDropTarget(wx.TextDropTarget):​
 +    def __init__(self,​ object):
 +        wx.TextDropTarget.__init__(self)
 +        self.object = object
 +
 +    def OnDropText(self,​ x, y, data):
 +        self.object.InsertStringItem(0,​ data)
 +
 +
 +class DragDrop(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(650, 500))
 +
 +        splitter1 = wx.SplitterWindow(self,​ -1, style=wx.SP_3D)
 +        splitter2 = wx.SplitterWindow(splitter1,​ -1, style=wx.SP_3D)
 +        self.dir = wx.GenericDirCtrl(splitter1,​ -1, dir='/​home/',​ style=wx.DIRCTRL_DIR_ONLY)
 +        self.lc1 = wx.ListCtrl(splitter2,​ -1, style=wx.LC_LIST)
 +        self.lc2 = wx.ListCtrl(splitter2,​ -1, style=wx.LC_LIST)
 +
 +        dt = MyTextDropTarget(self.lc2)
 +        self.lc2.SetDropTarget(dt)
 +        self.Bind(wx.EVT_LIST_BEGIN_DRAG,​ self.OnDragInit,​ id=self.lc1.GetId())
 +
 +        tree = self.dir.GetTreeCtrl()
 +
 +        splitter2.SplitHorizontally(self.lc1,​ self.lc2)
 +        splitter1.SplitVertically(self.dir,​ splitter2)
 +
 +        self.Bind(wx.EVT_TREE_SEL_CHANGED,​ self.OnSelect,​ id=tree.GetId())
 +
 +        self.OnSelect(0)
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnSelect(self,​ event):
 +        list = os.listdir(self.dir.GetPath())
 +        self.lc1.ClearAll()
 +        self.lc2.ClearAll()
 +        for i in range(len(list)):​
 +            if list[i][0] != '​.':​
 +                self.lc1.InsertStringItem(0,​ list[i])
 +
 +    def OnDragInit(self,​ event):
 +        text = self.lc1.GetItemText(event.GetIndex())
 +        tdo = wx.TextDataObject(text)
 +        tds = wx.DropSource(self.lc1)
 +        tds.SetData(tdo)
 +        tds.DoDragDrop(True)
 +
 +
 +app = wx.App()
 +DragDrop(None,​ -1, '​dragdrop.py'​)
 +app.MainLoop()
 +
 +</​code>​
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# filedrop.py
 +
 +import wx
 +
 +class FileDrop(wx.FileDropTarget):​
 +    def __init__(self,​ window):
 +        wx.FileDropTarget.__init__(self)
 +        self.window = window
 +
 +    def OnDropFiles(self,​ x, y, filenames):
 +
 +        for name in filenames:
 +            try:
 +                file = open(name, '​r'​)
 +                text = file.read()
 +                self.window.WriteText(text)
 +                file.close()
 +            except IOError, error:
 +                dlg = wx.MessageDialog(None,​ 'Error opening file\n'​ + str(error))
 +                dlg.ShowModal()
 +            except UnicodeDecodeError,​ error:
 +                dlg = wx.MessageDialog(None,​ '​Cannot open non ascii files\n'​ + str(error))
 +                dlg.ShowModal()
 +
 +class DropFile(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size = (450, 400))
 +
 +        self.text = wx.TextCtrl(self,​ -1, style = wx.TE_MULTILINE)
 +        dt = FileDrop(self.text)
 +        self.text.SetDropTarget(dt)
 +        self.Centre()
 +        self.Show(True)
 +
 +
 +app = wx.App()
 +DropFile(None,​ -1, '​filedrop.py'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +</​html>​
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Internationalization =====
 +
 +
 +
 +
 +
 +
 +In computing, Internationalization and localization are means of adapting computer software for non-native environments,​ especially other nations and cultures. Internationalization is the process of ensuring that an application is capable of adapting to local requirements,​ for instance ensuring that the local writing system can be displayed. Localization is the process of adapting the software to be as familiar as possible to a specific locale, by displaying text in the local language and using local conventions for the display of such things as units of measurement. (wikipedia)
 +
 +
 +
 +
 +==== Unicode ====
 +
 +
 +
 +
 +There are two builds of wxPython. The ansi build and the unicode build. If we want to create and use wxPython applications
 +in languages other than english, we must have the unicode build.
 +
 +
 +
 +
 +
 +
 +**Unicode** is an industry standard allowing computers to consistently represent and manipulate text expressed in any of the world'​s writing systems. It is a character enconding standart which uses 16 bits for storing characters. The traditional **ASCII** enconding uses only 8 bits.
 +
 +
 +
 +
 +
 +
 +
 +First, we need to get the unicode enconding of Лев Николaевич Толстoй Анна Каренина words. ​
 +
 +
 +
 +
 +
 +<code python>
 +>>>​ unicode(u'​Лев Николaевич Толстoй Анна Каренина'​)
 +u'​\u041b\u0435\u0432 \u041d\u0438\u043aa\u0430\u0301\u0435\u0432\u0438\u0447
 +\u0422\u043e\u043b\u0441o\u0439 \u0410\u043d\u043d\u0430 ​
 +\u041a\u0430\u0440\u0435\u043d\u0438\u043d\u0430'​
 +</​code>​
 +
 +
 +
 +
 +We launch the python terminal and use the //​unicode()//​ function call. Notice, that in the example, we use additional ​
 +\n\ characters to divide the words into two lines.
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +import wx
 +
 +text = u'​\u041b\u0435\u0432 \u041d\u0438\u043a\u043e\u043b\u0430\
 +\u0435\u0432\u0438\u0447 \u0422\u043e\u043b\u0441\u0442\u043e\u0439 \n\
 +\u0410\u043d\u043d\u0430 \u041a\u0430\u0440\u0435\u043d\u0438\u043d\u0430'​
 +
 +
 +class Unicode(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 150))
 +
 +        self.Bind(wx.EVT_PAINT,​ self.OnPaint)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnPaint(self,​ event):
 +        dc = wx.PaintDC(self)
 +        dc.DrawText(text,​ 50, 50)
 +
 +app = wx.App()
 +Unicode(None,​ -1, '​Unicode'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +
 +
 +In the example, we draw Anna Karenina in russian azbuka on the window.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​unicode.jpg |Unicode}}
 +
 +
 +
 +==== Locale ====
 +
 +
 +
 +
 +A locale is an object that defines user's language, country, number format, letter format, currency format etc.
 +A local variant has the following format.
 +
 +
 +
 +
 +<code python>
 + ​[language[_territory][.codeset][@modifier]]
 +</​code>​
 +
 +
 +
 +
 +For example, **de_AT.utf8** is a german local used in Austria, with UTF8 codeset.
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# locale.py
 +
 +import wx
 +import time
 +import locale
 +
 +class Locale(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(250, 420))
 +
 +        panel = wx.Panel(self,​ -1)
 +
 +
 +        tm = time.localtime()
 +
 +        font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)
 +        us = wx.StaticText(self,​ -1, '​United States',​ (25, 20))
 +        us.SetFont(font)
 +
 +        wx.StaticLine(self,​ -1, (25, 50), (200 ,1))
 +
 +        locale.setlocale(locale.LC_ALL,​ ''​)
 +        date = time.strftime('​%x',​ tm)
 +        time_ = time.strftime('​%X',​ tm)
 +        curr =  locale.currency(100000)
 +
 +        wx.StaticText(self,​ -1, 'date: ', (25, 70))
 +        wx.StaticText(self,​ -1, 'time: ', (25, 90))
 +        wx.StaticText(self,​ -1, '​currency:​ ', (25, 110))
 +
 +        wx.StaticText(self,​ -1, str(date), (125, 70))
 +        wx.StaticText(self,​ -1, str(time_), (125, 90))
 +        wx.StaticText(self,​ -1, str(curr), (125, 110))
 +
 +        de = wx.StaticText(self,​ -1, '​Germany',​ (25, 150))
 +        de.SetFont(font)
 +
 +        wx.StaticLine(self,​ -1, (25, 180), (200,1))
 +
 +        locale.setlocale(locale.LC_ALL,​ ('​de_DE',​ '​UTF8'​))
 +        date = time.strftime('​%x',​ tm)
 +        time_ = time.strftime('​%X',​ tm)
 +        curr =  locale.currency(100000)
 +
 +        wx.StaticText(self,​ -1, 'date: ', (25, 200))
 +        wx.StaticText(self,​ -1, 'time: ', (25, 220))
 +        wx.StaticText(self,​ -1, '​currency:​ ', (25, 240))
 +        wx.StaticText(self,​ -1, date, (125, 200))
 +        wx.StaticText(self,​ -1, time_, (125, 220))
 +        wx.StaticText(self,​ -1, curr, (125, 240))
 +
 +        de = wx.StaticText(self,​ -1, '​Slovakia',​ (25, 280))
 +        de.SetFont(font)
 +
 +        wx.StaticLine(self,​ -1, (25, 310), (200,1))
 +
 +        locale.setlocale(locale.LC_ALL,​ ('​sk_SK',​ '​UTF8'​))
 +        date = time.strftime('​%x',​ tm)
 +        time_ = time.strftime('​%X',​ tm)
 +        curr =  locale.currency(100000)
 +
 +        wx.StaticText(self,​ -1, 'date: ', (25, 330))
 +        wx.StaticText(self,​ -1, 'time: ', (25, 350))
 +        wx.StaticText(self,​ -1, '​currency:​ ', (25, 370))
 +
 +        wx.StaticText(self,​ -1, str(date), (125, 330))
 +        wx.StaticText(self,​ -1, str(time_), (125, 350))
 +        wx.StaticText(self,​ -1, str(curr), (125, 370))
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +app = wx.App()
 +Locale(None,​ -1, '​Locale'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +
 +
 +We use the standart built-in module **locale** to work with localized settings. In our example, we will show various formats of date, time and currency in the USA, Germany and Slovakia. ​
 +
 +
 +
 +
 +<code python>
 + ​locale.setlocale(locale.LC_ALL,​ ('​de_DE',​ '​UTF8'​))
 +</​code>​
 +
 +
 +
 +
 +Here we set a locale object for Germany. **LC_ALL** is a combination of all various local settings, e.g. LC_TIME, LC_MONETARY,​ LC_NUMERIC.
 +
 +
 +
 +
 +<code python>
 + date = time.strftime('​%x',​ tm)
 + time_ = time.strftime('​%X',​ tm)
 + curr =  locale.currency(100000)
 +</​code>​
 +
 +
 +
 +
 +These function calls reflect the current locale object.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​locale.jpg |Locale}}
 +
 +
 +==== World Time ====
 +
 +
 +
 +
 +At a specific moment, we have different time in countries across the world. Our globe is divided into time zones. It is not uncommon for programmers to deal with such tasks. wxPython comes with a //​wx.DateTime//​ object. According to the documentation,​ wxDateTime class represents an absolute moment in the time. 
 +
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +import wx
 +import time
 +
 +class WorldTime(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(270, 280))
 +
 +        self.panel = wx.Panel(self,​ -1)
 +        self.panel.SetBackgroundColour('#​000000'​)
 +        font = wx.Font(12, wx.FONTFAMILY_DEFAULT, ​
 + wx.FONTSTYLE_NORMAL,​ wx.FONTWEIGHT_BOLD,​ False, '​Georgia'​)
 +
 +        self.dt = wx.DateTime()
 +
 +        self.tokyo = wx.StaticText(self.panel,​ -1, 
 + self.dt.FormatTime() , (20, 20))
 +        self.tokyo.SetForegroundColour('#​23f002'​)
 +        self.tokyo.SetFont(font)
 +
 +        self.moscow = wx.StaticText(self.panel,​ -1,  ​
 + self.dt.FormatTime() , (20, 70))
 +        self.moscow.SetForegroundColour('#​23f002'​)
 +        self.moscow.SetFont(font)
 +
 +        self.budapest = wx.StaticText(self.panel,​ -1,  ​
 + self.dt.FormatTime() , (20, 120))
 +        self.budapest.SetForegroundColour('#​23f002'​)
 +        self.budapest.SetFont(font)
 +
 +        self.london = wx.StaticText(self.panel,​ -1,  ​
 + self.dt.FormatTime() , (20, 170))
 +        self.london.SetForegroundColour('#​23f002'​)
 +        self.london.SetFont(font)
 +
 +        self.newyork = wx.StaticText(self.panel,​ -1,  ​
 + self.dt.FormatTime() , (20, 220))
 +        self.newyork.SetForegroundColour('#​23f002'​)
 +        self.newyork.SetFont(font)
 +
 +        self.OnTimer(None)
 +
 +        self.timer = wx.Timer(self)
 +        self.timer.Start(1000)
 +        self.Bind(wx.EVT_TIMER,​ self.OnTimer)
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnTimer(self,​ evt):
 +        now = self.dt.Now()
 +        self.tokyo.SetLabel('​Tokyo:​ ' + str(now.Format(('​%a %T'​), ​
 + wx.DateTime.GMT_9)))
 +        self.moscow.SetLabel('​Moscow:​ ' + str(now.Format(('​%a %T'​), ​
 + wx.DateTime.MSD)))
 +        self.budapest.SetLabel('​Budapest:​ ' +  str(now.Format(('​%a %T'​), ​
 + wx.DateTime.CEST)))
 +        self.london.SetLabel('​London:​ ' + str(now.Format(('​%a %T'​), ​
 + wx.DateTime.WEST)))
 +        self.newyork.SetLabel('​New York: ' + str(now.Format(('​%a %T'​), ​
 + wx.DateTime.EDT)))
 +
 +
 +app = wx.App()
 +WorldTime(None,​ -1, 'World Time')
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +
 +
 +
 +In the code example, we show current time in Tokyo, Moscow, Budapest, London and New York.
 +
 +
 +
 +
 +<code python>
 + ​self.dt = wx.DateTime()
 +</​code>​
 +
 +
 +
 +
 +Here we create a //​wx.DateTime//​ object.
 +
 +
 +
 +
 +<code python>
 + now = self.dt.Now()
 +</​code>​
 +
 +
 +
 +
 +We get the "​absolute moment"​ in time.
 +
 +
 +
 +
 +<code python>
 + ​self.tokyo.SetLabel('​Tokyo:​ ' + str(now.Format(('​%a %T'​), ​
 +     ​wx.DateTime.GMT_9)))
 +</​code>​
 +
 +
 +
 +
 +This code line sets the time to the appropriate format. ​ The %a conversion specifier is an abbreviated weekday name according to the current locale. The %T is the time of day using decimal numbers using the format %H:%M:%S.
 +The second parameter of the Format() method specifies the time zone. GMT_9 is used for Japan, EDT (Eastern Daylight Saving Time) is used in New York etc.
 +
 +
 +
 +
 +
 +
 +
 +The code example was checked with the [[http://​www.timeanddate.com/​worldclock/​|timeanddate.com]] website.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://​zetcode.com/​wxpython/​images/​worldtime.jpg |World Time}}
 +
 +
 +==== Sorting ====
 +
 +
 +
 +
 +Locale settings also affect the way, how strings are being sorted. For example hungarian language has some characters that are missing in Slovak language or English language. Some languages have accents, others don'​t. ​
 +
 +
 +
 +
 +<code python>
 +#​!/​usr/​bin/​python
 +
 +# collate.py
 +
 +import wx
 +import locale
 +
 +ID_SORT = 1
 +
 +words = [u'​Sund',​ u'​S\xe4bel',​ u'​S\xfcnde',​ u'​Schl\xe4fe',​ u'​Sabotage'​]
 +
 +
 +class Collate(wx.Frame):​
 +    def __init__(self,​ parent, id, title):
 +        wx.Frame.__init__(self,​ parent, id, title, size=(300, 220))
 +
 +        panel = wx.Panel(self,​ -1)
 +        hbox = wx.BoxSizer(wx.HORIZONTAL)
 +
 +        self.listbox = wx.ListBox(panel,​ -1)
 +        for i in words:
 +            self.listbox.Append(i)
 +        hbox.Add(self.listbox,​ 1, wx.EXPAND | wx.ALL, 20)
 +
 +        btnPanel = wx.Panel(panel,​ -1)
 +        vbox = wx.BoxSizer(wx.VERTICAL)
 +        new = wx.Button(btnPanel,​ ID_SORT, '​Sort',​ size=(90, 30))
 +
 +        self.Bind(wx.EVT_BUTTON,​ self.OnSort,​ id=ID_SORT)
 +
 +        vbox.Add((-1,​ 20))
 +        vbox.Add(new)
 +
 +        btnPanel.SetSizer(vbox)
 +        hbox.Add(btnPanel,​ 0.6, wx.EXPAND | wx.RIGHT, 20)
 +        panel.SetSizer(hbox)
 +
 +        locale.setlocale(locale.LC_COLLATE,​ ('​de_DE',​ '​UTF8'​))
 +
 +        self.Centre()
 +        self.Show(True)
 +
 +    def OnSort(self,​ event):
 +        self.listbox.Clear()
 +        words.sort( lambda a,b: locale.strcoll(a,​ b) )
 +        for i in words:
 +            self.listbox.Append(i)
 +
 +
 +app = wx.App()
 +Collate(None,​ -1, '​Collate'​)
 +app.MainLoop()
 +</​code>​
 +
 +
 +
 +
 +