أعجوبة

البرمجيات الحُرة والمفتوحة المصدر

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

أدوات الموقع


docs:javaswing

اختلافات

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

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

جانبي المراجعة السابقةالمراجعة السابقة
docs:javaswing [2011/08/28 10:26] alsadidocs:javaswing [2015/04/23 03:20] (حالي) – تحرير خارجي 127.0.0.1
سطر 1: سطر 1:
 +{{tag>مقالات مترجمة برمجة جافا java swing}}
 +
 +====== البرمجية الرسومية في جافا مع swing ======
 +
 +  * مقالة من تأليف Jan Bodnar
 +  * المصدر http://zetcode.com/tutorials/javaswingtutorial/
 +  * ترجمة //**سيف أبـاظة**//
 +  * قيد الإنشاء
 +
 +هذا درس حول الـ Java Swing , هذا الدرس للمطورين المبتدئين و المتوسط , بعد قراءة هذا الدرس ستتمكن من كتابة برامج Java Swing بكل سهوله .
 +
 +Similar tutorials
 +  * QtJambi tutorial
 +  * Java 2D games tutorial
 +  * Java 2D tutorial
 +  * Java Gnome tutorial
 +  * Java SWT tutorial
 +
 +
 +
 +
 +
 +
 +
 +
 +===== مدخل إلى التعامل مع الـ Java Swing Toolkit =====
 +
 +
 +
 +==== عن هذا الدرس ====
 +
 +
 +هو درس تمهيدي , إلى التعامل مع الـ Swing , الهدف من هذا هو البدء في إستعمال الـ Java Swing Toolkit , تمت تجربة الأمثال على نظام تشغيل لينكس .
 +
 +
 +
 +
 +
 +==== ما هي الـ Swing====
 +
 +
 +
 +
 +هي مكتبة لأدوات الوجهه الرسوميه ( مثل : الأزرار , مربعات النص … ) تختصر إلى GUI و هي من إنتاج Sun Microsystems , تكون مضمنه مع الـ Java بأسم Swing .
 +
 +__**من المزايا الرئيسيه فيها :**__
 +
 +
 +  - .متعددت المنصات , أي تعمل على أي بيئة تشغيل
 +  - قابله للتعديل
 +  - قابليه للتجديد
 +  - خفيفة
 +
 +
 +
 +__**وتتضمن الحزم التاليه :**__
 +
 +  * javax.swing
 +  * javax.swing.border
 +  * javax.swing.colorchooser
 +  * javax.swing.event
 +  * javax.swing.filechooser
 +  * javax.swing.plaf
 +  * javax.swing.plaf.basic
 +  * javax.swing.plaf.metal
 +  * javax.swing.plaf.multi
 +  * javax.swing.plaf.synth
 +  * javax.swing.table
 +  * javax.swing.text
 +  * javax.swing.text.html
 +  * javax.swing.text.html.parser
 +  * javax.swing.text.rtf
 +  * javax.swing.tree
 +  * javax.swing.undo 
 +
 +
 +تتميز Swing بأنها غنيه بالـ widget الأساسيه مثل الـ Botton و الـ Label و TextBox , و أيضا مثل الـ Tree و الـ Tables , وهي مكتوبه كلها بالـ Java , كما أنها جزء من الـ JFC , تم إنشائها لتكون سمه متكامله لبرامج سطح المكتب .
 +
 +الـ JFC تتضمن أيضاً الـ AWT , فهذا جعل هناك إمكانية التعامل مع الـ Java 2D و الإسقاط Drag and Drop.
 +
 +تم تصميمها في عام 1997 مع الـ JDK الإصدار 1.2 بصوره متكامله تماماً .
 +منصة Java تحتوي على مكتبات ثنائية الأبعاد 2D مما يُمكن المبرمجين من التعامل مع الرسم و التصوير الثنائي الأبعاد , وهناك  نوعين من الـ Widget الهامه للتعامل مع هذا الخاصيه وهم :
 +
 +  * الأدوات الخفيفه    Lightweight
 +  * الأدوات الثقيله    - Heavyweight
 +
 +
 +الأدوات الثقيله ( Heavyweight ) تعتمد على الـ API الخاصة بنظام التشغيل لرسم الأدوات الخاصه بها ( widget ) , مثل الـ Borland VCL فهي من الأدوات الثقيله لأنها تعتمد على
 +
 + الـ Win32 API المدموجه مع وجهة البرامج في وندوز , في Unix و Linux هناك أدوات الـ +GTK التي تكون مبنيه في الأساس على مكتبة X11 , و Swing هو بديل الـ GTK و أيضاً بأدوات خفيفة و له تأثير جمالي على الـ widget .
 +
 +====  مكتبة SWT  ====
 +
 +
 +
 +هي أيضاً مكتبه للـ GUI في لغة الـ Java , وتسمى SWT .
 +تم برمجتها في شركة IBM و الأن هي مشروع مفتوح المصدر , مدعمه من IBM , تعتبر الـ SWT مثال للأدوات الثقيله ( Heavyweight ) , وتسمح بإستغلال أساس نظام التشغيل لعمل وجهه رسوميه GUI , وتقوم بإنشائها بإستخدام الوجهه الأصليه للـ Java , من مُمَيزاتها السرعه و التأثيرات الجميله التي يُطلق عليها أسم الـ Look and Feel , و من سلبياتها كثرة أحتمالات الأخطاء بها و أقل كفاءه من الـ Swing , و الـ SWT تماماً مثل مكتبة Windows Centric .
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== البرنامج الأول بالـ Java Swing =====
 +
 +
 +
 +
 +
 +سنبدء الأن في هذا الجزء ببرمجة أول برنامج لنا بإستخدام أداة الـ Swing , وسيكون برنامج بسيط جداً , لكنه سيُغطي أساسيات هامه .
 +
 +
 +
 +
 +==== برنامجنا الأول ====
 +
 +
 +
 +
 +في هذا البرنامج سنقوم بتصميم نافذه Window عاديه جداً ولكن أساسيه
 +
 +
 +
 +
 +<code java>
 +import javax.swing.JFrame;
 +
 +
 +public class Simple extends JFrame {
 +
 +    public Simple() {
 +
 +        setSize(300, 200);
 +        setTitle("Simple");
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +   }
 +
 +    public static void main(String[] args) {
 +
 +        Simple simple = new Simple();
 +        simple.setVisible(true);
 +
 +    } 
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +كما نرى مجموعة بسيطه وسهله من الأكواد أنشأت لنا نافذه مثل أي نافذه نستخدمها في البرامج العاديه تماماً , فبإمكانك بهذا التطبيق الصغير تكبير أو تصغير النافذه , ربما بعد ذالك نزيد من التعقيد في الكود ولكن هذا يعتمد على ذكاء المُبرمج .
 +
 +
 +
 +
 +<code java>
 + import javax.swing.JFrame;
 +</code>
 +
 +
 +
 +هنا قمنا بضم Widget أسمها Jframe , وهي تقوم بعمل إطار من نوع TOPLEVEL , أي يُمكن توضيفها مع Widget أخرى .
 +
 +
 +
 +<code java>
 + setSize(300, 200);
 + setTitle("Simple");
 +</code>
 +
 +
 +
 +السطر الأول نقوم بتحديد مساحة النافذه بـ 300 pix عرض و 200 pix طول .
 +السطر الثاني نقوم بوضع عنوان للنافذه .
 +
 +
 +
 +
 +<code java>
 + setDefaultCloseOperation(EXIT_ON_CLOSE);
 +</code>
 +
 +
 +
 +هذا الـ method ستقوم بإغلاق النافذه إذا تم الضغط على زر الإغلاق x , وهذه تكون الصوره الإفتراضية , وما بين القوسين أي يقوم بتنفيذ عملية الخروج دون إحداث أي شيء .
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/simple.jpg |Simple}}
 +
 +
 +
 +
 +==== توسيط النافذه في منتصف الشاشة  ====
 +
 +
 +
 +
 +بصوره إفتراضيه , عندما تظهر النافذه على الشاشه , لا تكون في المنتصف , بل ستظهر في أعلى اليسار في الزاويه .
 +
 +الكود التالي سيقوم بإظهر النافذه في منتصف الشاشه .
 +
 +
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +import java.awt.Toolkit;
 +
 +import javax.swing.JFrame;
 +
 +public class CenterOnScreen extends JFrame {
 +
 +    public CenterOnScreen() {
 +
 +        setSize(300, 200);
 +        setTitle("CenterOnScreen");
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +
 +        Toolkit toolkit = getToolkit();
 +        Dimension size = toolkit.getScreenSize();
 +        setLocation(size.width/2 - getWidth()/2, 
 + size.height/2 - getHeight()/2);
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        CenterOnScreen cos = new CenterOnScreen();
 +        cos.setVisible(true);
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +لجعل النافذه في المنتصف فيجب علينا تحديد الـ Resolution في الشاشه , ولهذا أستخدمنا الكلاس Toolkit .
 +
 +
 +
 +<code java>
 + Toolkit toolkit = getToolkit();
 + Dimension size = toolkit.getScreenSize();
 +</code>
 +
 +
 +
 +
 +هنا أحضرنا رقم المقاس الخاص بالشاشه .
 +
 +
 +
 +
 +<code java>
 + setLocation(size.width/2 - getWidth()/2, size.height/2 - getHeight()/2);
 +</code>
 +
 +
 +
 +
 +لتحديد مكان النافذه على الشاشه , نستخدم الـ method التي أسمها setLocation
 +
 +
 +
 +
 +
 +====الأزرار - Buttons ====
 +
 +
 +
 +
 +
 +في هذا المثال سنقوم بإنشاء زرين , الزر الأول يقوم بإصدار صوت , والزر الثاني يقوم بإغلاق البرنامج .
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +import java.awt.Toolkit;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class Buttons extends JFrame {
 +
 +    private Toolkit toolkit;
 +
 +    public Buttons() {
 +
 +        setTitle("Buttons");
 +        setSize(300, 200);
 +
 +        toolkit = getToolkit();
 +        Dimension size = toolkit.getScreenSize();
 +        setLocation((size.width - getWidth())/2, (size.height - getHeight())/2);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +
 +        JPanel panel = new JPanel();
 +        getContentPane().add(panel);
 +
 + panel.setLayout(null);
 +
 +        JButton beep = new JButton("Beep");
 +        beep.setBounds(150, 60, 80, 30);
 +        beep.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                toolkit.beep();
 +            }
 +        });
 +
 +       JButton close = new JButton("Close");
 +       close.setBounds(50, 60, 80, 30);
 +       close.addActionListener(new ActionListener() {
 +           public void actionPerformed(ActionEvent event) {
 +               System.exit(0);
 +          }
 +       });
 +
 +        panel.add(beep);
 +        panel.add(close);
 +
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        Buttons buttons = new Buttons();
 +        buttons.setVisible(true);
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +في هذا المثال سنتعرف على نقطتين مهمين , وهم إدارة النماذج ( Layout Management ) و معالجة الأحداث ( Event Handling )  , وسنتحدث عنه بإختصار  ,لأن كل من هذه الخواص لها فصل كامل .
 +
 +
 +
 +<code java>
 + JPanel panel = new JPanel();
 + getContentPane().add(panel);
 +</code>
 +
 +
 +
 +
 +قمنا بإنشاء عنصر Jpanel , وهو حاويه ( Container ) من الأدوات خفيفة الوزن ( lightweight ) , بعد هذا قمنا بإضافة العنصر Jpanel في العنصر Jframe .
 +
 +
 +
 +<code java>
 + panel.setLayout(null);
 +</code>
 +
 +
 +
 +
 +يمتلك العنصر Jpanel القدره على إدارة النماذج الإنسيابيه ( FlowLayout ) , فهي مسؤله عن تحديد مكان الـ Widget في الحاويه ( Container ) , فإذا قمنا بطلب setLayout(null( فهذا سيُمكنا من تحديد مكان العنصر الخاص بنا , ولهذا قمنا بإستخدام الMethod  التي أسمها  setBounds .
 +ملاحظة :
 +قم بمحاولة إلغاء الـ setLayout مره و //setBounds// مره أخرى حتى تعرف الغرض منهم .
 +
 +
 +
 +<code java>
 + JButton beep = new JButton("Beep");
 + beep.setBounds(150, 60, 80, 30);
 + beep.addActionListener(new ActionListener() {
 +     public void actionPerformed(ActionEvent event) {
 +         toolkit.beep();
 +     }
 + });
 +</code>
 +
 +
 +
 +
 +هنا قمنى بإنشاء أول زر , وقمنا بتحديد مكانه عن طريق الـ setBounds Method , وقمنا بعدها بإنشاء حدث Listener , فعند الضغط على الزر فسيتم تنفيذ الـ ActionEvent و في مثلنا هذا سيقوم الزر بإصدار صوت Beep.
 +
 +
 +
 +
 +<code java>
 + System.exit(0);
 +</code>
 +
 +
 +زر الخروج سنخرج به من البرنامج تماماً , لهذا قمبنا بإستدعاء الـ Method الذي أسمه System.exit .
 +
 +
 +
 +<code java>
 + panel.add(beep);
 + panel.add(close);
 +</code>
 +
 +
 +
 +
 +لطلب عرض الأزرار , فيجب علينا وضعها في الـ Panel السابق إنشائها .
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/buttons.jpg |Buttons}}
 +
 +
 +
 +==== التعامل مع الـ tooltip ====
 +
 +
 +
 +
 +أداة الـ Tooltip جزء من أجزاء البرامج الداخليه في النظام , الـ Swing تقوم بعرض مستطيل صغير إذا مر مؤشر الفأره على Object . 
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +import java.awt.Toolkit;
 +
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class Tooltip extends JFrame {
 +
 +    private Toolkit toolkit;
 +
 +    public Tooltip() {
 +
 +        setTitle("Tooltip");
 +        setSize(300, 200);
 +
 +        toolkit = getToolkit();
 +        Dimension size = toolkit.getScreenSize();
 +        setLocation((size.width - getWidth())/2, (size.height - getHeight())/2);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +
 +        JPanel panel = new JPanel();
 +        getContentPane().add(panel);
 +
 +        panel.setLayout(null);
 +        panel.setToolTipText("A Panel container");
 +
 +        JButton button = new JButton("Button");
 +        button.setBounds(100, 60, 80, 30);
 +        button.setToolTipText("A button component");
 +
 +        panel.add(button);
 +
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        Tooltip tooltip = new Tooltip();
 +        tooltip.setVisible(true);
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +قمنا بإضافة خاصية الـ Tooltip لكل من الزر و الـ Panel  , في هذا السطر 
 +
 +
 +
 +
 +<code java>
 + panel.setToolTipText("A Panel container");
 +</code>
 +
 +
 +
 +فلتفعيل هذا الخاصيه نقوم بإستدعاء الـ Method الذي أسمه  setTooltipText().
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/tooltip.jpg |Tooltip}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== القوائم و شريط الأدوات في Java Swing =====
 +
 +
 +==== طريقة إنشاء شريط الأدوات (Menubar) ====
 +
 +
 +
 +
 +يعتبر الـ Menubar من أكثر الأدوات الواضحة دائماً للمستخدم في البرامج التي تعتمد على الوجهة الرسومية (GUI). يتكون من مجموعة من الأوامر التي يتم تنفيذا سواء بالنقر عليها أو بطلبها عبر لوحة المفاتيح , وهناك معاير يُكتب بها الكود لتجنب الغموض و البس أثناء إستدعاء هذا الأوامر لتنفيذ مهمه معينه .
 +
 +
 +لإستخدام الـ Menu في الـ Java Swing , هناك إستدعاء لثالث كائنات Object وهم Jmenu , Jmenubar , JmenuItem .
 +
 +
 +
 +
 +==== إنشاء Menu بسيط ====
 +
 +
 +
 +
 +سنبدء بإنشاء Menu بسيط جداً وسهل
 +
 +
 +
 +
 +<code java>
 +package com.zetcode;
 +
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.event.KeyEvent;
 +
 +import javax.swing.ImageIcon;
 +import javax.swing.JFrame;
 +import javax.swing.JMenu;
 +import javax.swing.JMenuBar;
 +import javax.swing.JMenuItem;
 +
 +
 +public class Menu extends JFrame {
 +
 +    public Menu() {
 +
 +        setTitle("JMenuBar");
 +
 +        JMenuBar menubar = new JMenuBar();
 +        ImageIcon icon = new ImageIcon("exit.png");
 +
 +        JMenu file = new JMenu("File");
 +        file.setMnemonic(KeyEvent.VK_F);
 +
 +        JMenuItem fileClose = new JMenuItem("Close", icon);
 +        fileClose.setMnemonic(KeyEvent.VK_C);
 +        fileClose.setToolTipText("Exit application");
 +        fileClose.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                System.exit(0);
 +            }
 +
 +        });
 +
 +        file.add(fileClose);
 +
 +        menubar.add(file);
 +
 +        setJMenuBar(menubar);
 +
 +        setSize(250, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        new Menu();
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +في هذا المثال قمنا بإنشاء Menu تحتوي على عنصر واحد , وإختيار العنصر Close سيتم من خلاله إغلاق البرنامج تماماً .
 +
 +
 +
 +
 +<code java>
 + JMenuBar menubar = new JMenuBar();
 +</code>
 +
 +
 +
 +
 +هنا قمنا بإنشاء Menubar
 +
 +
 +
 +
 +<code java>
 + ImageIcon icon = new ImageIcon("exit.png");
 +</code>
 +
 +
 +
 +
 +قمنا بوضع icon للعنصر Close
 +
 +
 +
 +
 +<code java>
 + JMenu file = new JMenu("File");
 + file.setMnemonic(KeyEvent.VK_F);
 +</code>
 +
 +
 +
 +قمنا هنا بإنشاء الـ Menu و جعلنا هناك إمكانية الوصول لها من خلال لوحة المفاتيح , وربطناها بمفتاح مخصص بإستخدام Menthod أسمها setMnemonic , فبهذا تمكنا من الوصول إلى هذه الـMenu بالضغط على Alt + F
 +
 +
 +<code java>
 + fileClose.setToolTipText("Exit application");
 +</code>
 +
 +
 +
 +
 +وهذا السطر يُمكنا من عمل Tooltip لعنصر الإغلاق Close .
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/menubar.jpg |JMenuBar}}
 +
 +
 +
 +==== القوائم الفرعية – Submenu ====
 +
 +
 +
 +
 +من الممكن إنشاء قوائم فرعية  للقائمة الواحده , مما يُشكل مجموعة إلى مجموعات , مثلا ً, بإمكاننا وضع أوامر في القائمة وظيفتها تقوم بإخفاء و إضهار البار الشخصي على البرنامج أو شريط الحالة أو بار العناوين في برامج تصفح الإنترنت , وكل هذا عن طريق قائمة فرعيه تسمى Toolbars متفرعه من قائمه فرعيه . 
 +وبإمكاننا أيضاً عمل الفواصل في القوائم , فهو عباره عن خط بسيط يفصل عنصر عن عنصر , كثيراً ما نراه في البرامج بين الحفظ و الفتح و بين الطباعه و معاينة الطباعة , أيضاً بإمكاننا تنفيذ أوامر القائمه عن طريق لوحة المفاتيح .
 +
 +
 +البرنامج التالي إضافة على السابق في زيادة عدد العناصر و عمل فاصل 
 +بالإضافة إلى قائمة فرعية و إختصار سريع للبرنامج.
 +
 +
 +<code java>
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.event.KeyEvent;
 +
 +import javax.swing.ImageIcon;
 +import javax.swing.JFrame;
 +import javax.swing.JMenu;
 +import javax.swing.JMenuBar;
 +import javax.swing.JMenuItem;
 +import javax.swing.KeyStroke;
 +
 +
 +public class Submenu extends JFrame {
 +
 +    public Submenu() {
 +
 +        setTitle("Submenu");
 +
 +        JMenuBar menubar = new JMenuBar();
 +        ImageIcon iconNew = new ImageIcon("new.png");
 +        ImageIcon iconOpen = new ImageIcon("open.png");
 +        ImageIcon iconSave = new ImageIcon("save.png");
 +        ImageIcon iconClose = new ImageIcon("exit.png");
 +
 +        JMenu file = new JMenu("File");
 +        file.setMnemonic(KeyEvent.VK_F);
 +
 +        JMenu imp = new JMenu("Import");
 +        imp.setMnemonic(KeyEvent.VK_M);
 +
 +        JMenuItem newsf = new JMenuItem("Import newsfeed list...");
 +        JMenuItem bookm = new JMenuItem("Import bookmarks...");
 +        JMenuItem mail = new JMenuItem("Import mail...");
 +
 +        imp.add(newsf);
 +        imp.add(bookm);
 +        imp.add(mail);
 +
 +        JMenuItem fileNew = new JMenuItem("New", iconNew);
 +        fileNew.setMnemonic(KeyEvent.VK_N);
 +
 +        JMenuItem fileOpen = new JMenuItem("Open", iconOpen);
 +        fileNew.setMnemonic(KeyEvent.VK_O);
 +
 +        JMenuItem fileSave = new JMenuItem("Save", iconSave);
 +        fileSave.setMnemonic(KeyEvent.VK_S);     
 +
 +        JMenuItem fileClose = new JMenuItem("Close", iconClose);
 +        fileClose.setMnemonic(KeyEvent.VK_C);
 +        fileClose.setToolTipText("Exit application");
 +        fileClose.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, 
 +            ActionEvent.CTRL_MASK));
 +
 +        fileClose.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                System.exit(0);   
 +            }
 +
 +        });
 +
 +        file.add(fileNew);
 +        file.add(fileOpen);
 +        file.add(fileSave);
 +        file.addSeparator();
 +        file.add(imp);
 +        file.addSeparator();
 +        file.add(fileClose);
 +
 +        menubar.add(file);
 +
 +        setJMenuBar(menubar);
 +
 +        setSize(360, 250);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new Submenu();
 +    }
 +}
 +</code>
 +
 +
 +نأتي الأن للشرح ….
 +
 +
 +
 +
 +
 +<code java>
 + JMenu imp = new JMenu("Import");
 + ...
 + file.add(imp);
 +</code>
 +
 +
 +
 +
 +إنشاء قائمة فرعيه مثلها مثل إنشاء القائمه العاديه , تُنشأ بنفس الطريقة ثما نقوم بوضعها في القائمة الأساسيه .
 +
 +
 +
 +<code java>
 + fileClose.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, 
 +     ActionEvent.CTRL_MASK));
 +</code>
 +
 +
 +
 +
 +هنا قمنا بئنشاء الإختصار المطلوب عمله للبرنامج , فقد قمنا بإختيار الإختصار Ctrl + W لإغلاق البرنامج .
 +
 +
 +
 +<code java>
 + file.addSeparator();
 +</code>
 +
 +
 +
 +
 +قمنا هنا بإنشاء فاصل أفقي , وهذا لجعل القائمة عباره عن مجموعات منفصله و مرتبه بشكل منطقي و يُسهل التعامل معاها .
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/submenu.jpg |Submenu}}
 +
 +
 +
 +
 +==== JCheckBoxMenuItem ====
 +
 +
 +
 +
 +في هذا المثال سنتعلم كيفية إنشاء عنصر CheckMark على الـ Menu القائمه
 +فعند الضغط عليها يضهر علامة الصح على العنصر , و الضغط عليها مره أخرى
 +يقوم بإلغاء العلامه من العنصر , و من الممكن تحميلها بنص أو أيكونه Icon ,أو الإثنين معاً على حسب إختيارك أنت .
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.event.KeyEvent;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.JCheckBoxMenuItem;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JMenu;
 +import javax.swing.JMenuBar;
 +import javax.swing.UIManager;
 +import javax.swing.border.EtchedBorder;
 +
 +
 +public class CheckMenuItem extends JFrame {
 +
 +
 +    private JLabel statusbar;
 +
 +    public CheckMenuItem() {
 +
 +        setTitle("CheckBoxMenuItem");
 +
 +        JMenuBar menubar = new JMenuBar();
 +        JMenu file = new JMenu("File");
 +        file.setMnemonic(KeyEvent.VK_F);
 +
 +        JMenu view = new JMenu("View");
 +        view.setMnemonic(KeyEvent.VK_V);
 +
 +        JCheckBoxMenuItem sbar = new JCheckBoxMenuItem("Show StatuBar");
 +        sbar.setState(true);
 +
 +        sbar.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                if (statusbar.isVisible()) {
 +                    statusbar.setVisible(false);
 +                } else {
 +                    statusbar.setVisible(true);
 +                }
 +            }
 +
 +        });
 +
 +        view.add(sbar);
 +
 +        menubar.add(file);
 +        menubar.add(view);
 +
 +        setJMenuBar(menubar);
 +
 +        statusbar = new JLabel(" Statusbar");
 +        statusbar.setBorder(BorderFactory.createEtchedBorder(
 + EtchedBorder.RAISED));
 +        add(statusbar, BorderLayout.SOUTH);
 +
 +
 +        setSize(360, 250);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new CheckMenuItem(); 
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +في هذا المثال قمنا بإنشاء قائمه تحتوي على CheckBoxMenuItem , عند الضغط عليها يختفي شريط الحالة و الضغط عليها مره أخرى يُظهر الشريط مره أخرى .
 +
 +
 +
 +<code java>
 + JCheckBoxMenuItem sbar = new JCheckBoxMenuItem("Show StatuBar");
 + sbar.setState(true);
 +</code>
 +
 +
 +
 +
 +هنا قمنى بإنشاء الأداه JcheckBoxMenuItem بالإضافة إلى عنوان العنصر , و قمنا بتحديد الحاله الإفتراضية True أي أن شريط الحالة في حالة ظهور .
 +
 +
 +
 +<code java>
 + if (statusbar.isVisible()) {
 + statusbar.setVisible(false);
 + } else {
 + statusbar.setVisible(true);
 + }
 +</code>
 +
 +
 +
 +
 +الذي قمنا به هنا هو تحديد هل شريط الحاله في حالة ظهور أم لا عن طريق الـ Method الذي أسمه isVisible , فإذا كان العائد هو القيمه True فتصبح حالة الظهور False و إذا عاد الـ Method بالقيمه False فتكون الحاله True.
 +
 +
 +
 +
 +<code java>
 + statusbar = new JLabel(" Statusbar");
 + statusbar.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
 +</code>
 +
 +
 +
 +
 +شريط الحاله هنا مجرد عنصر Jlabel عادي , فقمنا بإنشائه و تسميته  Statusbar , فالسطر الثاني قمنا بعمل إطار بارز حوله , في السطر الثالث قمنا بتحديد مكان شريط الحاله .
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/checkboxmenuitem.jpg |JCheckBoxMenuItem}}
 +
 +
 +
 +==== قوائم الـ popup ====
 +
 +
 +
 +
 +هناك نوع أخر من القوائم وهو الـ Popup , و تسمى أيضاً Context , دائماً ما نُشاهدها عند الضغط بالزر الأيمن على أحد العناصر , فكرتها هي تزويد المستخدم بالتحكم في العنصر المحدد , مثلاً الصور عند الضغط عليها نحصل على قائمه Context تحتوي على حفظ , دوران , تحريك ….. إلخ .
 +
 +في المثال التالي سنحصل على قائمه صغيره صغيره تحتوي على عنصرين الأول يقوم بإصدار صوت من الجهاز و الثاني يقوم بإغلاق البرنامج .
 +
 +
 +
 +
 +<code java>
 +import java.awt.Toolkit;
 +
 +import javax.swing.*;
 +import java.awt.event.*;
 +
 +public class PopupMenu {
 +
 +    private JPopupMenu menu;
 +    private Toolkit toolkit;
 +
 +  public PopupMenu(){
 +
 +
 +    JFrame frame = new JFrame("JPopupMenu");
 +    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +
 +    toolkit = frame.getToolkit();
 +
 +    menu = new JPopupMenu();
 +    JMenuItem menuItemBeep = new JMenuItem("Beep");
 +
 +    menuItemBeep.addActionListener(new ActionListener() {
 +        public void actionPerformed(ActionEvent e) {
 +            toolkit.beep();
 +        }
 +    });
 +
 +    menu.add(menuItemBeep);
 +
 +    JMenuItem menuItemClose = new JMenuItem("Close");
 +    menuItemClose.addActionListener(new ActionListener() {
 +        public void actionPerformed(ActionEvent e) {
 +            System.exit(0);
 +        }
 +
 +    });
 +
 +    menu.add(menuItemClose);
 +
 +    frame.addMouseListener(new MouseAdapter() {
 +        public void mouseReleased(MouseEvent e) {
 +            if (e.getButton() == e.BUTTON3) {
 +                menu.show(e.getComponent(), e.getX(), e.getY());
 +            }
 +        }
 +    });
 +
 +    frame.setSize(250, 200);
 +    frame.setLocationRelativeTo(null);
 +    frame.setVisible(true);
 +  }
 +
 +
 +
 +  public static void main(String[] args) {
 +        new PopupMenu();
 +  }
 +}
 +</code>
 +
 +
 +
 +بالطبع يُمكن معاملتها معاملة القوائم Menu العاديه , حيث يُمكن إنشاء صور و فواصل و قوائم فرعيه أخره لها .
 +
 +
 +<code java>
 + menu = new JPopupMenu();
 +</code>
 +
 +
 +
 +
 +قمنا هنا بإنشاء الـ Popup , من الـ Class الذي أسمه JpopupMenu.
 +
 +
 +
 +
 +<code java>
 + JMenuItem menuItemBeep = new JMenuItem("Beep");
 +</code>
 +
 +
 +
 +
 +هذا عنصر من عناصر الـ Popup قمنا بإنشائه , وهو تماماً مثل الـ menu العاديه .
 +
 +
 +
 +
 +<code java>
 + frame.addMouseListener(new MouseAdapter() {
 +     public void mouseReleased(MouseEvent e) {
 +         if (e.getButton() == e.BUTTON3) {
 +             menu.show(e.getComponent(), e.getX(), e.getY());
 +         }
 +     }
 + });
 +</code>
 +
 +
 +
 +
 +قمنا هنا بإنشاء حدث ظهور القائمه Popup عن الضغط على زر Button3 على الفأره , وسيتم الظهور في نفس مكان الضغط .
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/popupmenu.jpg |Popup menu}}
 +
 +
 +
 +
 +==== JToolbar ====
 +
 +
 +
 +
 +بعد التطرق إلى القوائم و عرفة كيفية إنشائها , نأتي الأن إلى شريط الأدوات ToolBar حيث أنه يوفر الوقت و البحث عن عنصر أو أمر معين يكثر أستخدامه , وتوفر لنا لغة Java في مكتبة Swing الأداه Jtoolbar حيث يتم إنشاء شريط الأدوات عن طريقها .
 +
 +سنقوم الأن بإنشاء شريط أدوات يحتوي على زر واحد للخروج
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JMenu;
 +import javax.swing.JMenuBar;
 +import javax.swing.JToolBar;
 +
 +
 +public class SimpleToolbar extends JFrame {
 +
 +
 +    public SimpleToolbar() {
 +
 +        setTitle("SimpleToolbar");
 +
 +        JMenuBar menubar = new JMenuBar();
 +        JMenu file = new JMenu("File");
 +        menubar.add(file);
 +        setJMenuBar(menubar);
 +
 +        JToolBar toolbar = new JToolBar();
 +
 +        ImageIcon icon = new ImageIcon(getClass().getResource("exit.png"));
 +
 +        JButton exit = new JButton(icon);
 +        toolbar.add(exit);
 +        exit.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                System.exit(0);
 +            }
 +
 +        });
 +
 +
 +        add(toolbar, BorderLayout.NORTH);
 +
 +        setSize(300, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new SimpleToolbar();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +نأتي للشرح 
 +
 +
 +
 +
 +<code java>
 + JToolBar toolbar = new JToolBar();
 +</code>
 +
 +
 +
 +
 +هذه طريقة إنشاء الـ Toolbar , وهي تُشبه طريقة إنشاء أي عنصر 
 +
 +
 +
 +
 +<code java>
 + JButton exit = new JButton(icon);
 + toolbar.add(exit);
 +</code>
 +
 +
 +
 +
 +قمنا بإنشاء زر و أضفناه إلى الـ Toolbar الذي قمنا بإنشائه .
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/simpletoolbar.jpg |Simple JToolBar}}
 +
 +
 +
 +=== Toolbars ===
 +
 +
 +
 +
 +
 +نفترض الأن أننا أردنا أن نقوم بإنشاء إثنين من شريط الأدوات .
 +سنقوم بالتالي :
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.BoxLayout;
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.JToolBar;
 +
 +
 +public class Toolbars extends JFrame {
 +
 +    public Toolbars() {
 +
 +        setTitle("Toolbars");
 +
 +        JToolBar toolbar1 = new JToolBar();
 +        JToolBar toolbar2 = new JToolBar();
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
 +
 +        ImageIcon newi = new ImageIcon(
 + getClass().getResource("new.png"));
 +        ImageIcon open = new ImageIcon(
 + getClass().getResource("open.png"));
 +        ImageIcon save = new ImageIcon(
 + getClass().getResource("save.png"));
 +        ImageIcon exit = new ImageIcon(
 + getClass().getResource("exit.png"));
 +
 +        JButton newb = new JButton(newi);
 +        JButton openb = new JButton(open);
 +        JButton saveb = new JButton(save);
 +
 +        toolbar1.add(newb);
 +        toolbar1.add(openb);
 +        toolbar1.add(saveb);
 +        toolbar1.setAlignmentX(0);
 +
 +        JButton exitb = new JButton(exit);
 +        toolbar2.add(exitb); 
 +        toolbar2.setAlignmentX(0);
 +
 +        exitb.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                System.exit(0);
 +            }
 +
 +        });
 +
 +        panel.add(toolbar1);
 +        panel.add(toolbar2);
 +
 +        add(panel, BorderLayout.NORTH);
 +
 +        setSize(300, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new Toolbars();
 +    }
 +}
 +</code>
 +
 +
 +
 +الهدف واحد وهو كيفية إنشاء الـ Toolbar , لكن لا مانع من أستخدام بعض الإمكانيات , ثما قمنا بوضع الـ Jpanel في يسار مدير الـ BorderLayout, ثما قمنا بوضعهم مُتوازي في الـ BoxLayout (Y_AXIS) , وبهذا تم وضع إثنين من الـ Toolbar في الـ Panel .
 +
 +
 +
 +<code java>
 + JToolBar toolbar1 = new JToolBar();
 + JToolBar toolbar2 = new JToolBar();
 +</code>
 +
 +
 +
 +
 +في السطرين السابقين قمنا بإنشاء الـ Toolbars .
 +
 +
 +
 +
 +<code java>
 + JPanel panel = new JPanel();
 + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
 +</code>
 +
 +
 +
 +
 +قمنا هنا بجعل الـ Panel مُتوازي في الـ BoxLayout
 +
 +
 +
 +
 +<code java>
 + toolbar1.setAlignmentX(0);
 +</code>
 +
 +
 +
 +الـ Toolbar موضعه على اليسار .
 +
 +
 +
 +
 +<code java>
 + panel.add(toolbar1);
 + panel.add(toolbar2);
 +
 + add(panel, BorderLayout.NORTH);
 +</code>
 +
 +
 +
 +
 +في النهاية تم وضع الـ Panel كلياً في الجزء الشمالي من الـ Frame.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/toolbars.jpg |Toolbars}}
 +
 +
 +=== إنشاء Toolbar عمودي ===
 +
 +
 +
 +
 +المِثال التالي يقوم بشرح كيفية إنشاء Toolbar عمودي .
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JToolBar;
 +import javax.swing.UIManager;
 +
 +
 +public class VerticalToolbar extends JFrame {
 +
 +
 +    public VerticalToolbar() {
 +
 +        setTitle("Vertical toolbar");
 +
 +        JToolBar toolbar = new JToolBar(JToolBar.VERTICAL);
 +
 +        ImageIcon select = new ImageIcon(
 + getClass().getResource("select.gif"));
 +        ImageIcon freehand = new ImageIcon(
 + getClass().getResource("freehand.gif"));
 +        ImageIcon shapeed = new ImageIcon(
 + getClass().getResource("shapeed.gif"));
 +        ImageIcon pen = new ImageIcon(
 + getClass().getResource("pen.gif"));
 +        ImageIcon rectangle = new ImageIcon(
 + getClass().getResource("rectangle.gif"));
 +        ImageIcon ellipse = new ImageIcon(
 + getClass().getResource("ellipse.gif"));
 +        ImageIcon qs = new ImageIcon(
 + getClass().getResource("qs.gif"));
 +        ImageIcon text = new ImageIcon(
 + getClass().getResource("text.gif"));
 +
 +        JButton selectb = new JButton(select);
 +        JButton freehandb = new JButton(freehand);
 +        JButton shapeedb = new JButton(shapeed);
 +        JButton penb = new JButton(pen);
 +        JButton rectangleb = new JButton(rectangle);
 +        JButton ellipseb = new JButton(ellipse);
 +        JButton qsb = new JButton(qs);
 +        JButton textb = new JButton(text);
 +
 +        toolbar.add(selectb);
 +        toolbar.add(freehandb);
 +        toolbar.add(shapeedb);
 +        toolbar.add(penb);
 +        toolbar.add(rectangleb);
 +        toolbar.add(ellipseb);
 +        toolbar.add(qsb);
 +        toolbar.add(textb);
 +
 +        add(toolbar, BorderLayout.WEST);
 +
 +        setSize(250, 350);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        try {
 +            UIManager.setLookAndFeel(
 +                UIManager.getSystemLookAndFeelClassName());
 +        } 
 +        catch (Exception e) {
 +            System.out.println("Error:" + e.getStackTrace());
 +        }
 +        new VerticalToolbar();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +في هذا المثال قمنا بإنشاء شريط أدوات و قمنى بوضعه في يسار النافذه , تماماً مثل برامج معالجة الصور مثل Xara Extreme أو Inkscape .
 +
 +
 +
 +<code java>
 + JToolBar toolbar = new JToolBar(JToolBar.VERTICAL);
 +</code>
 +
 +
 +
 +
 +في هذا السطر قمنا بإنشاء شريط أدوات طولي .
 +
 +
 +
 +
 +<code java>
 + add(toolbar, BorderLayout.WEST);
 +</code>
 +
 +
 +
 +
 +وهنا قمنا بتحديد موضع البار في يسار النافذه .
 +
 +
 +
 +<code java>
 + UIManager.setLookAndFeel(
 +     UIManager.getSystemLookAndFeelClassName());
 +</code>
 +
 +
 +
 +
 +قمنا هنا بجعل البرنامج خاضع للنظام في الـ Look and Feel , لأن الأزرار ليسة شفافه مما قد يكون شكلها سيء في النماذج الأخرى .
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/verticaltoolbar.jpg |Vertical toolbar}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +=====إدارة الطبقات في الـ Swing =====
 +
 +
 +للـ Java Swing نوعين من العناصر , الأول يكون ( الأصل/الأب) و الثاني ( الفرع/الأبن) , توضع العناصر السابقه في Layout , بأستخدام الـ Layout Managers , وتعتبر من أصعب الأجزاء في وجهة الإستخدام GUI الحديثه , وتنال قدر كبير من الإحترام لدى كثير من المبرمجين . 
 +وهناك عرض من ZetCode لكتاب يشرح أستخدام الـ Swing Layout Manager عدد صفحاته 196 .
 +
 +
 +<a href="/ebooks/javaswinglayout">Java Swing layout management tutorial</a> 
 +
 +
 +
 +
 +
 +==== No manager ====
 +
 +
 +
 +بالإمكان العمل دون الـ Layout Manager إذا أردنا ذالك , وفي المثال التالي لن نحتاج إليه , وقد نكتب أكواد لا تحتاج إلى إداره 
 +, وهذا لتجنب التعقيد في الكود , لكن لجعله إحترافي لابد من إستخدام التعقيدات ..
 +بدون الـ Layout Manager ستكون مواضع الأدوات بقيم مُطلقه .
 +
 +
 +
 +<code java>
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +
 +
 +public class Absolute extends JFrame {
 +
 +
 +    public Absolute() {
 +
 +        setTitle("Absolute positioning");
 +
 +        setLayout(null);
 +
 +        JButton ok = new JButton("OK");
 +        ok.setBounds(50, 150, 80, 25);
 +
 +        JButton close = new JButton("Close");
 +        close.setBounds(150, 150, 80, 25);
 +
 +        add(ok);
 +        add(close);
 +
 +        setSize(300, 250);
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new Absolute();
 +    }
 +}
 +</code>
 +
 +
 +
 +هذا المثال يُوضح زرين في النافذه فقط .
 +
 +
 +
 +<code java>
 + setLayout(null);
 +</code>
 +
 +
 +
 +
 +قمنا يتحديد موضع بقيمه مطلقه وهي Null في الـ Method الذي أسمه setLayout.
 +
 +
 +
 +<code java>
 + ok.setBounds(50, 150, 80, 25);
 +</code>
 +
 +
 +
 +setBounds تحدد موضع زر OK عن طريق إحداثيات X , Y و الطول و العرض .
 +
 +
 +==== FlowLayout manager ====
 +
 +
 +سنستعرض الأن أبسط أسلوب للتعامل مع الـ Layout Manger في الـ Swing , الفكره الرئيسيه للـ Layout Manger هي عدم دمج العناصر مع بعضها البعض , وهذا بعد تعديل المساحات و المقاسات للعناصر , فهو يمنح كل عنصر حجمة الطبيعي و المستحسن له , كما أنه يضع العناصر في ROW بالترتيب وفي الأماكن الـتي تُحدد له , أما إذا لم تضعها في Row فسيتم وضعها بعد الـ Layout , كما أنها تسمح لك أيضاً برص العناصر سواء يمين أو يسار أو في المنتصف و تكون إفتراضياً في المنتصف بالإضافه إلى ترك مسافه بين العنصر و الأخر 5px و بينها وبين الإطار الموضوعه فيه .
 +
 +
 +
 +<code java>
 + FlowLayout()
 + FlowLayout(int align)
 + FlowLayout(int align, int hgap, int vgap) 
 +</code>
 +
 +
 +
 +هذه البنيات مُتوفره في الـ FlowLayout , ويتم إنشائها في الأول بقيم غير صحيحه إفتراضيه , متمركزه وبفراغات 5px , هنا مدراء تسمح لك بتحديد هذه الباراميتر .
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.JTextArea;
 +import javax.swing.JTree;
 +
 +
 +public class FlowLayoutExample extends JFrame {
 +
 +
 +    public FlowLayoutExample() {
 +
 +        setTitle("FlowLayout Example");
 +
 +        JPanel panel = new JPanel();
 +
 +        JTextArea area = new JTextArea("text area");
 +        area.setPreferredSize(new Dimension(100, 100));
 +
 +        JButton button = new JButton("button");
 +        panel.add(button);
 +
 +        JTree tree = new JTree();
 +        panel.add(tree);
 +
 +        panel.add(area);
 +
 +        add(panel);
 +
 +        pack();
 +
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new FlowLayoutExample();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +في هذا المثال نقوم بإنشاء زر و أدات الشجره و مربع نص , النقطه التي يجب الإنتباه لها , أنه عند عمل أدات الشجره بدون قيم محدده , فيتم وضع قيم إفتراضيه لها .
 +
 +
 +
 +<code java>
 + JPanel panel = new JPanel();
 +</code>
 +
 +
 +
 +يقوم الـ Layout Manager في Jpanel  بتضمين العناصر تلقائياً دون تدخل .
 +
 +
 +<code java>
 + JTextArea area = new JTextArea("text area");
 + area.setPreferredSize(new Dimension(100, 100));
 +</code>
 +
 +
 +سيقوم الـ Layout Manager بإضافة مربع النص بحجم ممتاز ( المستحسن ) , وهذا يعني , أننا أحرار في تحديد حجم العناصر فهنا حددنا مساحة مربع النص بـ 100px × 100px , فإذا قمنا بإلغاء السطر الثاني سيتم تحديد مساحة مربع النص على حسب النص الموجود بداخلها ليس أكثر من هذا ولا أقل , وبدون النص , فستكون النتيجه هي إختفاء العنصر تماماً , أو قم بتجربة زيادة نص فوق الموجود دون تحديد المساحة , ستكون النتيجه أن العنصر سيمتدد أو يتقلص على حسب النص الموجود .
 +
 +
 +
 +
 +<code java>
 + panel.add(area);
 +</code>
 +
 +
 +هنا قمنا بإضافة العنصر للـ panel تمهيداً لإضافتها في النافذه الرئيسية وهذا ببساطه عن طريق الأمر add
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/flowlayout.png |FlowLaout manager}}
 +
 +
 +
 +==== GridLayout ====
 +
 +
 +
 +يعتبر هو المسؤل عن تحديد عنصر في شبكة على شكل مستطيل , فهو يجعل النافذه مقسمه إلى مستطيلات متساوية الحجم , بحيث يكون هناك عنصر واحد في كل مستطيل .
 +
 +
 +
 +<code java>
 +import java.awt.GridLayout;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +
 +
 +public class GridLayoutExample extends JFrame {
 +
 +    public GridLayoutExample() {
 +
 +        setTitle("GridLayout");
 +
 +        JPanel panel = new JPanel();
 +
 +        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 +        panel.setLayout(new GridLayout(5, 4, 5, 5));
 +
 +        String[] buttons = {
 +            "Cls", "Bck", "", "Close", "7", "8", "9", "/", "4", 
 +            "5", "6", "*", "1", "2", "3", "-", "0", ".", "=", "+"
 +        };
 +
 +
 +        for (int i = 0; i < buttons.length; i++) {
 +
 +            if (i == 2) 
 +                panel.add(new JLabel(buttons[i]));
 +            else 
 +                panel.add(new JButton(buttons[i]));
 +        }
 +
 +        add(panel);
 +
 +        setSize(350, 300);
 +
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +
 +    }
 +
 +    public static void main(String[] args) {
 +        new GridLayoutExample();
 +    }
 +}
 +</code>
 +
 +
 +
 +هذا المثال يُوضح لك كيفية إنشاء هيكل للآله الحاسبه , وتعتبر مثال جيد لفهم الـ Layout Manager , فقد قمنا بإضافة 19 زر و Label واحده في الـ Layout Manager , وكل الأزرار في مقاس واحد .
 +
 +
 +
 +<code java>
 + panel.setLayout(new GridLayout(5, 4, 5, 5));
 +</code>
 +
 +
 +
 +هنا قمنا بوضع GridLayout في عنصر الـ Panel والـ Layout يأخذ أربع براميتر ( الأول : عدد الصفوف , الثاني : عدد الأعمده , الثالث و الرابع : المسافات الطوليه و العرضيه بين العناصر وبعضها ) .
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/gridlayout.png |GridLayout manager}}
 +
 +
 +
 +==== BorderLayout ====
 +
 +
 +
 +يعتبر الـ BorderLayout من الأدوات المفيده , فهو يقوم بتقسيم المسافات إلى خمسة مناطق شمال و غرب و جنوب و شرق و وسط , وكل منطقه تحتوي على عنصرواحد فقط , أما إذا كنت تُود إضافة المزيد من العناصر في المنطقه الواحده , فبإمكانك وضع Panel فهذا سيكون منظم أكثر في هذه الحاله , في العناصر التي في المناطق الـ N W S E تأخذ حجم مميز لها , أما العنصر الأوسط فيأخذ كامل مساحة اليسار.
 +و يبدو بشكل غير جيد , خصوصاً إذا كانت العناصر قريبه جداً من بعضها , فمن المفترض وضع مسافه بينهم .
 +في الـ Swing Toolkit هناك إمكانيه لوضع إطار حول العناصر , ولإنشاء بوردر(Border) , فإما نقوم بطلب إنشاء كلاس جديد EmptyBorder أو نستخدم BorderFactory , لكن هناك إضافه على الـ EmptyBotder أنه يستخدم نوع أخر من الـ Border , لكن للـ Layout Manager سنستخدم واحده فقط .
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Color;
 +import java.awt.Dimension;
 +import java.awt.Insets;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.border.EmptyBorder;
 +
 +
 +public class BorderExample extends JFrame {
 +
 +
 +    public BorderExample() {
 +
 +        setTitle("Border Example");
 +
 +        JPanel panel = new JPanel(new BorderLayout());
 +        JPanel top = new JPanel();
 +
 +        top.setBackground(Color.gray);
 +        top.setPreferredSize(new Dimension(250, 150));
 +        panel.add(top);
 +
 +        panel.setBorder(new EmptyBorder(new Insets(20, 20, 20, 20)));
 +
 +        add(panel);
 +
 +        pack();
 +
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new BorderExample();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +هذا المثال سيقوم بإظهار مربع Panel رمادي اللون وحوله إطار Border .
 +
 +
 +
 +
 +<code java>
 + JPanel panel = new JPanel(new BorderLayout());
 + JPanel top = new JPanel();
 +</code>
 +
 +
 +
 +
 +قمنا بوضع Panel في Panel , وإستخدمنا BorderLayout في الـ Panel الأول , لأن الـ border سيقوم بإعادة تحجيم العنصر التابع له .
 +
 +
 +
 +<code java>
 + panel.add(top);
 +</code>
 +
 +
 +
 +
 +هنا قمنا بوضع الـ Panel المسمى Top داخل العنصر Panel , بصوره أوضح , قمنا بوضعها في منتصف العنصر BorderLayout
 +
 +
 +
 +<code java>
 + panel.setBorder(new EmptyBorder(new Insets(20, 20, 20, 20)));
 +</code>
 +
 +
 +
 +
 +هنا قمنا بعمل Border بمقاس 20px في كل الأطراف , وتأخذ الترتيب عكس عقارب الساعه أي تكون بالترتيب 
 +Top,left,buttom,right
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/borderexample.png |Border example}}
 +
 +
 +
 +
 +
 +
 +المثال التالي سنتعرف على طريقة إستعمال نموذجيه للـ BorderLayout
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Dimension;
 +import java.awt.Insets;
 +
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JMenu;
 +import javax.swing.JMenuBar;
 +import javax.swing.JTextArea;
 +import javax.swing.JToolBar;
 +import javax.swing.border.EmptyBorder;
 +import javax.swing.border.LineBorder;
 +
 +
 +public class BorderLayoutExample extends JFrame {
 +
 +
 +    public BorderLayoutExample() {
 +
 +        setTitle("BorderLayout");
 +
 +        JMenuBar menubar = new JMenuBar();
 +        JMenu file = new JMenu("File");
 +
 +        menubar.add(file);
 +        setJMenuBar(menubar);
 +
 +        JToolBar toolbar = new JToolBar();
 +        toolbar.setFloatable(false);
 +
 +        ImageIcon exit = new ImageIcon("exit.png");
 +        JButton bexit = new JButton(exit);
 +        bexit.setBorder(new EmptyBorder(0 ,0, 0, 0));
 +        toolbar.add(bexit);
 +
 +        add(toolbar, BorderLayout.NORTH);
 +
 +        JToolBar vertical = new JToolBar(JToolBar.VERTICAL);
 +        vertical.setFloatable(false);
 +        vertical.setMargin(new Insets(10, 5, 5, 5));
 +
 +        ImageIcon select = new ImageIcon("drive.png");
 +        ImageIcon freehand = new ImageIcon("computer.png");
 +        ImageIcon shapeed = new ImageIcon("printer.png");
 +
 +        JButton selectb = new JButton(select);
 +        selectb.setBorder(new EmptyBorder(3, 0, 3, 0));
 +
 +        JButton freehandb = new JButton(freehand);
 +
 +        freehandb.setBorder(new EmptyBorder(3, 0, 3, 0));
 +        JButton shapeedb = new JButton(shapeed);
 +        shapeedb.setBorder(new EmptyBorder(3, 0, 3, 0));
 +
 +        vertical.add(selectb);
 +        vertical.add(freehandb);
 +        vertical.add(shapeedb);
 +
 +        add(vertical, BorderLayout.WEST);
 +
 +        add(new JTextArea(), BorderLayout.CENTER);
 +
 +        JLabel statusbar = new JLabel(" Statusbar");
 +        statusbar.setPreferredSize(new Dimension(-1, 22));
 +        statusbar.setBorder(LineBorder.createGrayLineBorder());
 +        add(statusbar, BorderLayout.SOUTH);
 +
 +        setSize(350, 300);
 +
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new BorderLayoutExample();
 +    }
 +}
 +</code>
 +
 +
 +
 +هذا المثال يعرض هيكل لنموذج جيد الإستخدام , بالإضافة إستخدام شريط الأدوات الأفقي و الرأسي , و شريط الحاله و مربع النص الموجود في المنطقه الوسطى .
 +
 +
 +الـ Layout الإفتراضي في النموذج Jframe هو BorderLayout لذالك لن نحتاج لإضافته .
 +
 +
 +
 +
 +<code java>
 + add(toolbar, BorderLayout.NORTH);
 +</code>
 +
 +
 +
 +
 +قمنا بإضافة شريط الأدوات في الشمال الـ Layout
 +
 +
 +
 +
 +<code java>
 + add(vertical, BorderLayout.WEST); 
 +</code>
 +
 +
 +
 +
 +قمنا بإضافة شريط الأدوات vertical إلى أعلى الـ Layout
 +
 +
 +
 +
 +<code java>
 + add(new JTextArea(), BorderLayout.CENTER);
 +</code>
 +
 +
 +
 +
 +قمنا بإضافة مربع النص إلى منتصف الـ Layout
 +
 +
 +
 +
 +<code java>
 + add(statusbar, BorderLayout.SOUTH);
 +</code>
 +
 +
 +
 +
 +قمنا بإضافة شريط الحاله أسفل الـ Layout
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/borderlayout.png |BorderLayout manager}}
 +
 +
 +
 +==== BoxLayout ====
 +
 +
 +
 +تعتبر هذه الأداه من أقوى مدراء الطبقات , فهو يسمح لك بعمل Layout متطوره , فهو يسمح بإضافة العنصر سواء في الـ row أو الـ column . ويدعم الـ nesting بشكل قوي و مميز , مما يجعله مرن جدا في التعامل معه , بصوره أوضح , هو يسمح لك بوضع Box Layout داخل BoxLayout مما يُشكل شبكه كبيره من الـ Layout .
 +عادتاً ما يستخدم الـ Box Layout Manager الكلاس Class أسمه Box , هذا الكلاس يقوم بإنشاء عناصر غير ظاهره , مما يُعطي التأثيرات على الطبقات Layout .
 +
 +- glue
 +- strut
 +- rigid area
 +دعنا نبدء الأن ..
 +ما نريده هو وضع زرين في أقصى يمين النافذه في الأسفل بالإعتماد على الـ Box Layout .
 +
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +
 +import javax.swing.Box;
 +import javax.swing.BoxLayout;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class TwoButtons extends JFrame {
 +
 +    public TwoButtons() {
 +
 +        setTitle("Two Buttons");
 +
 +        JPanel basic = new JPanel();
 +        basic.setLayout(new BoxLayout(basic, BoxLayout.Y_AXIS));
 +        add(basic);
 +
 +        basic.add(Box.createVerticalGlue());
 +
 +        JPanel bottom = new JPanel();
 +        bottom.setAlignmentX(1f);
 +        bottom.setLayout(new BoxLayout(bottom, BoxLayout.X_AXIS));
 +
 +        JButton ok = new JButton("OK");
 +        JButton close = new JButton("Close");
 +
 +        bottom.add(ok);
 +        bottom.add(Box.createRigidArea(new Dimension(5, 0)));
 +        bottom.add(close);
 +        bottom.add(Box.createRigidArea(new Dimension(15, 0)));
 +
 +        basic.add(bottom);
 +        basic.add(Box.createRigidArea(new Dimension(0, 15)));
 +
 +        setSize(300, 250);
 +
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +
 +    }
 +
 +    public static void main(String[] args) {
 +        new TwoButtons();
 +    }
 +}
 +</code>
 +
 +
 +
 +ما قمنا به الأن هو تفسير لهذه الرسمه 
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/twobuttons.png |Two buttons}}
 +
 +
 +
 +
 +
 +قمنا بإنشاء قائمتين panels , الأولى basic و هي BoxLayout عمودي و الثاني bottom أفقي , وقمنى بوضع الـ bottom في الـ basic , قمنى بمحاذات إلى اليمين الـ Panel bottom , المسافه بين أعلى النافذه و الـ Panel bottom مسافه قابله للتوسع , و التي يتولها glue.
 +
 +
 +
 +
 +<code java>
 + basic.setLayout(new BoxLayout(basic, BoxLayout.Y_AXIS));
 +</code>
 +
 +
 +
 +
 +بعد إنشاء Basic Panel بالطريقة المعتاده قمنا بوضعها طولياً في الـ BoxLayout.
 +
 +
 +
 +
 +
 +<code java>
 + JPanel bottom = new JPanel();
 + bottom.setAlignmentX(1f);
 + bottom.setLayout(new BoxLayout(bottom, BoxLayout.X_AXIS));
 +</code>
 +
 +
 +
 +
 +الـ bottom Panel قمنى بوضعها في اليمين عن طريق أستخدام اmethod المسمى  setAlignmentX , فالـ Panel أصبح أفقي .
 +
 +
 +قمنا بوضع الـ Panel الذي به الأزرار في الـ Panel الأساسي و المسمى basic
 +<code java>
 + bottom.add(Box.createRigidArea(new Dimension(5, 0)));
 +</code>
 +
 +
 +
 +
 +وضعنا مسافه بين الزرين و الـ Panel 
 +
 +
 +
 +
 +<code java>
 + basic.add(bottom);
 +</code>
 +
 +
 +
 +قمنا بوضع الـ Panel الذي به الأزرار في الـ Panel الأساسي و المسمى basic
 +
 +
 +
 +
 +<code java>
 + basic.add(Box.createRigidArea(new Dimension(0, 15)));
 +</code>
 +
 +
 +
 +وضعنا مسافه بين الزرين و الـ Panel 
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/twobuttons2.png |Two buttons}}
 +
 +
 +
 +
 +
 +عند إستعمال مدير BoxLayout , فبإمكاننا وضع مناطق ثابته الحجم بين عناصرنا . 
 +
 +
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +
 +import java.awt.Insets;
 +
 +import javax.swing.Box;
 +import javax.swing.BoxLayout;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.border.EmptyBorder;
 +
 +
 +public class RigidArea extends JFrame {
 +
 +    public RigidArea() {
 +
 +        setTitle("RigidArea");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
 +
 +        panel.setBorder(new EmptyBorder(new Insets(40, 60, 40, 60)));
 +
 +        panel.add(new JButton("Button"));
 +        panel.add(Box.createRigidArea(new Dimension(0, 5)));
 +        panel.add(new JButton("Button"));
 +        panel.add(Box.createRigidArea(new Dimension(0, 5)));
 +        panel.add(new JButton("Button"));
 +
 +        panel.add(Box.createRigidArea(new Dimension(0, 5)));
 +        panel.add(new JButton("Button"));
 +
 +        add(panel);
 +
 +        pack();
 +
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new RigidArea();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +في هذا المثال قمنا بإضافة أربعة أزرار , و بصوره إفتراضيه قمنا بعدم وضع أي مسافات بينهم , ولوضع بعض المسافات بينهم , قمنا بإستخدام rigid area .
 +
 +
 +<code java>
 + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
 +</code>
 +
 +
 +
 +
 +قمنا بإستخدام الشكل العمودي لـ BoxLayout في الـ Panel
 +
 +
 +
 +
 +<code java>
 + panel.add(new JButton("Button"));
 + panel.add(Box.createRigidArea(new Dimension(0, 5)));
 + panel.add(new JButton("Button"));
 +</code>
 +
 +
 +
 +
 +في هذه السطور قمنا بإنشاء الأزرار و قمنا بإضافة مسافه ثابته عن طريق createRigidArea بين الزرين .
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/rigidarea.png |Rigid area}}
 +
 +
 +
 +
 +==== Tip of the Day ====
 +
 +
 +
 +
 +Jdeveloper هي إطار من نوع Dialog يُطلق عليه أسم ( Tip of the Day ) أو نصيحة اليوم .
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/tipofday1.png |Tip of the Day}}
 +
 +
 +
 +
 +
 +سنقوم الأن بعمل Dialog صغير بإستخدام مجموعة مختلفة من الـ Layout Manager , التي بأسماء 
 +Border Layout , flow Layout , box Layout
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Color;
 +import java.awt.Dimension;
 +import java.awt.FlowLayout;
 +import java.awt.event.KeyEvent;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.BoxLayout;
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JCheckBox;
 +import javax.swing.JDialog;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +import javax.swing.JSeparator;
 +import javax.swing.JTextPane;
 +
 +
 +public class TipOfDay extends JDialog {
 +
 +
 +    public TipOfDay() {
 +
 +        setTitle("Tip of the Day");
 +
 +        JPanel basic = new JPanel();
 +        basic.setLayout(new BoxLayout(basic, BoxLayout.Y_AXIS));
 +        add(basic);
 +
 +        JPanel topPanel = new JPanel(new BorderLayout(0, 0));
 +        topPanel.setMaximumSize(new Dimension(450, 0));
 +        JLabel hint = new JLabel("JDeveloper Productivity Hints");
 +        hint.setBorder(BorderFactory.createEmptyBorder(0, 25, 0, 0));
 +        topPanel.add(hint);
 +
 +        ImageIcon icon = new ImageIcon("jdev.png");
 +        JLabel label = new JLabel(icon);
 +        label.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 +        topPanel.add(label, BorderLayout.EAST);
 +
 +        JSeparator separator = new JSeparator();
 +        separator.setForeground(Color.gray);
 +
 +        topPanel.add(separator, BorderLayout.SOUTH);
 +
 +        basic.add(topPanel);
 +
 +        JPanel textPanel = new JPanel(new BorderLayout());
 +        textPanel.setBorder(BorderFactory.createEmptyBorder(15, 25, 15, 25));
 +        JTextPane pane = new JTextPane();
 +
 +        pane.setContentType("text/html");
 +        String text = "&lt;p&gt;&lt;b&gt;Closing windows using the mouse wheel&lt;/b&gt;&lt;/p&gt;" +
 +            "&lt;p&gt;Clicking with the mouse wheel on an editor tab closes the window. " +
 +            "This method works also with dockable windows or Log window tabs.&lt;/p&gt;";
 +        pane.setText(text);
 +        pane.setEditable(false);
 +        textPanel.add(pane);
 +
 +        basic.add(textPanel);
 +
 +        JPanel boxPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0));
 +
 +        JCheckBox box = new JCheckBox("Show Tips at startup");
 +        box.setMnemonic(KeyEvent.VK_S);
 +
 +        boxPanel.add(box);
 +        basic.add(boxPanel);
 +
 +        JPanel bottom = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 +
 +        JButton ntip = new JButton("Next Tip");
 +        ntip.setMnemonic(KeyEvent.VK_N);
 +        JButton close = new JButton("Close");
 +        close.setMnemonic(KeyEvent.VK_C);
 +
 +        bottom.add(ntip);
 +        bottom.add(close);
 +        basic.add(bottom);
 +
 +        bottom.setMaximumSize(new Dimension(450, 0));
 +
 +        setSize(new Dimension(450, 350));
 +        setResizable(false);
 +        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +
 +    public static void main(String[] args) {
 +        new TipOfDay();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +هذا المثال قمنا فيه بإستخدام مجموعه من الـ Layout Managers , وببساطة قمنا بوضع أربع قوائم Panel في قائمة Panel عموديه أساسيه .
 +
 +
 +
 +
 +<code java>
 + JPanel basic = new JPanel();
 + basic.setLayout(new BoxLayout(basic, BoxLayout.Y_AXIS));
 + add(basic);
 +</code>
 +
 +
 +
 +
 +قمنا بإنشاء الـ Panel الأساسي و هو موضوع في BoxLayout عرضي لكي يسمح لنا بإضافة قوائم Panel أخرى بداخله , ثما قمنا بإدخال الـ Basic Panel الذي تم إنشائه في الـ Jdialog.
 +
 +
 +<code java>
 + JPanel topPanel = new JPanel(new BorderLayout(0, 0));
 +</code>
 +
 +
 +
 +
 +هنا قمنى بإنشاء Panel لأعلى النافذه و التي سنقوم بإضافة ثلاث عناصر لها وهي عنوان النصيحه , رمز النافذه , سطر فاصل بين العناوين و بين مربع النص .
 +
 +
 +
 +<code java>
 + topPanel.setMaximumSize(new Dimension(450, 0));
 +</code>
 +
 +
 +
 +
 +قمنا بتحديد مقاس القائمة التي في الأعلى topPanel إلى أقصى عرض موجود دون تحديد الطول فجعلنه يساوي 0.
 +
 +
 +
 +<code java>
 + JPanel textPanel = new JPanel(new BorderLayout());
 + ...
 + textPanel.add(pane);
 +</code>
 +
 +
 +
 +
 +قمنا بوضع قائمة مربع النص textPanel في منتصف الـ Border , و أعطينى لها كل المساحة في اليمين و اليسار مثل ما حددنا.
 +
 +
 +<code java>
 + JPanel boxPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 20, 0));
 +</code>
 +
 +
 +
 +
 +سنقوم بإضهار زر الإختيار CheckBox في الـ boxPanel , و موضعها في اليسار , و في الـ Flow Layout قمنا بإبعاد العنصر من اليسار بمقياس 20px بينما العناصر الأخرى نبعدها بمقدار 25px , هذا يرجع إلى إن هذا النوع من الـ layout يضع مسافة إفتراضيه 5px بين العنصر و العنصر المحتضن .
 +
 +
 +
 +<code java>
 + JPanel bottom = new JPanel(new FlowLayout(FlowLayout.RIGHT));
 + ...
 + bottom.setMaximumSize(new Dimension(450, 0));
 +</code>
 +
 +
 +
 +
 +قمنا بإضهار الزرين في أقصى اليمين , و هذه القائمة من نوع FlowLayout , وحددنا القيما العضمى العرضيه على حسب عرض النافذه , وتركنا الطول يساوي 0.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/tipofday2.png |Tip of the Day}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
 +</script>
 +
 +
 +
 +
 +
 +
 +===== Java Swing Events =====
 +
 +
 +
 +
 +
 +Events are an important part in any GUI program.
 +All GUI applications are event-driven. An application reacts to different event types which are generated during it's 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.
 +In the event model, there are three participants:
 +
 +
 +
 +
 +
 +
 +  * event source
 +  * event object
 +  * event listener
 +
 +
 +
 +
 +
 +The **Event source** is the object whose state changes. It generates Events. 
 +The **Event object** (Event) encapsulates the state changes in the event source.
 +The **Event listener** is the object that wants to be notified. Event source object delegates the task of handling an event to the event listener. 
 +
 +
 +
 +
 +
 +
 +
 +Event handling in Java Swing toolkit is very powerful and flexible. Java uses Event Delegation Model.
 +We specify the objects that are to be notified when a specific event occurs.
 +
 +
 +
 +
 +
 +==== An event object ====
 +
 +
 +
 +
 +
 +When something happens in the application, an event object is created. For example, when we click on the button or select
 +an item from list. There are several types of events. An **ActionEvent**, **TextEvent**, **FocusEvent**, **ComponentEvent** etc. 
 +Each of them is created under specific conditions. 
 +
 +
 +
 +
 +
 +
 +
 +Event object has information about an event, that has happened. In the next example, we will analyze an 
 +**ActionEvent** in more detail. 
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import java.text.DateFormat;
 +
 +import java.util.Calendar;
 +import java.util.Date;
 +import java.util.Locale;
 +
 +import javax.swing.DefaultListModel;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JList;
 +import javax.swing.JPanel;
 +
 +
 +public class EventObject extends JFrame {
 +
 +
 +    private JList list;
 +    private DefaultListModel model;
 +
 +    public EventObject() {
 +
 +        setTitle("Event Object");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(null);
 +
 +        model = new DefaultListModel();
 +        list = new JList(model);
 +        list.setBounds(150, 30, 220, 150);
 +
 +        JButton ok = new JButton("Ok");
 +        ok.setBounds(30, 35, 80, 25);
 +
 +        ok.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +
 +                Locale locale = Locale.getDefault();
 +                Date date = new Date();
 +                String s = DateFormat.getTimeInstance(DateFormat.SHORT,
 +                    locale).format(date);
 +
 +                if ( !model.isEmpty() )
 +                    model.clear();
 +
 +                if (event.getID() == ActionEvent.ACTION_PERFORMED)
 +                    model.addElement(" Event Id: ACTION_PERFORMED");
 +
 +                model.addElement(" Time: " + s);
 +
 +                String source = event.getSource().getClass().getName();
 +                model.addElement(" Source: " + source);
 +
 +                int mod = event.getModifiers();
 +
 +                StringBuffer buffer = new StringBuffer(" Modifiers: ");
 +
 +                if ((mod & ActionEvent.ALT_MASK) > 0)
 +                    buffer.append("Alt ");
 +
 +                if ((mod & ActionEvent.SHIFT_MASK) > 0)
 +                    buffer.append("Shift ");
 +
 +                if ((mod & ActionEvent.META_MASK) > 0)
 +                    buffer.append("Meta ");
 +
 +                if ((mod & ActionEvent.CTRL_MASK) > 0)
 +                    buffer.append("Ctrl ");
 +
 +                model.addElement(buffer);
 +            }
 +        });
 +
 +        panel.add(ok);
 +        panel.add(list);
 +        add(panel);
 +
 +        setSize(420, 250);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new EventObject();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +The code example shows a button and a list. If we click on the button, information about the event is displayed in the list.
 +In our case, we are talking about an **ActionEvent** class. 
 +The data will be the time, when the event occured, the id of the event, the event source and the modifier keys. 
 +</b>
 +
 +<code java>
 + public void actionPerformed(ActionEvent event) {
 +</code>
 +
 +
 +
 +
 +Inside the action listener, we have an event parameter. It is the instance of the event, that has occured. In our case it is
 +an **ActionEvent**.
 +
 +
 +
 +
 +<code java>
 + cal.setTimeInMillis(event.getWhen());
 +</code>
 +
 +
 +
 +
 +Here we get the time, when the event occured. The method returns time value in milliseconds. So we must format it appropriately.
 +
 +
 +
 +
 +<code java>
 + String source = event.getSource().getClass().getName();
 + model.addElement(" Source: " + source);
 +</code>
 +
 +
 +
 +
 +Here we add the name of the source of the event to the list. In our case the source is a **JButton**.
 +
 +
 +
 +
 +<code java>
 + int mod = event.getModifiers();
 +</code>
 +
 +
 +
 +
 +We get the modifier keys. It is a bitwise-or of the modifier constants.
 +
 +
 +
 +
 +<code java>
 + if ((mod & ActionEvent.SHIFT_MASK) > 0)
 +     buffer.append("Shift ");
 +</code>
 +
 +
 +
 +
 +Here we determine, whether we have pressed a Shift key. 
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/eventobject.png |Event Object}}
 +
 +
 +==== Implementation ====
 +
 +
 +
 +
 +There are several ways, how we can implement event handling in Java Swing toolkit. 
 +
 +
 +
 +
 +<ul style="list-style-image: url(../images/bluesq.jpg); 0% 40% no-repeat; margin: 3px 0pt 3px 20px;
 + padding: 0px 0pt 1px 20px; ">
 +  * Anonymous inner class
 +  * Inner class
 +  * Derived class
 +
 +
 +
 +
 +=== Anonymous inner class ===
 +
 +
 +
 +
 +We will illustrate these concepts on a simple event example. 
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class SimpleEvent extends JFrame {
 +
 +
 +    public SimpleEvent() {
 +
 +        setTitle("Simle Event");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(null);
 +
 +        JButton close = new JButton("Close");
 +        close.setBounds(40, 50, 80, 25);
 +
 +        close.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                System.exit(0);
 +            }
 +
 +        });
 +
 +        panel.add(close);
 +        add(panel);
 +
 +        setSize(300, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new SimpleEvent();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +In this example, we have a button that closes the window upon clicking. 
 +
 +
 +
 +
 +<code java>
 + JButton close = new JButton("Close");
 +</code>
 +
 +
 +
 +
 +The button is the **event source**. It will generate events.
 +
 +
 +
 +
 +<code java>
 + close.addActionListener(new ActionListener() {
 +     public void actionPerformed(ActionEvent event) {
 +         System.exit(0);
 +     }
 + });
 +</code>
 +
 +
 +
 +
 +Here we **register** an action listener with the button. This way, the events are sent to the **event target**.
 +The event target in our case is **ActionListener** class. In this code, we use an **anonymous inner class**.
 +
 +
 +
 +
 +
 +=== Inner class ===
 +
 +
 +
 +
 +
 +Here we implement the example using an inner **ActionListener** class. 
 +
 +
 +
 +
 +<code java>
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class InnerClass extends JFrame {
 +
 +    public InnerClass() {
 +
 +        setTitle("Using inner class");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(null);
 +
 +        JButton close = new JButton("Close");
 +        close.setBounds(40, 50, 80, 25);
 +
 +        ButtonListener listener = new ButtonListener();
 +        close.addActionListener(listener); 
 +
 +        panel.add(close);
 +        add(panel);
 +
 +        setSize(300, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    class ButtonListener implements ActionListener {
 +        public void actionPerformed(ActionEvent e)
 +        {
 +            System.exit(0);
 +        }
 +      }
 +
 +    public static void main(String[] args) {
 +        new InnerClass();
 +    }
 +}
 +</code>
 +
 +
 +
 +<code java>
 + ButtonListener listener = new ButtonListener();
 + close.addActionListener(listener); 
 +</code>
 +
 +
 +
 +
 +Here we have a non anonymous inner class. 
 +
 +
 +
 +
 +<code java>
 + class ButtonListener implements ActionListener {
 +    public void actionPerformed(ActionEvent e)
 +    {
 +        System.exit(0);
 +    }
 + }
 +</code>
 +
 +
 +
 +
 +The button listener is defined here. 
 +
 +
 +
 +
 +
 +
 +=== A derived class implementing the listener ===
 +
 +
 +
 +
 +The following example will derive a class from a component and implement an action listener inside the
 +class.
 +
 +
 +
 +
 +<code java>
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class UsingInterface extends JFrame {
 +
 +
 +    public UsingInterface() {
 +
 +        setTitle("Using inner class");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(null);
 +
 +        MyButton close = new MyButton("Close");
 +        close.setBounds(40, 50, 80, 25);
 +
 +        panel.add(close);
 +        add(panel);
 +
 +        setSize(300, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    class MyButton extends JButton implements ActionListener {
 +
 +        public MyButton(String text) {
 +            super.setText(text);
 +            addActionListener(this);
 +        }
 +
 +        public void actionPerformed(ActionEvent e)
 +        {
 +            System.exit(0);
 +        }
 +
 +    }
 +
 +    public static void main(String[] args) {
 +        new UsingInterface();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +In this example, we create a MyButton class, which will implement the action listener. 
 +
 +
 +
 +
 +<code java>
 + MyButton close = new MyButton("Close");
 +</code>
 +
 +
 +
 +
 +Here we create the MyButton custom class.
 +
 +
 +
 +
 +<code java>
 + class MyButton extends JButton implements ActionListener {
 +</code>
 +
 +
 +
 +
 +The MyButton class is extended from the **JButton** class. It implements the
 +**ActionListener** interface. This way, the event handling is managed within the MyButton class. 
 +
 +
 +
 +
 +<code java>
 + addActionListener(this);
 +</code>
 +
 +
 +
 +
 +Here we add the action listener to the MyButton class. 
 +
 +
 +
 +
 +
 +
 +==== Multiple sources ====
 +
 +
 +
 +
 +A listener can be plugged into several sources. This will be explained in the next example.
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +import javax.swing.border.EtchedBorder;
 +
 +
 +public class MultipleSources extends JFrame {
 +
 +    JLabel statusbar;
 +
 +    public MultipleSources() {
 +
 +        setTitle("Multiple Sources");
 +        JPanel panel = new JPanel();
 +        statusbar = new JLabel(" ZetCode");
 +
 +        statusbar.setBorder(BorderFactory.createEtchedBorder(
 +                EtchedBorder.RAISED));
 +
 +        panel.setLayout(null);
 +
 +        JButton close = new JButton("Close");
 +        close.setBounds(40, 30, 80, 25);
 +        close.addActionListener(new ButtonListener());
 +
 +        JButton open = new JButton("Open");
 +        open.setBounds(40, 80, 80, 25);
 +        open.addActionListener(new ButtonListener());
 +
 +        JButton find = new JButton("Find");
 +        find.setBounds(40, 130, 80, 25);
 +        find.addActionListener(new ButtonListener());
 +
 +        JButton save = new JButton("Save");
 +        save.setBounds(40, 180, 80, 25);
 +        save.addActionListener(new ButtonListener());
 +
 +        panel.add(close);
 +        panel.add(open);
 +        panel.add(find);
 +        panel.add(save);
 +
 +        add(panel);
 +        add(statusbar, BorderLayout.SOUTH);
 +
 +        setSize(400, 300);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    class ButtonListener implements ActionListener {
 +        public void actionPerformed(ActionEvent e)
 +        {
 +            JButton o = (JButton) e.getSource();
 +            String label = o.getText();
 +            statusbar.setText(" " + label + " button clicked");
 +        }
 +      }
 +
 +
 +    public static void main(String[] args) {
 +        new MultipleSources();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +We create four buttons and a statusbar. The statusbar will display an informative message upon clicking on the
 +button.
 +
 +
 +
 +
 +
 +<code java>
 + close.addActionListener(new ButtonListener());
 + ...
 + open.addActionListener(new ButtonListener());
 + ...
 +</code>
 +
 +
 +
 +
 +Each button will be registered against a **ButtonListener** class.
 +
 +
 +
 +
 +
 +<code java>
 + JButton o = (JButton) e.getSource();
 + String label = o.getText();
 +</code>
 +
 +
 +
 +
 +Here we determine, which button was pressed.
 +
 +
 +
 +
 +<code java>
 + statusbar.setText(" " + label + " button clicked")
 +</code>
 +
 +
 +
 +
 +We update the statusbar.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/multiplesources.png |Multiple Sources}}
 +
 +
 +
 +==== Multiple listeners ====
 +
 +
 +
 +
 +We can register several listeners for one event. 
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import java.util.Calendar;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +import javax.swing.JSpinner;
 +import javax.swing.SpinnerModel;
 +import javax.swing.SpinnerNumberModel;
 +import javax.swing.border.EtchedBorder;
 +
 +
 +public class MultipleListeners extends JFrame {
 +
 +    private JLabel statusbar;
 +    private JSpinner spinner;
 +    private static int count = 0;
 +
 +    public MultipleListeners() {
 +
 +        setTitle("Multiple Listeners");
 +        JPanel panel = new JPanel();
 +        statusbar = new JLabel("0");
 +
 +        statusbar.setBorder(BorderFactory.createEtchedBorder(
 +                EtchedBorder.RAISED));
 +
 +        panel.setLayout(null);
 +
 +        JButton add = new JButton("+");
 +        add.setBounds(40, 30, 80, 25);
 +        add.addActionListener(new ButtonListener1());
 +        add.addActionListener(new ButtonListener2());
 +
 +        Calendar calendar = Calendar.getInstance();
 +        int currentYear = calendar.get(Calendar.YEAR);
 +
 +        SpinnerModel yearModel = new SpinnerNumberModel(currentYear,
 +                                       currentYear - 100,
 +                                       currentYear + 100,
 +                                       1);
 +
 +        spinner = new JSpinner(yearModel);
 +        spinner.setEditor(new JSpinner.NumberEditor(spinner, "#"));
 +
 +        spinner.setBounds(190, 30, 80, 25);
 +
 +        panel.add(add);
 +        panel.add(spinner);
 +
 +        add(panel);
 +        add(statusbar, BorderLayout.SOUTH);
 +
 +        setSize(300, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    class ButtonListener1 implements ActionListener {
 +        public void actionPerformed(ActionEvent e)
 +        {
 +            Integer val = (Integer) spinner.getValue();
 +            spinner.setValue(++val);
 +        }
 +      }
 +
 +    class ButtonListener2 implements ActionListener {
 +        public void actionPerformed(ActionEvent e)
 +        {
 +            statusbar.setText(Integer.toString(++count));
 +        }
 +      }
 +
 +
 +    public static void main(String[] args) {
 +        new MultipleListeners();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +In this example, we have a button, spinner and a statusbar.  We use two button listeners for one event. One click of a button will add one year to the spinner component and update the statusbar. The statusbar will show, how many times we have clicked on the button. 
 +
 +
 +
 +
 +<code java>
 + add.addActionListener(new ButtonListener1());
 + add.addActionListener(new ButtonListener2());
 +</code>
 +
 +
 +
 +
 +We register two button listeners. 
 +
 +
 +
 +
 +<code java>
 + SpinnerModel yearModel = new SpinnerNumberModel(currentYear,
 +                              currentYear - 100,
 +                              currentYear + 100,
 +                              1);
 + spinner = new JSpinner(yearModel);
 +</code>
 +
 +
 +
 +
 +Here we create the spinner component. We use a year model for the spinner. The **SpinnerNumberModel**
 +arguments are initial value, min, max values and the step. 
 +
 +
 +
 +
 +<code java>
 + spinner.setEditor(new JSpinner.NumberEditor(spinner, "#"));
 +</code>
 +
 +
 +
 +
 +We remove the thousands separator.
 +
 +
 +
 +
 +
 +<code java>
 + Integer val = (Integer) spinner.getValue();
 + spinner.setValue(++val);
 +</code>
 +
 +
 +
 +
 +Here we increase the year number. 
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/multiplelisteners.png |Multiple Listeners}}
 +
 +
 +
 +
 +==== Removing listeners ====
 +
 +
 +
 +
 +The Java Swing toolkit enables us to remove the registered listeners. 
 +
 +
 +
 +
 +<code java>
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.event.ItemEvent;
 +import java.awt.event.ItemListener;
 +
 +import javax.swing.JButton;
 +import javax.swing.JCheckBox;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +
 +
 +public class RemoveListener extends JFrame {
 +
 +    private JLabel text;
 +    private JButton add;
 +    private JCheckBox active;
 +    private ButtonListener buttonlistener;
 +    private static int count = 0;
 +
 +    public RemoveListener() {
 +
 +        setTitle("Remove listener");
 +        JPanel panel = new JPanel();
 +
 +        panel.setLayout(null);
 +
 +        add = new JButton("+");
 +        add.setBounds(40, 30, 80, 25);
 +        buttonlistener = new ButtonListener();
 +
 +        active = new JCheckBox("Active listener");
 +        active.setBounds(160, 30, 140, 25);
 +
 +        active.addItemListener(new ItemListener() {
 +            public void itemStateChanged(ItemEvent event) {
 +                if (active.isSelected()) {
 +                  add.addActionListener(buttonlistener);}
 +                else {
 +                  add.removeActionListener(buttonlistener);
 +                }
 +            }
 +        });
 +
 +        text = new JLabel("0");
 +        text.setBounds(40, 80, 80, 25);
 +
 +        panel.add(add);
 +        panel.add(active);
 +        panel.add(text);
 +
 +        add(panel);
 +
 +        setSize(310, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    class ButtonListener implements ActionListener {
 +        public void actionPerformed(ActionEvent e)
 +        {
 +            text.setText(Integer.toString(++count));
 +        }
 +      }
 +
 +    public static void main(String[] args) {
 +        new RemoveListener();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +We have three components on the panel. A button, check box and a label. By toggling the check box, we add or remove
 +the listener for a button.
 +
 +
 +
 +
 +<code java>
 + buttonlistener = new ButtonListener();
 +</code>
 +
 +
 +
 +
 +We have to create a non anonymous listener, if we want to later remove it. We need a reference to it. 
 +
 +
 +
 +
 +<code java>
 + if (active.isSelected()) {
 +     add.addActionListener(buttonlistener);}
 + else {
 +     add.removeActionListener(buttonlistener);
 + }
 +</code>
 +
 +
 +
 +
 +We determine, whether the check box is selected. Then we add or remove the listener. 
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/removelistener.png |Remove listener}}
 +
 +
 +
 +
 +==== Moving a window ====
 +
 +
 +
 +
 +The following example will look for a position of a window on the screen. 
 +
 +
 +
 +
 +<code java>
 +import java.awt.Font;
 +import java.awt.event.ComponentEvent;
 +import java.awt.event.ComponentListener;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +
 +
 +public class MovingWindow extends JFrame implements ComponentListener {
 +
 +    private JLabel labelx;
 +    private JLabel labely;
 +
 +    public MovingWindow() {
 +
 +        setTitle("Moving window");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(null);
 +
 +        labelx = new JLabel("x: ");
 +        labelx.setFont(new Font("Serif", Font.BOLD, 14));
 +        labelx.setBounds(20, 20, 60, 25);
 +
 +        labely = new JLabel("y: ");
 +        labely.setFont(new Font("Serif", Font.BOLD, 14));
 +        labely.setBounds(20, 45, 60, 25);
 +
 +        panel.add(labelx);
 +        panel.add(labely);
 +
 +        add(panel);
 +
 +        addComponentListener(this);
 +
 +        setSize(310, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public void componentResized(ComponentEvent e) {
 +    }
 +
 +    public void componentMoved(ComponentEvent e) {
 +        int x = e.getComponent().getX();
 +        int y = e.getComponent().getY();
 +        labelx.setText("x: " + x);
 +        labely.setText("y: " + y);
 +    }
 +
 +    public void componentShown(ComponentEvent e) {
 +    }
 +
 +    public void componentHidden(ComponentEvent e) {
 +    }
 +
 +
 +    public static void main(String[] args) {
 +        new MovingWindow();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +The example shows the current window coordinates on the panel. 
 +To get the window position, we use the **ComponentListener**
 +
 +
 +
 +
 +<code java>
 + labelx.setFont(new Font("Serif", Font.BOLD, 14));
 +</code>
 +
 +
 +
 +
 +We make the font bigger, the default one is a bit small.
 +
 +
 +
 +
 +<code java>
 + int x = e.getComponent().getX();
 + int y = e.getComponent().getY();
 +</code>
 +
 +
 +
 +
 +Here we get the x and the y positions.
 +
 +
 +
 +
 +
 +
 +
 +Notice, that we have to implement all four methods, that are available in the **ComponentListener**.
 +Even, if we do not use them. 
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/movingwindow.png |Moving a window}}
 +
 +
 +
 +
 +==== Adapters ====
 +
 +
 +
 +
 +Adapters are convenient classes. In the previous code example, we had to implement all four methods of a **ComponentListener** class. Even if we did not use them.    To avoid unnecessary coding, we can use adapters. Adapter is a class that implements all necessary methods. They
 +are empty. We then use only those methods, that we actually need. 
 +There is no adapter for a button click event.  Because there we have only one method to implement. The **actionPerformed()** method.
 +We can use adapters in situations, where we have more than one method to implement. 
 +
 +
 +
 + 
 +
 +
 +
 +The following example is a rewrite of the previous one, using a **ComponentAdapter**.
 +
 +
 +
 +
 +<code java>
 +import java.awt.Font;
 +import java.awt.event.ComponentAdapter;
 +import java.awt.event.ComponentEvent;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +
 +
 +public class Adapter extends JFrame {
 +
 +    private JLabel labelx;
 +    private JLabel labely;
 +
 +    public Adapter() {
 +
 +        setTitle("Adapter");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(null);
 +
 +        labelx = new JLabel("x: ");
 +        labelx.setFont(new Font("Serif", Font.BOLD, 14));
 +        labelx.setBounds(20, 20, 60, 25);
 +
 +        labely = new JLabel("y: ");
 +        labely.setFont(new Font("Serif", Font.BOLD, 14));
 +        labely.setBounds(20, 45, 60, 25);
 +
 +
 +        panel.add(labelx);
 +        panel.add(labely);
 +
 +        add(panel);
 +        addComponentListener(new MoveAdapter());
 +
 +        setSize(310, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +
 +    class MoveAdapter extends ComponentAdapter {
 +      public void componentMoved(ComponentEvent e) {
 +          int x = e.getComponent().getX();
 +          int y = e.getComponent().getY();
 +          labelx.setText("x: " + x);
 +          labely.setText("y: " + y);
 +      }
 +     }
 +
 +    public static void main(String[] args) {
 +        new Adapter();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +This example is a rewrite of the previous one. Here we use the **ComponentAdapter**.
 +
 +
 +
 +
 +
 +<code java>
 + addComponentListener(new MoveAdapter());
 +</code>
 +
 +
 +
 +
 +Here we register the component listener. 
 +
 +
 +
 +
 +<code java>
 + class MoveAdapter extends ComponentAdapter {
 +     public void componentMoved(ComponentEvent e) {
 +         int x = e.getComponent().getX();
 + int y = e.getComponent().getY();
 + labelx.setText("x: " + x);
 +         labely.setText("y: " + y);
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +Inside the MoveAdapter inner class, we define the **componentMoved()** method. All the other methods are left empty.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Java Swing dialogs =====
 +
 +
 +
 +
 +
 +
 +Dialog windows or dialogs are an indispensable part of most modern GUI applications. A dialog is defined as a conversation between two or more persons. In a computer application a dialog is a window which is used to "talk" to the application. A dialog is used to input data, modify data, change the application settings etc. Dialogs are important means of communication between a user and a computer program.
 +
 +
 +
 +
 +
 +
 +
 +
 +In Java Swing toolkit, we can create two kinds of dialogs. Custom dialogs and standard dialogs. 
 +**Custom dialogs** are dialogs, created by the programmer. They are based on the **JDialog** class. 
 +**Standard dialogs** preedefined dialogs available in the Swing toolkit. For example **JColorChooser** or **JFileChooser**.
 +These are dialogs for common programming tasks like showing text, receiving input , loading and saving files etc. They save programmer's time and enhance using some standard behaviour.
 +
 +
 +
 +
 +
 +
 +
 +There are two basic types of dialogs. Modal and modeless. **Modal** dialogs block input to other top level windows. 
 +**Modeless** dialogs allow input to other windows. What type of dialog to use, depends on the circumstances. An open file dialog is a good example of a modal dialog. While choosing a file to open, no other operation should be permitted.
 +A typical modeless dialog is a find text dialog. (Like in Eclipse IDE.) It is handy to have the ability to move the cursor in the text control and define, where to start the finding of the particular text. 
 +
 +
 +
 +
 +
 +==== A simple custom dialog ====
 +
 +
 +
 +
 +In the following example we create a simple custom dialog. It is a sample about dialog, found in most GUI applications, usually located in the help menu.  
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +import java.awt.Font;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.event.KeyEvent;
 +
 +import javax.swing.Box;
 +import javax.swing.BoxLayout;
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JDialog;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JMenu;
 +import javax.swing.JMenuBar;
 +import javax.swing.JMenuItem;
 +
 +
 +class AboutDialog extends JDialog {
 +
 +    public AboutDialog() {
 +
 +        setTitle("About Notes");
 +
 +        setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
 +
 +        add(Box.createRigidArea(new Dimension(0, 10)));
 +
 +        ImageIcon icon = new ImageIcon("notes.png");
 +        JLabel label = new JLabel(icon);
 +        label.setAlignmentX(0.5f);
 +        add(label);
 +
 +        add(Box.createRigidArea(new Dimension(0, 10)));
 +
 +        JLabel name = new JLabel("Notes, 1.23");
 +        name.setFont(new Font("Serif", Font.BOLD, 13));
 +        name.setAlignmentX(0.5f);
 +        add(name);
 +
 +        add(Box.createRigidArea(new Dimension(0, 50)));
 +
 +        JButton close = new JButton("Close");
 +        close.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                dispose();
 +            }
 +        });
 +
 +        close.setAlignmentX(0.5f);
 +        add(close);
 +
 +        setModalityType(ModalityType.APPLICATION_MODAL);
 +
 +        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setSize(300, 200);
 +
 +    }
 +
 +}
 +
 +
 +public class SimpleDialog extends JFrame {
 +
 +
 +    public SimpleDialog() {
 +
 +        setTitle("Simple Dialog");
 +
 +        JMenuBar menubar = new JMenuBar();
 +
 +        JMenu file = new JMenu("File");
 +        file.setMnemonic(KeyEvent.VK_F);
 +
 +        JMenu help = new JMenu("Help");
 +        help.setMnemonic(KeyEvent.VK_H);
 +
 +        JMenuItem about = new JMenuItem("About");
 +        help.add(about);
 +
 +        about.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                AboutDialog ad = new AboutDialog();
 +                ad.setVisible(true);
 +            }
 +
 +        });
 +
 +        menubar.add(file);
 +        menubar.add(help);      
 +        setJMenuBar(menubar);
 +
 +        setSize(300, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new SimpleDialog();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +The sample code will popup a small dialog box. The dialog will display an icon a text and one close button.
 +
 +
 +
 +
 +<code java>
 + class AboutDialog extends JDialog {
 +</code>
 +
 +
 +
 +
 +The custom dialog is based on the **JDialog** class.
 +
 +
 +
 +
 +
 +<code java>
 + setModalityType(ModalityType.APPLICATION_MODAL);
 +</code>
 +
 +
 +
 +
 +Here we make the dialog modal. 
 +
 +
 +
 +
 +
 +<code java>
 + setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 +</code>
 +
 +
 +
 +
 +Here we set the defaul close operation. 
 +
 +
 +
 +
 +
 +<code java>
 + AboutDialog ad = new AboutDialog();
 + ad.setVisible(true);
 +</code>
 +
 +
 +
 +
 +Here we display the about dialog, from the menu of the main frame.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/simpledialog.jpg |Simple custom dialog}}
 +
 +
 +==== Message boxes ====
 +
 +
 +
 +
 +Message boxes provide information to the user. 
 +
 +
 +
 +
 +<code java>
 +import java.awt.GridLayout;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JOptionPane;
 +import javax.swing.JPanel;
 +
 +
 +public class MessageBoxes extends JFrame {
 +
 +
 +    private JPanel panel;
 +
 +    public MessageBoxes() {
 +
 +        setTitle("Message Boxes");
 +
 +        panel = new JPanel();
 +        panel.setLayout(new GridLayout(2, 2));
 +
 +        JButton error = new JButton("Error");
 +        JButton warning = new JButton("Warning");
 +        JButton question = new JButton("Question");
 +        JButton information = new JButton("Information");
 +
 +        error.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                JOptionPane.showMessageDialog(panel, "Could not open file", 
 +                    "Error", JOptionPane.ERROR_MESSAGE);
 +            }
 +
 +        });
 +
 +        warning.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                JOptionPane.showMessageDialog(panel, "A deprecated call", 
 +                    "Warning", JOptionPane.WARNING_MESSAGE);
 +            }
 +
 +        });
 +
 +        question.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                JOptionPane.showMessageDialog(panel, "Are you sure to quit?", 
 +                    "Question", JOptionPane.QUESTION_MESSAGE);
 +            }
 +
 +        });
 +
 +        information.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                JOptionPane.showMessageDialog(panel, "Download completed", 
 +                    "Question", JOptionPane.INFORMATION_MESSAGE);
 +            }
 +
 +        });
 +
 +        panel.add(error);
 +        panel.add(warning);
 +        panel.add(question);
 +        panel.add(information);
 +
 +        add(panel);
 +
 +        setSize(300, 200);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new MessageBoxes();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +The example shows an error, question, warning and information message boxes.
 +
 +
 +
 +
 +<code java>
 + panel.setLayout(new GridLayout(2, 2));
 +</code>
 +
 +
 +
 +
 + We use a **GridLayout** layout manager to organize buttons, that will popup message boxes.
 +
 +
 +
 +
 +<code java>
 + JButton error = new JButton("Error");
 + JButton warning = new JButton("Warning");
 + JButton question = new JButton("Question");
 + JButton information = new JButton("Information");
 +</code>
 +
 +
 +
 +
 +Here are the four buttons, that we will use.
 +
 +
 +
 +
 +<code java>
 + JOptionPane.showMessageDialog(panel, "Could not open file", 
 +     "Error", JOptionPane.ERROR_MESSAGE);
 +</code>
 +
 +
 +
 +
 +To create a message box, we call the **showMessageDialog** static method of the <b class="keyword">
 +JOptionPane</b> class. We provide the component name, message text, title and a message type. The message type is determined
 +by the constant we choose.  Available constants are:
 +
 +
 +
 +
 +
 +
 +  * ERROR_MESSAGE
 +  * WARNING_MESSAGE
 +  * QUESTION_MESSAGE
 +  * INFORMATION_MESSAGE
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/messageboxes.png |Message boxes}}
 +
 +
 +
 +
 +
 +
 +|  {{ http://zetcode.com/tutorials/javaswingtutorial/images/error.png |Error box}}  |  {{ http://zetcode.com/tutorials/javaswingtutorial/images/warning.png |Warning box}}  |
 +|  {{ http://zetcode.com/tutorials/javaswingtutorial/images/question.png |Question box}}  |  {{ http://zetcode.com/tutorials/javaswingtutorial/images/information.png |Information box}}  |
 +
 +
 +==== JFileChooser ====
 +
 +
 +
 +
 +JFileChooser is a standard dialog for selecting a file from the file system.
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import java.io.BufferedReader;
 +import java.io.File;
 +import java.io.FileReader;
 +import java.io.IOException;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JFileChooser;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.JScrollPane;
 +import javax.swing.JTextArea;
 +import javax.swing.JToolBar;
 +import javax.swing.filechooser.FileFilter;
 +import javax.swing.filechooser.FileNameExtensionFilter;
 +
 +
 +public class FileChooserDialog extends JFrame {
 +
 +    private JPanel panel;
 +    private JTextArea area;
 +
 +    public FileChooserDialog() {
 +
 +        setTitle("FileChooserDialog");
 +
 +        panel = new JPanel();
 +        panel.setLayout(new BorderLayout());
 +        ImageIcon open = new ImageIcon("open.png");
 +
 +        JToolBar toolbar = new JToolBar();
 +        JButton openb = new JButton(open);
 +
 +        openb.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                JFileChooser fileopen = new JFileChooser();
 +                FileFilter filter = new FileNameExtensionFilter("c files", "c");
 +                fileopen.addChoosableFileFilter(filter);
 +
 +                int ret = fileopen.showDialog(panel, "Open file");
 +
 +                if (ret == JFileChooser.APPROVE_OPTION) {
 +                    File file = fileopen.getSelectedFile();
 +                    String text = readFile(file);
 +                    area.setText(text);
 +                }
 +
 +            }
 +        });
 +
 +        toolbar.add(openb);
 +
 +        area = new JTextArea();
 +        area.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
 +
 +        JScrollPane pane = new JScrollPane();
 +        pane.getViewport().add(area);
 +
 +        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
 +        panel.add(pane);
 +        add(panel);
 +
 +        add(toolbar, BorderLayout.NORTH);
 +
 +        setSize(400, 300);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public String readFile (File file) {
 +
 +     StringBuffer fileBuffer = null;
 +     String fileString = null;
 +     String line = null;
 +
 +     try {
 +       FileReader in = new FileReader (file);
 +       BufferedReader brd = new BufferedReader (in);
 +       fileBuffer = new StringBuffer() ;
 +
 +       while ((line = brd.readLine()) != null) {
 +             fileBuffer.append(line + System.getProperty("line.separator"));
 +       }
 +
 +       in.close();
 +       fileString = fileBuffer.toString();
 +     }
 +     catch  (IOException e ) {
 +       return null;
 +     }
 +     return fileString;
 +    } 
 +
 +
 +    public static void main(String[] args) {
 +        new FileChooserDialog();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +The code example will demonstrate how to use a file chooser dialog in order to load file contents into the 
 +text area component. 
 +
 +
 +
 +
 +<code java>
 + JFileChooser fileopen = new JFileChooser();
 +</code>
 +
 +
 +
 +
 +This is the constructor of the file chooser dialog.
 +
 +
 +
 +
 +<code java>
 + FileFilter filter = new FileNameExtensionFilter("c files", "c");
 + fileopen.addChoosableFileFilter(filter);
 +</code>
 +
 +
 +
 +
 +Here we define the file filter. In our case, we will have c files with extension .c. We have also the default
 +All files option.
 +
 +
 +
 +
 +<code java>
 + int ret = fileopen.showDialog(panel, "Open file");
 +</code>
 +
 +
 +
 +
 +Here we show the file chooser dialog. Upon clicking on the open file button, the return value is equal to
 +**JFileChooser.APPROVE_OPTION**.
 +
 +
 +
 +
 +<code java>
 + if (ret == JFileChooser.APPROVE_OPTION) {
 +     File file = fileopen.getSelectedFile();
 +     String text = readFile(file);
 +     area.setText(text);
 + }
 +</code>
 +
 +
 +
 +
 +Here we get the name of the selected file. We read the contents of the file and set the text into the textarea. 
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/filechooserdialog.jpg |JFileChooser dialog}}
 +
 +
 +
 +==== JColorChooser ====
 +
 +
 +
 +
 +JColorChooser is a standard dialog for selecting a color.
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Color;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JColorChooser;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.JToolBar;
 +
 +
 +public class ColorChooserDialog extends JFrame {
 +
 +    private JPanel panel;
 +    private JPanel display;
 +
 +    public ColorChooserDialog() {
 +
 +        setTitle("ColorChooserDialog");
 +
 +        panel = new JPanel();
 +        panel.setLayout(new BorderLayout());
 +        ImageIcon open = new ImageIcon("color.png");
 +
 +        JToolBar toolbar = new JToolBar();
 +        JButton openb = new JButton(open);
 +
 +        openb.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                JColorChooser clr = new JColorChooser();
 +                Color color = clr.showDialog(panel, "Choose Color", Color.white);
 +                display.setBackground(color);
 +            }
 +        });
 +
 +        toolbar.add(openb);
 +
 +        display = new JPanel();
 +        display.setBackground(Color.WHITE);
 +
 +        panel.setBorder(BorderFactory.createEmptyBorder(30, 50, 30, 50));
 +        panel.add(display);
 +        add(panel);
 +
 +        add(toolbar, BorderLayout.NORTH);
 +
 +        setSize(400, 300);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +
 +    public static void main(String[] args) {
 +        new ColorChooserDialog();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +In the example, we have a white panel. We will change the background color of the panel by selecting a color from
 +the color chooser dialog. 
 +
 +
 +
 +
 +<code java>
 + JColorChooser clr = new JColorChooser();
 + Color color = clr.showDialog(panel, "Choose Color", Color.white);
 + display.setBackground(color);
 +</code>
 +
 +
 +
 +
 +This code shows a color chooser dialog. The **showDialog()** method returns the selected color
 +value. We change the display panel background to the newly selected color. 
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/colorchooser.jpg |JColorChooser dialog}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Basic Swing components =====
 +
 +
 +
 +
 +
 +Swing components are basic building blocks of an application. Swing toolkit has a wide range of various widgets. Buttons, check boxes,sliders, list boxes etc. Everything a programmer needs for his job. In this section of the tutorial, we will describe several useful components.
 +
 +
 +
 +
 +
 +==== JLabel Component ====
 +
 +
 +
 +
 +**JLabel** is a simple component for displaying text, images or both. It does not react to input events.
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Color;
 +import java.awt.Dimension;
 +import java.awt.Font;
 +import java.awt.Toolkit;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +
 +
 +public class MyLabel extends JFrame {
 +
 +    private Toolkit toolkit;
 +
 +    public MyLabel() {
 +
 + setTitle("No Sleep");
 +
 +        String lyrics =  "&lt;html&gt;It's way too late to think of&lt;br&gt;"
 +        "Someone I would call now&lt;br&gt;"
 +        "And neon signs got tired&lt;br&gt;"
 +        "Red eye flights help the stars out&lt;br&gt;"
 +        "I'm safe in a corner&lt;br&gt;"
 +        "Just hours before me&lt;br&gt;"
 +        "&lt;br&gt;"
 +        "I'm waking with the roaches&lt;br&gt;"
 +        "The world has surrendered&lt;br&gt;"
 +        "I'm dating ancient ghosts&lt;br&gt;"
 +        "The ones I made friends with&lt;br&gt;"
 +        "The comfort of fireflies&lt;br&gt;"
 +        "Long gone before daylight&lt;br&gt;"
 +        "&lt;br&gt;"
 +        "And if I had one wishful field tonight&lt;br&gt;"
 +        "I'd ask for the sun to never rise&lt;br&gt;"
 +        "If God leant his voice for me to speak&lt;br&gt;"
 +        "I'd say go to bed, world&lt;br&gt;"
 +        "&lt;br&gt;"
 +        "I've always been too late&lt;br&gt;"
 +        "To see what's before me&lt;br&gt;"
 +        "And I know nothing sweeter than&lt;br&gt;"
 +        "Champaign from last New Years&lt;br&gt;"
 +        "Sweet music in my ears&lt;br&gt;"
 +        "And a night full of no fears&lt;br&gt;"
 +        "&lt;br&gt;"
 +        "But if I had one wishful field tonight&lt;br&gt;"
 +        "I'd ask for the sun to never rise&lt;br&gt;"
 +        "If God passed a mic to me to speak&lt;br&gt;"
 +        "I'd say stay in bed, world&lt;br&gt;"
 +        "Sleep in peace&lt;/html&gt;";
 +
 +        JPanel panel = new JPanel(); 
 +        panel.setLayout(new BorderLayout(10, 10));
 + 
 +        JLabel label = new JLabel(lyrics);
 +        label.setFont(new Font("Georgia", Font.PLAIN, 14));
 +        label.setForeground(new Color(50, 50, 25));
 +
 +
 +        panel.add(label, BorderLayout.CENTER);
 +        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
 +        add(panel);
 +        pack();
 +
 +        toolkit = getToolkit();
 +        Dimension screensize = toolkit.getScreenSize();
 +        setLocation((screensize.width - getWidth())/2, 
 +            (screensize.height - getHeight())/2);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        MyLabel mylabel = new MyLabel();
 +        mylabel.setVisible(true);
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +In our example, we show lyrics of no sleep song from cardigans. We can use html tags in **JLabel** component.
 +We use the &lt;br&gt; tag to separate lines.
 +
 +
 +
 +
 +<code java>
 + JPanel panel = new JPanel(); 
 + panel.setLayout(new BorderLayout(10, 10));
 +</code>
 +
 +
 +
 +
 +We create a panel and set a **BorderLayout** manager.
 +
 +
 +
 +
 +<code java>
 + JLabel label = new JLabel(lyrics);
 + label.setFont(new Font("Georgia", Font.PLAIN, 14));
 + label.setForeground(new Color(50, 50, 25));
 +</code>
 +
 +
 +
 +
 +Here we create the label component. We set it's font to plain georgia, 14 px tall. We also change the foreground color.
 +
 +
 +
 +
 +<code java>
 + panel.add(label, BorderLayout.CENTER);
 + panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
 +</code>
 +
 +
 +
 +
 +We put the label into the center of the panel. We put 10px around the label. 
 +
 +
 +
 +
 +<code java>
 + add(panel);
 + pack();
 +</code>
 +
 +
 +
 +
 +The panel is added to the frame component. We call the **pack()** method, which will resize the window, so that all components are visible.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/nosleep.jpg |JLabel}}
 +
 +
 +
 +==== JCheckBox ====
 +
 +
 +
 +
 +JCheckBox is a widget that has two states. On and Off. It is a box with a label.  If the checkbox is checked, it is represented by a tick in a box. A checkbox can be used to show/hide splashscreen at startup, toggle visibility of a toolbar etc.
 +
 +
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.Box;
 +import javax.swing.BoxLayout;
 +import javax.swing.JCheckBox;
 +import javax.swing.JFrame;
 +
 +
 +public class CheckBox extends JFrame implements ActionListener {
 +
 +    public CheckBox() {
 +
 +        setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
 +        add(Box.createRigidArea(new Dimension(15, 20)));
 +
 +        JCheckBox checkbox = new JCheckBox("Show Title", true);
 +        checkbox.setFocusable(false);
 +        checkbox.addActionListener(this);
 +        add(checkbox);
 +
 +        setSize(280, 200);
 +        setTitle("CheckBox example");
 +        setLocationRelativeTo(null);
 +        setResizable(false);
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        new CheckBox();
 +
 +    }
 +
 +
 +    public void actionPerformed(ActionEvent e) {
 +        if (this.getTitle() == "") {
 +            this.setTitle("Checkbox example");
 +        } else {
 +            this.setTitle("");
 +        }
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +Our code example shows or hides the title of the window depending on it's state. 
 +
 +
 +
 +
 +<code java>
 + setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
 + add(Box.createRigidArea(new Dimension(15, 20)));
 +</code>
 +
 +
 +
 +
 +In this example, we use a **BoxLayout** layout manager. We put some space there, so that
 +the checkbox is not too close to the corner.
 +
 +
 +
 +
 +<code java>
 + JCheckBox checkbox = new JCheckBox("Show Title", true);
 +</code>
 +
 +
 +
 +
 +Here we have a constructor for the checkbox. We provide text and state. 
 +
 +
 +
 +
 +<code java>
 + checkbox.setFocusable(false);
 +</code>
 +
 +
 +
 +
 +We have disabled the focus for the checkbox. The rectangle around the text looks ugly, so we go without the focus.
 +
 +
 +
 +
 +<code java>
 + if (this.getTitle() == "") {
 +     this.setTitle("Checkbox example");
 + } else {
 +     this.setTitle("");
 + }
 +</code>
 +
 +
 +
 +
 +Here we toggle the title of the window.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/checkbox.jpg |JCheckBox}}
 +
 +
 +
 +==== JSlider ====
 +
 +
 +
 +
 +JSlider is a component that lets the user graphically select a value by sliding a knob within a bounded interval.
 +Our example will show a volume control. 
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Dimension;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.Box;
 +import javax.swing.BoxLayout;
 +import javax.swing.ImageIcon;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +import javax.swing.JSlider;
 +import javax.swing.event.ChangeEvent;
 +import javax.swing.event.ChangeListener;
 +
 +
 +public class Slider extends JFrame {
 +
 +    private JSlider slider;
 +    private JLabel label;
 +
 +    ImageIcon mute = new ImageIcon(ClassLoader.getSystemResource("mute.png"));
 +    ImageIcon min = new ImageIcon(ClassLoader.getSystemResource("min.png"));
 +    ImageIcon med = new ImageIcon(ClassLoader.getSystemResource("med.png"));
 +    ImageIcon max = new ImageIcon(ClassLoader.getSystemResource("max.png"));
 +
 +    public Slider() {
 +
 +        setTitle("JSlider");
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
 +        panel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40));
 +        setLayout(new BorderLayout());
 +
 +        panel.add(Box.createHorizontalGlue());
 +        slider = new JSlider(0, 150, 0);
 +
 +        slider.setPreferredSize(new Dimension(150, 30));
 +
 +        slider.addChangeListener(new ChangeListener() {
 +            public void stateChanged(ChangeEvent event) {
 +                int value = slider.getValue();
 +                if (value == 0) {
 +                    label.setIcon(mute);
 +                } else if (value > 0 && value <= 30) {
 +                    label.setIcon(min);
 +                } else if (value > 30 && value < 80) {
 +                    label.setIcon(med);
 +                } else {
 +                    label.setIcon(max);
 +                }
 +            }
 +        });
 +
 +        panel.add(slider);
 +        panel.add(Box.createRigidArea(new Dimension(5, 0)));
 +
 +        label = new JLabel(mute, JLabel.CENTER);
 +        panel.add(label);
 +        panel.add(Box.createHorizontalGlue());
 +        add(panel, BorderLayout.CENTER);
 +
 +        pack();
 +        setLocationRelativeTo(null);
 +
 +    }
 +
 +
 +    public static void main(String[] args) {
 +
 +        Slider button = new Slider();
 +        button.setVisible(true); 
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +In the code example, we show a **JSlider** and a **JLabel**.
 +By dragging the slider, we change the icon on the label component. 
 +
 +
 +
 +
 +
 +<code java>
 + ImageIcon mute = new ImageIcon(ClassLoader.getSystemResource("mute.png"));
 +</code>
 +
 +
 +
 +
 +Here we create an image icon. 
 +
 +
 +
 +
 +<code java>
 + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
 +</code>
 +
 +
 +
 +
 +Panel component has a horizontal **BoxLayout**.
 +
 +
 +
 +
 +<code java>
 + panel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40));
 +</code>
 +
 +
 +
 +
 +We creare a 40px border around the panel.
 +
 +
 +
 +
 +
 +<code java>
 + panel.add(Box.createHorizontalGlue());
 +</code>
 +
 +
 +
 +
 +We put resizable space to bo both sides, left and right. It is to prevent **JSlider** from 
 +growing to unnatural sizes.
 +
 +
 +
 +
 +<code java>
 + slider = new JSlider(0, 150, 0);
 +</code>
 +
 +
 +
 +
 +This is a **JSlider** constructor. The parameters are minimum value, maximum value and current
 +value.
 +
 +
 +
 +
 +
 +
 +
 +
 +<code java>
 + slider.addChangeListener(new ChangeListener() {
 + ...
 + });
 +</code>
 +
 +
 +
 +
 +We add a **ChangeListener** to the slider. Inside the listener, we determine the current
 +slider value and update the label accordingly.
 +
 +
 +
 +
 +<code java>
 + panel.add(Box.createRigidArea(new Dimension(5, 0)));
 +</code>
 +
 +
 +
 +
 +We place a 5px rigid space between the two components. They are too close to each other, when the slider is at the end position. 
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/slider.jpg |JSlider}}
 +
 +
 +
 +==== JComboBox ====
 +
 +
 +
 +
 +Combobox is a component that combines a button or editable field and a drop-down list. The user can select a value from the drop-down list, which appears at the user's request. If you make the combo box editable, then the combo box includes an editable field into which the user can type a value.
 +
 +
 +
 +
 +<code java>
 +import java.awt.Component;
 +import java.awt.Dimension;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.event.ItemEvent;
 +import java.awt.event.ItemListener;
 +
 +import javax.swing.Box;
 +import javax.swing.BoxLayout;
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JComboBox;
 +import javax.swing.JDialog;
 +import javax.swing.JLabel;
 +import javax.swing.border.LineBorder;
 +
 +
 +public class ComboBox extends JDialog implements 
 + ActionListener, ItemListener {
 +
 +    final String[] authors = {
 + "Leo Tolstoy", "John Galsworthy", 
 +        "Honore de Balzac", "Stefan Zweig", 
 + "Boris Pasternak", "Tom Wolfe"
 +    };
 +
 +    final String[] images = {
 + "tolstoy.jpg", "galsworthy.jpg", "balzac.jpg", 
 +        "zweig.jpg", "pasternak.jpg", "wolfe.jpg"
 +    };
 +
 +    private JLabel display = null;  
 +    private JComboBox combobox = null;
 +    private JButton button = null;
 +
 +    ImageIcon icon = new ImageIcon(
 + ClassLoader.getSystemResource("balzac.jpg"));
 +
 +    public ComboBox() {
 +
 +        setLayout(new BoxLayout(getContentPane(), 
 + BoxLayout.Y_AXIS));
 +        add(Box.createRigidArea(new Dimension(0, 35)));
 +
 +        display = new JLabel();
 +        display.setPreferredSize(new Dimension(100, 127));
 +        display.setMaximumSize(new Dimension(100, 127));
 +        display.setAlignmentX(Component.CENTER_ALIGNMENT);
 +        display.setBorder(LineBorder.createGrayLineBorder());
 +        add(display);
 +
 +        add(Box.createRigidArea(new Dimension(0, 15)));
 +
 +        combobox = new JComboBox(authors);
 +        combobox.setSelectedIndex(-1);
 +        combobox.setPreferredSize(new Dimension(140, 22));
 +        combobox.setMaximumSize(new Dimension(140, 22));
 +        combobox.addItemListener(this);
 +        add(combobox);
 +
 +        add(Box.createRigidArea(new Dimension(0, 15)));
 +
 +        button = new JButton("Close");
 +        button.setAlignmentX(Component.CENTER_ALIGNMENT);
 +        button.addActionListener(this);
 +        add(button);
 +
 +        setTitle("JComboBox");
 +        setSize(300, 300);
 +        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new ComboBox();
 +    }
 +
 +
 +    public void actionPerformed(ActionEvent e) {
 +        System.exit(0);
 +    }
 +
 +    public void itemStateChanged(ItemEvent e) {
 +
 +        if (e.getStateChange() == ItemEvent.SELECTED) {
 +            JComboBox combo = (JComboBox) e.getSource();
 +            int index = combo.getSelectedIndex();
 +            display.setIcon(new ImageIcon(
 +                ClassLoader.getSystemResource(images[index])));
 +        }
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +In our example, we have three components. A label, a combobox and a button. The button closes the window. 
 +We have six names of famous novelists in our combobox. If we select a name, an image is displayed in the label.
 +
 +
 +
 +
 +
 +<code java>
 +public class ComboBox extends JDialog implements 
 + ActionListener, ItemListener {
 +</code>
 +
 +
 +
 +
 +This is a dialog based application example.
 +
 +
 +
 +
 +
 +<code java>
 + display = new JLabel();
 +</code>
 +
 +
 +
 +
 +The display area is a simple **JLabel**.
 +
 +
 +
 +
 +<code java>
 + combobox = new JComboBox(authors);
 + combobox.setSelectedIndex(-1);
 +</code>
 +
 +
 +
 +
 +The constructor of the **JComboBox** takes a string array of novelists. If we provide -1 as an argument in the **setSelectedIndex()** method, no item to be selected.
 +
 +
 +
 +
 +<code java>
 + combobox.addItemListener(this);
 +</code>
 +
 +
 +
 +
 +We add an **ItemListener** to our combobox. In the event handler, we get the selected index of the combobox and set an appropriate icon for the label. The selected item is an index to the array of images.
 +
 +
 +
 +
 +<code java>
 +
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/combobox.jpg |JComboBox}}
 +
 +
 +
 +==== JProgressBar ====
 +
 +
 +
 +
 +A progress bar is a widget that is used, when we process lengthy tasks. It is animated so that the user knows, that our task is progressing. The **JProgressBar** widget provides a horizontal or vertical progress bar.
 +The initial and minimum values are 0, and the maximum is 100.
 +
 +
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.Box;
 +import javax.swing.BoxLayout;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.JProgressBar;
 +import javax.swing.Timer;
 +
 +
 +public class ProgressBar extends JFrame {
 +
 +    ActionListener updateProBar;
 +    Timer timer;
 +    JProgressBar progressBar;
 +    JButton button;
 +
 +    public ProgressBar() {
 +
 +        setTitle("JProgressBar");
 +
 +        JPanel panel = new JPanel();
 +        panel.setBorder(BorderFactory.createEmptyBorder(40, 40, 40, 40));
 +        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
 +
 +
 +
 +        progressBar = new JProgressBar();
 +
 +        progressBar.setMaximumSize(new Dimension(150, 20));
 +        progressBar.setMinimumSize(new Dimension(150, 20));
 +        progressBar.setPreferredSize(new Dimension(150, 20));
 +
 +        progressBar.setAlignmentX(0f);
 +
 +        panel.add(progressBar);
 +        panel.add(Box.createRigidArea(new Dimension(0, 20)));
 +
 +        button = new JButton("Start");
 +        button.setFocusable(false);
 +        button.setMaximumSize(button.getPreferredSize());
 +
 +        updateProBar = new ActionListener() {
 +            public void actionPerformed(ActionEvent actionEvent) {
 +                int val = progressBar.getValue();
 +                if (val >= 100) {
 +                    timer.stop();
 +                    button.setText("End");
 +                    return;
 +                }
 +
 +                progressBar.setValue(++val);
 +            }
 +        };
 +
 +        timer = new Timer(50, updateProBar);
 +
 +        button.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent e) {
 +                if (timer.isRunning()) {
 +                    timer.stop();
 +                    button.setText("Start");
 +
 +                } else if (button.getText() != "End") {
 +                    timer.start();
 +                    button.setText("Stop");
 +                }
 +
 +            }
 +        });
 +
 +
 +        panel.add(button);
 +        add(panel);
 +
 +        pack();
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setResizable(false);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        new ProgressBar();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +The example displays a progress bar and a button. The button starts and stops the progress. 
 +
 +
 +
 +
 +<code java>
 + progressBar = new JProgressBar();
 +</code>
 +
 +
 +
 +
 +Here we create the **JProgressBar**. The minimum value is 0, maximum 100 and the initial value is 0.
 +These are the default values.
 +
 +
 +
 +
 +<code java>
 + progressBar.setMaximumSize(new Dimension(150, 20));
 + progressBar.setMinimumSize(new Dimension(150, 20));
 + progressBar.setPreferredSize(new Dimension(150, 20));
 +</code>
 +
 +
 +
 +
 +These lines are for design purposes only. I want my examples to look nice. The default height on my box was only 14px
 +which looked bad.
 +
 +
 +
 +
 +<code java>
 +  progressBar.setAlignmentX(0f);
 +</code>
 +
 +
 +
 +
 +This line aligns both progress bar with the button. To the left.
 +
 +
 +
 +
 +
 +<code java>
 + panel.add(Box.createRigidArea(new Dimension(0, 20)));
 +</code>
 +
 +
 +
 +
 +Here we put some rigid space between the two components.
 +
 +
 +
 +
 +<code java>
 + button.setFocusable(false);
 +</code>
 +
 +
 +
 +
 +Focus looks bad, better disable it.
 +
 +
 +
 +
 +<code java>
 + timer = new Timer(50, updateProBar);
 +</code>
 +
 +
 +
 +
 +The timer object launches updateProBar listener every 50ms. Inside that listener,  we check, if the progress bar reached
 +the value 100 and stop the timer, or update the progress bar.
 +
 +
 +
 +
 +<code java>
 + if (timer.isRunning()) {
 +     timer.stop();
 +     button.setText("Start");
 +
 + } else if (button.getText() != "End") {
 +     timer.start();
 +     button.setText("Stop");
 + }
 +</code>
 +
 +
 +
 +
 +Clicking on the button starts or stops the progress. The text of the button is updated dynamically. It can have Start, Stop or End String values. 
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/progressbar.jpg |JProgressBar}}
 +
 +
 +
 +==== JToggleButton ====
 +
 +
 +
 +
 +**JToggleButton** is a button that has two states. Pressed and not pressed. You toggle between these two states by clicking on it. There are situations where this functionality fits well.
 +
 +
 +
 +
 +<code java>
 +import java.awt.Color;
 +import java.awt.Dimension;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.Box;
 +import javax.swing.BoxLayout;
 +import javax.swing.JDialog;
 +import javax.swing.JPanel;
 +import javax.swing.JToggleButton;
 +import javax.swing.border.LineBorder;
 +
 +
 +public class ToggleButton extends JDialog implements ActionListener {
 +
 +    private JToggleButton red;
 +    private JToggleButton green;
 +    private JToggleButton blue;
 +    private JPanel display;
 +
 +    public ToggleButton() {
 +
 +        setTitle("JToggleButton");
 +
 +        JPanel bottom = new JPanel();
 +        bottom.setLayout(new BoxLayout(bottom, BoxLayout.X_AXIS));
 +        bottom.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 +
 +        JPanel leftPanel = new JPanel();
 +        leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
 +
 +        red = new JToggleButton("red");
 +        red.addActionListener(this);
 +
 +        green = new JToggleButton("green");
 +        green.addActionListener(this);
 +
 +        blue = new JToggleButton("blue");
 +        blue.addActionListener(this);
 +
 +        blue.setMaximumSize(green.getMaximumSize());
 +        red.setMaximumSize(green.getMaximumSize());
 +
 +        leftPanel.add(red);
 +        leftPanel.add(Box.createRigidArea(new Dimension(25, 7)));
 +        leftPanel.add(green);
 +        leftPanel.add(Box.createRigidArea(new Dimension(25, 7)));
 +        leftPanel.add(blue);
 +
 +
 +        bottom.add(leftPanel);
 +        bottom.add(Box.createRigidArea(new Dimension(20, 0)));
 +
 +        display = new JPanel();
 +        display.setPreferredSize(new Dimension(110, 110));
 +        display.setBorder(LineBorder.createGrayLineBorder());
 +        display.setBackground(Color.black);    
 +
 +        bottom.add(display);
 +        add(bottom);
 +
 +        pack();
 +        setResizable(false);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +
 +
 +    public static void main(String[] args) {
 +        new ToggleButton();    
 +    }
 +
 +    public void actionPerformed(ActionEvent e) {
 +
 +        Color color = display.getBackground();
 +        int red = color.getRed();
 +        int green = color.getGreen();
 +        int blue = color.getBlue();
 +
 +        if (e.getActionCommand() == "red") {
 +            if (red == 0) {
 +                red = 255;  
 +            } else {
 +                red = 0;
 +            }
 +        }
 +
 +        if (e.getActionCommand() == "green") {
 +            if (green == 0) {
 +                green = 255;  
 +            } else {
 +                green = 0;
 +            }
 +        }
 +
 +        if (e.getActionCommand() == "blue") {
 +            if (blue == 0) {
 +                blue = 255;  
 +            } else {
 +                blue = 0;
 +            }
 +        }
 +
 +        Color setCol = new Color(red, green, blue);
 +        display.setBackground(setCol);
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +The example has three panels and three toggle buttons. Panels are bottom panel, left panel and display panel. The bottom panel is use to organize the left and display panels. For this, we use horizontal **BoxLayout** manager.
 +The left panel will holt three toggle buttons. This time we use vertical **BoxLayout** manager.
 +We set the background color of the display panel to black. The toggle buttons will toggle the red, green and blue parts of the color value. The background color will depend on which togglebuttons we have pressed.
 +
 +
 +
 +
 +
 +<code java>
 + red = new JToggleButton("red");
 + red.addActionListener(this);
 +</code>
 +
 +
 +
 +
 +Here we create a toggle button and set an action listener to it. 
 +
 +
 +
 +
 +<code java>
 + blue.setMaximumSize(green.getMaximumSize());
 + red.setMaximumSize(green.getMaximumSize());
 +</code>
 +
 +
 +
 +
 +We make all three buttons of equal size. 
 +
 +
 +
 +
 +
 +<code java>
 + Color color = display.getBackground();
 + int red = color.getRed();
 + int green = color.getGreen();
 + int blue = color.getBlue();
 +</code>
 +
 +
 +
 +
 +In the **actionPerformed** method, we determine the current red, green, blue parts of the
 +display background color.
 +
 +
 +
 +
 +<code java>
 + if (e.getActionCommand() == "red") {
 +     if (red == 0) {
 +         red = 255;  
 +     } else {
 +        red = 0;
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +We determine, which button was toggled, and update the color part of the RGB value accordingly.
 +
 +
 +
 +
 +<code java>
 + Color setCol = new Color(red, green, blue);
 + display.setBackground(setCol);
 +</code>
 +
 +
 +
 +
 +Here a new color is created and the display panel is updated to a new color.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/togglebutton.jpg |JToggleButton}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== المكونات الأساسية للمكتبة Swing (الجزء الثانى) =====
 +
 +
 +
 +
 +
 +مكونات (أدوات) Swing هى المكون الأساسى لبناء التطبيق. و تحتوى مكتبة Swing على العديد من الأدوات المختلفة. منها الأزار Buttons و صناديق الإختيار check boxesو  المنزلقات sliders و صناديق القائمة list boxes..إلخ.و من الواضح أن هذا كل ما يحتاجه المبرمج لعمله.و فى هذا الجزء من الدرس سوف نشرح العديد من المكونات (الأدوات) المفيدة.
 +
 +
 +
 +
 +
 +==== الأداة JList (قائمة) ====
 +
 +
 +
 +
 +**JList** هى عبارة عن أداة تعرض قائمة من العناصر و تسمح أيضاً بتحديد أى منهم, واحد أو أكثر.
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Dimension;
 +import java.awt.Font;
 +import java.awt.GraphicsEnvironment;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JList;
 +import javax.swing.JPanel;
 +import javax.swing.JScrollPane;
 +import javax.swing.UIManager;
 +import javax.swing.event.ListSelectionEvent;
 +import javax.swing.event.ListSelectionListener;
 +
 +
 +public class List extends JFrame {
 +
 +    private JLabel label;
 +    private JList list;
 +
 +
 +    public List() {
 +
 +        setTitle("List");
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(new BorderLayout());
 +        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 +
 +        GraphicsEnvironment ge = 
 +            GraphicsEnvironment.getLocalGraphicsEnvironment();
 +
 +        String[] fonts = ge.getAvailableFontFamilyNames();
 +
 +        list = new JList(fonts);
 +        list.addListSelectionListener(new ListSelectionListener() {
 +            public void valueChanged(ListSelectionEvent e) {
 +                if (!e.getValueIsAdjusting()) {
 +                    String name = (String) list.getSelectedValue();
 +                    Font font = new Font(name, Font.PLAIN, 12);
 +                    label.setFont(font);
 +                }
 +            }
 +        });
 +
 +        JScrollPane pane = new JScrollPane();
 +        pane.getViewport().add(list);
 +        pane.setPreferredSize(new Dimension(250, 200));
 +        panel.add(pane);
 +
 +        label = new JLabel("Aguirre, der Zorn Gottes");
 +        label.setFont(new Font("Serif", Font.PLAIN, 12));
 +        add(label, BorderLayout.SOUTH);
 +
 +
 +        add(panel);
 +
 +        pack();
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +
 +    }
 +
 +    public static void main(String[] args) {
 +        new List();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +فى هذا المثال سوف نعرض أداتين هما  **JList** و **JLabel** (أداتى قائمة و عنوان)   
 +الأداة List  تحتوى على جميع اسماء الخطوط المثبتة بالنظام, إذا حددنا أحد اسماء الخطوط فى القائمة فسيتم عرضه بداخل الأداة Label.
 +
 +
 +
 +
 +
 +<code java>
 + GraphicsEnvironment ge = 
 +     GraphicsEnvironment.getLocalGraphicsEnvironment();
 +
 + String[] fonts = ge.getAvailableFontFamilyNames();
 +</code>
 +
 +
 +
 +
 +هنا حصلنا على كل الخطوط المتاحة المثبته بالنظام. 
 +
 +
 +
 +
 +<code java>
 + list = new JList(fonts);
 +</code>
 +
 +
 +
 +
 + قمنا بإنشاء أداة **JList** .
 +
 +
 +
 +
 +<code java>
 + public void valueChanged(ListSelectionEvent e) {
 +     if (!e.getValueIsAdjusting()) {
 +</code>
 +
 +
 +
 +
 +ربما تكون هذه القطعة من الكود مربكة قليلاً. فأحداث التحديد فى القائمة list عبارة عن مجموعة. فنحن نستلم الحدثبن معاً التحديد و إلغاء التحديد.
 +و لكى نحصل على حدث التحديد فقط فإننا نستخدم الدالة **getValueIsAdjusting()** , لماذا هذا الاسم الغريب؟ ليست هناك أدنى فكرة.
 +
 +
 +
 +
 +<code java>
 + String name = (String) list.getSelectedValue();
 + Font font = new Font(name, Font.PLAIN, 12);
 + label.setFont(font);
 +</code>
 +
 +
 +
 +
 +هنا نححصل على العنصر المحدد و نعرض خط جديد باسم العنصر المحدد فى الأداة label.
 +
 +
 +
 +
 +<code java>
 + JScrollPane pane = new JScrollPane();
 + pane.getViewport().add(list);
 +</code>
 +
 +
 +
 +
 +من المشوق أن الأداة JLabel افتراضياً لا تدعم التمرير, لذلك لا بد من وضعها داخل أداة JScrollPane لجعلها تدعم التمرير.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/list.jpg |JList}}
 +
 +
 +
 +==== الأداة JTextArea (صندوق نصى) ====
 +
 +
 +
 +
 +**JTextArea** هى عبارة عن أداة لعرض النصوص العادية و يمكنها عرض الأسطر المتعددة. و تعتبر أداة خفيفة فى العمل مع النصوص. و هذه الأداة لا تدعم التمرير لذلك سوف نستخدم الأداة **JScrollPane** لجعلها تدعم التمرير.
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Dimension;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.JScrollPane;
 +import javax.swing.JTextArea;
 +
 +
 +public class TextArea extends JFrame {
 +
 +    public TextArea() {
 +
 +        setTitle("JTextArea");
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(new BorderLayout());
 +        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 +
 +        JScrollPane pane = new JScrollPane();
 +        JTextArea area = new JTextArea(); 
 +
 +        area.setLineWrap(true);
 +        area.setWrapStyleWord(true);
 +        area.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
 +
 +        pane.getViewport().add(area);
 +        panel.add(pane);
 +
 +        add(panel);
 +        setSize(new Dimension(350, 300));
 +
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        new TextArea();
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +يعرض المثال أداة نص **JTextArea** بسيطة مع مقتطفات من خطاب لـ Martin Luther King.
 +
 +
 +
 +
 +<code java>
 + JTextArea area = new JTextArea(); 
 +</code>
 +
 +
 +
 +
 +هنا أنشأنا الأداة **JTextArea**.
 +
 +
 +
 +
 +<code java>
 + area.setLineWrap(true);
 +</code>
 +
 +
 +
 +
 +جعل اسطور منسقة لتتناسب مع عرض الأداة.
 +
 +
 +
 +
 +<code java>
 + area.setWrapStyleWord(true);
 +</code>
 +
 +
 +
 +
 +هنا نحدد كيف تكون السطور منسقة و فى هذه الحالة فإنا ستكون عن طريق حدود الكلمات, ألا و هى الفراغات.
 +
 +
 +
 +<code java>
 + area.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
 +</code>
 +
 +
 +
 +
 +وضعنا بعض الحدود حول أداة النصوص.
 +
 +
 +
 +
 +<code java>
 + pane.getViewport().add(area);
 +</code>
 +
 +
 +
 +
 +لجعل الأداة **JTextArea** قابلة للتمرير وضعناها داخل أداة **JScrollPane**.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/textarea.jpg |JTextArea}}
 +
 +
 +====  الأداة JTextPane ====
 +
 +
 +
 +
 +**JTextPane** هى عبارة عن أداة أكثر تقدماً فى التعامل مع النصوص. فهى تستطيع أن تقوم ببعض عمليات التنسيق المعقدة على النص. كما يمكنها عرض وثائق html.
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Dimension;
 +
 +import java.io.IOException;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.JScrollPane;
 +import javax.swing.JTextPane;
 +
 +
 +public class TextPane extends JFrame {
 +
 +    public TextPane() {
 +
 +        setTitle("JTexPane");
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(new BorderLayout());
 +        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 +
 +        JScrollPane pane = new JScrollPane();
 +        JTextPane textpane = new JTextPane(); 
 +
 +        textpane.setContentType("text/html");
 +        textpane.setEditable(false);
 +
 +        String cd = System.getProperty("user.dir") + "/";
 +
 +        try {
 +            textpane.setPage("File:///" + cd + "test.html");
 +        } catch (IOException e) {
 +            System.out.println("Exception: " + e);
 +        }
 +
 +        textpane.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
 +
 +        pane.getViewport().add(textpane);
 +        panel.add(pane);
 +
 +        add(panel);
 +        setSize(new Dimension(380, 320));
 +
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        new TextPane();    
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +ها هو كود html و الذى سوف نعرضه داخل الأداة **JTextPane**, و مع العلم فإن الأداة لا تتعامل مع التمرير.
 +
 +
 +
 +
 +<code java>
 +&lt;html&gt;
 +&lt;head&gt;
 +&lt;title&gt;A simple html document&lt;/title&gt;
 +&lt;/head&gt;
 +&lt;body&gt;
 +
 +&lt;h2&gt;A simple html document&lt;/h2&gt;
 +
 +
 +&lt;p&gt;
 +&lt;b&gt;JTextPane&lt;/b&gt; can display html documents. 
 +&lt;/p&gt;
 +
 +&lt;br&gt;
 +
 +&lt;pre&gt;
 + JScrollPane pane = new JScrollPane();
 + JTextPane textpane = new JTextPane(); 
 +
 + textpane.setContentType("text/html");
 + textpane.setEditable(false);
 +&lt;/pre&gt;
 +
 +&lt;br&gt;
 +&lt;small&gt;The Java Swing tutorial, 2007&lt;/small&gt;
 +
 +&lt;/body&gt;
 +
 +&lt;/html&gt;
 +</code>
 +
 +
 +
 +
 +
 +فى هذا المثال عرضنا **JTextPane** و قمنا بتحميل وثيقة html و يعرض أيضاً هذا المثال قدرات التنسيق لهذه الأداة. 
 +
 +
 +
 +
 +<code java>
 + JTextPane textpane = new JTextPane(); 
 +
 + textpane.setContentType("text/html");
 + textpane.setEditable(false);
 +</code>
 +
 +
 +
 +
 +قمنا بإنشاء الأداة **JTextPane** و جعلنا محتوى الأداة هو وثيقة html ثم عطلنا إمكانية التعديل.
 +
 +
 +
 +
 +<code java>
 + String cd = System.getProperty("user.dir") + "/";
 +</code>
 +
 +
 +
 +
 +هنا حددنا مجلد العمل الحالى للمستخدم و الذى به وثيقة الـhtml.
 +
 +
 +
 +
 +<code java>
 + try {
 +     textpane.setPage("File:///" + cd + "test.html");
 + } catch (IOException e) {
 +     System.out.println("Exception: " + e);
 + }
 +</code>
 +
 +
 +
 +
 +هنا حملنا الوثيقة بداخل اللوحة pane. 
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/textpane.jpg |JTextPane}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Java Swing model architecture =====
 +
 +
 +
 +
 +
 +بنى مهندسو swing المكتبة على أساس مبدأ Model View Controller معدل
 +و بهذا تكون هناك كفاءة فى التعامل مع البيانات و الأداوت أثناء وقت التشغيل لبرنامج.
 +
 +
 +
 +
 +
 +
 +اسلوب التصميم MVC يقسم التطبيق إلى ثلاثة أجزاء و هم Model و View و Controller . و هنا يمثل الجزء Model البيانات فى التطبيق و الجزء View  هو الممثل المرئى للبيانات, أما الجزء Controller  فيعالج و يستجيب للأحداث, و هى الأحداث الذى يقوم بها مستخدم التطبيق و ربما أيضاً يقوم بتغييرات على الجزء Model. تتمثل الفكرة فى فصل تفاعلات المستخدم و عرض البيانات من الوصول إلى البيانات و منطق عمل التطبيق و التى تتمثل فى الوسيط Controller.
 +
 +
 +
 +
 +
 +
 +
 +تستخدم مكتبة Swing اسلوب تصميم معدل من اسلوب MVC فهى تحتوى على عنصر واجهة مستخدم **UI object** منفرد لكل من الجزئين View و .  و فى بعض الأحيان يدعى هذا الاسلوب المعدل بهيكل النموذج القابل للفصل.Controller.
 +
 +
 +
 +
 +
 +
 +
 +فى مكتبة swing لكل أداة model خاص به, حتى الأدوات البسيطة مثل الأزرار buttons . و هناك نوعان من 
 +
 +
 +
 +
 +  * state models
 +  * data models
 +
 +
 +
 +
 +
 +The state models handle the state of the component. For example the model keeps track whether the component is selected or pressed. The data models handle data, they work with. A list component keeps a list of items, it is displaying. 
 +
 +
 +
 +
 +
 +
 +
 +
 +For Swing developer it means, that we often need to get a model instance in order to manipulate the data in the component. 
 +But there are exceptions. For convenience, there are some methods that return data without the model.
 +
 +
 +
 +
 +<code java>
 + public int getValue() { 
 +     return getModel().getValue(); 
 + }
 +</code>
 +
 +
 +
 +
 +For example the **getValue()** method of the **JSlider** component. 
 +The developer does not need to work with the model directly. Instead, the access to the model is done behind the scenes.
 +It would be an overkill to work with models directly in such simple situations. Because of this, the Swing tookit provides some convenience methods like the previous one.
 +
 +
 +
 +
 +
 +
 +
 +To query the state of the model, we have two kinds of notifications.
 +
 +
 +
 +
 +
 +  * lightweight notification
 +  * stateful notification
 +
 +
 +
 +
 +
 +
 +The lightweight notification uses a **ChangeListener** class. We have only one single event 
 +(**ChangeEvent)**
 +for all notifications coming from the component. For more complicated components, the stateful notification is used.
 +For such notifications, we have different kinds of events. For example the **JList** component has **ListDataEvent** and **ListSelectionEvent**. 
 +
 +
 +
 +
 +
 +
 +
 +If we do not set a model for a component, a default one is created. For example the button component has 
 +**DefaultButtonModel** model
 +
 +
 +
 +
 +<code java>
 + public JButton(String text, Icon icon) {
 + // Create the model
 + setModel(new DefaultButtonModel());
 +
 + // initialize
 + init(text, icon);
 +}
 +</code>
 +
 +
 +
 +
 +If we look at the JButton.java source file, we find out, that the default model is created at the construction of the component. 
 +
 +
 +
 +
 +
 +==== ButtonModel ====
 +
 +
 +
 +يستخدم الـmodel للعديد من أنواع الأزار مثل ازرار الضغط (push buttnons) و أزرار 
 +
 +
 +
 +
 +<code java>
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.DefaultButtonModel;
 +import javax.swing.JButton;
 +import javax.swing.JCheckBox;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +import javax.swing.event.ChangeEvent;
 +import javax.swing.event.ChangeListener;
 +
 +
 +public class ButtonModel extends JFrame {
 +
 +    private JButton ok;
 +    private JLabel enabled;
 +    private JLabel pressed;
 +    private JLabel armed;
 +
 +    public ButtonModel() {
 +
 +        setTitle("ButtonModel");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(null);
 +
 +        ok = new JButton("ok");
 +        JCheckBox cb = new JCheckBox("Enabled", true);
 +
 +        ok.setBounds(40, 30, 80, 25);
 +        ok.addChangeListener(new ChangeListener() {
 +            public void stateChanged(ChangeEvent e) {
 +
 +            DefaultButtonModel model = (DefaultButtonModel) ok.getModel();
 +            if (model.isEnabled())
 +                enabled.setText("Enabled: true");
 +            else
 +                enabled.setText("Enabled: false");
 +
 +            if (model.isArmed())
 +                armed.setText("Armed: true");
 +            else
 +                armed.setText("Armed: false");
 +
 +            if (model.isPressed())
 +                pressed.setText("Pressed: true");
 +            else
 +                pressed.setText("Pressed: false");
 +            }
 +
 +        });
 +
 +        cb.addActionListener(new ActionListener() {
 +
 +            public void actionPerformed(ActionEvent e) {
 +                if (ok.isEnabled())
 +                    ok.setEnabled(false);
 +                else 
 +                    ok.setEnabled(true);
 +            }
 +        });
 +
 +        cb.setBounds(180, 30, 100, 25);
 +
 +        enabled = new JLabel("Enabled: true");
 +        enabled.setBounds(40, 90, 90, 25);
 +        pressed = new JLabel("Pressed: false");
 +        pressed.setBounds(40, 120, 90, 25);
 +        armed  = new JLabel("Armed: false");
 +        armed.setBounds(40, 150, 90, 25);
 +
 +        panel.add(ok);
 +        panel.add(cb);
 +        panel.add(enabled);
 +        panel.add(pressed);
 +        panel.add(armed);
 +
 +        add(panel);
 +
 +        setSize(350, 250);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new ButtonModel();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +In our example, we have a button, check box and three labels. The labels represent three properties of the button.
 +Whether it is pressed, disabled or armed.
 +
 +
 +
 +
 +
 +<code java>
 + ok.addChangeListener(new ChangeListener() {
 +</code>
 +
 +
 +
 +
 +We use a lightweight **ChangeListener** to listen for button state changes.
 +
 +
 +
 +
 +<code java>
 + DefaultButtonModel model = (DefaultButtonModel) ok.getModel();
 +</code>
 +
 +
 +
 +
 +Here we get the default button model.
 +
 +
 +
 +
 +<code java>
 + if (model.isEnabled())
 +     enabled.setText("Enabled: true");
 + else
 +     enabled.setText("Enabled: false");
 +</code>
 +
 +
 +
 +
 +We query the model, whether the button is enabled or not. We update the label accordingly.
 +
 +
 +
 +
 +<code java>
 + if (ok.isEnabled())
 +     ok.setEnabled(false);
 + else 
 +     ok.setEnabled(true);
 +</code>
 +
 +
 +
 +
 +The check box enables or disables the button. To enable the ok button, we call the **setEnable()**
 +method. So we change the state of the button. Where is the model? The answer lies in the AbstractButton.java file. 
 +
 +
 +
 +
 +<code java>
 + public void setEnabled(boolean b) {
 +     if (!b && model.isRollover()) {
 +         model.setRollover(false);
 +     
 +     super.setEnabled(b);
 +     model.setEnabled(b);
 + }
 +</code>
 +
 +
 +
 +
 +The answer is, that internally, we the Swing toolkit works with a model. The **setEnable()** is another convenience method for programmers. 
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/buttonmodel.png |ButtonModel}}
 +
 +
 +==== Custom ButtonModel ====
 +
 +
 +
 +
 +In the previous example, we used a default button model. In the following code example we will use our own 
 +button model. 
 +
 +
 +
 +
 +<code java>
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.ButtonModel;
 +import javax.swing.DefaultButtonModel;
 +import javax.swing.JButton;
 +import javax.swing.JCheckBox;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +
 +
 +public class ButtonModel2 extends JFrame {
 +
 +    private JButton ok;
 +    private JLabel enabled;
 +    private JLabel pressed;
 +    private JLabel armed;
 +
 +    public ButtonModel2() {
 +
 +        setTitle("ButtonModel");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(null);
 +
 +        ok = new JButton("ok");
 +        JCheckBox cb = new JCheckBox("Enabled", true);
 +
 +        ok.setBounds(40, 30, 80, 25);
 +
 +        cb.addActionListener(new ActionListener() {
 +
 +            public void actionPerformed(ActionEvent e) {
 +                if (ok.isEnabled())
 +                    ok.setEnabled(false);
 +                else 
 +                    ok.setEnabled(true);
 +            }
 +        });
 +
 +        cb.setBounds(180, 30, 100, 25);
 +
 +        enabled = new JLabel("Enabled: true");
 +        enabled.setBounds(40, 90, 90, 25);
 +        pressed = new JLabel("Pressed: false");
 +        pressed.setBounds(40, 120, 90, 25);
 +        armed  = new JLabel("Armed: false");
 +        armed.setBounds(40, 150, 90, 25);
 +
 +        ButtonModel model = new DefaultButtonModel() {
 +            public void setEnabled(boolean b) {
 +                if (b)
 +                    enabled.setText("Pressed: true");
 +                else 
 +                    enabled.setText("Pressed: false");
 +
 +                super.setEnabled(b);
 +            }
 +
 +            public void setArmed(boolean b) {
 +                if (b)
 +                    armed.setText("Armed: true");
 +                else
 +                    armed.setText("Armed: false");
 +
 +                super.setArmed(b);
 +            }
 +
 +            public void setPressed(boolean b) {
 +                if (b)
 +                    pressed.setText("Pressed: true");
 +                else 
 +                    pressed.setText("Pressed: false");
 +
 +                super.setPressed(b);
 +            }
 +
 +        };
 +
 +        ok.setModel(model);
 +
 +        panel.add(ok);
 +        panel.add(cb);
 +        panel.add(enabled);
 +        panel.add(pressed);
 +        panel.add(armed);
 +
 +        add(panel);
 +
 +        setSize(350, 250);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new ButtonModel2();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +This example does the same thing as the previous one. The difference is that we don't use a change listener and
 +we use a custom button model. 
 +
 +
 +
 +
 +<code java>
 + ButtonModel model = new DefaultButtonModel() {
 +</code>
 +
 +
 +
 +
 +We create a button model and overwrite the necessary methods. 
 +
 +
 +
 +
 +<code java>
 + public void setEnabled(boolean b) {
 +     if (b)
 +         enabled.setText("Pressed: true");
 +     else 
 +         enabled.setText("Pressed: false");
 +
 +     super.setEnabled(b);
 +}
 +</code>
 +
 +
 +
 +
 +We overwrite the **setEnabled()** method and add some functionality there. We must not forget to call the parent method as well to procede with the processing. 
 +
 +
 +
 +
 +
 +<code java>
 + ok.setModel(model);
 +</code>
 +
 +
 +
 +
 +We set the custom model for the button.
 +
 +
 +
 +
 +
 +==== JList models ====
 +
 +
 +
 +
 +Several components have two models. The **JList** component has the following models:
 +**ListModel** and **ListSelectionModel**. The ListModel handles data. And the
 +ListSelectionModel works with the GUI. The following example shows both models. 
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Dimension;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.event.MouseAdapter;
 +import java.awt.event.MouseEvent;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.Box;
 +import javax.swing.BoxLayout;
 +import javax.swing.DefaultListModel;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JList;
 +import javax.swing.JOptionPane;
 +import javax.swing.JPanel;
 +import javax.swing.JScrollPane;
 +import javax.swing.ListSelectionModel;
 +
 +
 +public class List extends JFrame {
 +
 +    private DefaultListModel model;
 +    private JList list;
 +
 +    public List() {
 +
 +        setTitle("JList models");
 +
 +        model = new DefaultListModel();
 +        model.addElement("Amelie");
 +        model.addElement("Aguirre, der Zorn Gottes");
 +        model.addElement("Fargo");
 +        model.addElement("Exorcist");
 +        model.addElement("Schindler list");
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
 +
 +        JPanel leftPanel = new JPanel();
 +        JPanel rightPanel = new JPanel();
 +
 +        leftPanel.setLayout(new BorderLayout());
 +        rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
 +
 +        list = new JList(model);
 +        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 +        list.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
 +
 +        list.addMouseListener(new MouseAdapter() {
 +
 +            public void mouseClicked(MouseEvent e) {
 +                if(e.getClickCount() == 2){
 +                  int index = list.locationToIndex(e.getPoint());
 +                  Object item = model.getElementAt(index);
 +                  String text = JOptionPane.showInputDialog("Rename item", item);
 +                  String newitem = null;
 +                  if (text != null) 
 +                     newitem = text.trim();
 +                  else 
 +                     return;
 +
 +                  if (!newitem.isEmpty()) {
 +                    model.remove(index);
 +                    model.add(index, newitem);
 +                    ListSelectionModel selmodel = list.getSelectionModel();
 +                    selmodel.setLeadSelectionIndex(index);
 +                  }
 +                }
 +            }
 +
 +        });
 +
 +        JScrollPane pane = new JScrollPane();
 +        pane.getViewport().add(list);  
 +        leftPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 +
 +        leftPanel.add(pane);
 +
 +        JButton removeall = new JButton("Remove All");
 +        JButton add = new JButton("Add");
 +        add.setMaximumSize(removeall.getMaximumSize());
 +        JButton rename = new JButton("Rename");
 +        rename.setMaximumSize(removeall.getMaximumSize());
 +        JButton delete = new JButton("Delete");
 +        delete.setMaximumSize(removeall.getMaximumSize());
 +
 +        add.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent e) {
 +                String text = JOptionPane.showInputDialog("Add a new item");
 +                String item = null;
 +
 +                if (text != null) 
 +                    item = text.trim();
 +                else 
 +                    return;
 +
 +                if (!item.isEmpty())
 +                    model.addElement(item);
 +            }
 +        });
 +
 +        delete.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                ListSelectionModel selmodel = list.getSelectionModel();
 +                int index = selmodel.getMinSelectionIndex();
 +                if (index >= 0)
 +                    model.remove(index);
 +            }
 +
 +        });
 +
 +        rename.addActionListener(new ActionListener() {
 +
 +            public void actionPerformed(ActionEvent e) {
 +                ListSelectionModel selmodel = list.getSelectionModel();
 +                int index = selmodel.getMinSelectionIndex();
 +                if (index == -1) return;
 +                Object item = model.getElementAt(index);
 +                String text = JOptionPane.showInputDialog("Rename item", item);
 +                String newitem = null;
 +
 +                if (text != null) {
 +                    newitem = text.trim();
 +                } else
 +                    return;
 +
 +                if (!newitem.isEmpty()) {
 +                    model.remove(index);
 +                    model.add(index, newitem);
 +                }
 +            }
 +        });
 +
 +        removeall.addActionListener(new ActionListener() {
 +                public void actionPerformed(ActionEvent e) {
 +                    model.clear();
 +                }
 +        });
 +
 +        rightPanel.add(add);
 +        rightPanel.add(Box.createRigidArea(new Dimension(0,4)));
 +        rightPanel.add(rename);
 +        rightPanel.add(Box.createRigidArea(new Dimension(0,4)));
 +        rightPanel.add(delete);
 +        rightPanel.add(Box.createRigidArea(new Dimension(0,4)));
 +        rightPanel.add(removeall);
 +
 +        rightPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 20));
 +
 +        panel.add(leftPanel);
 +        panel.add(rightPanel);
 +
 +        add(panel);
 +
 +        setSize(350, 250);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new List();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +The example shows a list component and four buttons. The buttons control the data in the list component. 
 +The example is a bit larger, because we did some additional checks there. We do not allow to input empty spaces into the 
 +list component. 
 +
 +
 +
 +
 +<code java>
 + model = new DefaultListModel();
 + model.addElement("Amelie");
 + model.addElement("Aguirre, der Zorn Gottes");
 + ...
 +</code>
 +
 +
 +
 +
 +We create a list model and add elements into it.
 +
 +
 +
 +
 +<code java>
 + list = new JList(model);
 + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 + list.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
 +</code>
 +
 +
 +
 +
 +We create a list component. The parameter of the constructor is the model, we have created. 
 +We put the list into the single selection mode. We also put some space around the list. 
 +
 +
 +
 +
 +
 +<code java>
 + if (text != null) 
 +     item = text.trim();
 + else 
 +     return;
 +
 + if (!item.isEmpty())
 +     model.addElement(item);
 +</code>
 +
 +
 +
 +
 +We add only items that are not equal to null and are not empty. e.g. that contain at least one character other than white
 +space. It makes no sense to add white spaces or null values into the list. 
 +
 +
 +
 +
 +<code java>
 + ListSelectionModel selmodel = list.getSelectionModel();
 + int index = selmodel.getMinSelectionIndex();
 + if (index >= 0)
 +     model.remove(index);
 +</code>
 +
 +
 +
 +
 +This is the code, that runs when we press the delete button. In order to delete an item from the list, it must
 +be selected. So we must figure out the currently selected item. For this, we call the **getSelectionModel()** method This is a GUI work, so we use a 
 +**ListSelectionModel**. Removing an item is working with data. For that we use the list data model.
 +
 +
 +
 +
 +
 +
 +
 +So, in our example we used both list models. We called add(), remove() and clear() methods of the list data model to work with our data. 
 +And we used a list selection model in order to find out the selected item, which is a GUI job. 
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/listmodels.png |List Models}}
 +
 +
 +
 +==== A document model ====
 +
 +
 +
 +
 +This is an excellent example of a separation of a data from the visual representation. In a **JTextPane** component, we have a **StyledDocument** for setting the style of the text data. 
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Dimension;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.BorderFactory;
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +import javax.swing.JScrollPane;
 +import javax.swing.JTextPane;
 +import javax.swing.JToolBar;
 +import javax.swing.text.Style;
 +import javax.swing.text.StyleConstants;
 +import javax.swing.text.StyledDocument;
 +
 +
 +public class DocumentModel extends JFrame {
 +
 +    private StyledDocument doc;
 +    private JTextPane textpane;
 +
 +    public DocumentModel() {
 +
 +        setTitle("Document Model");
 +
 +        JToolBar toolbar = new JToolBar();
 +
 +        ImageIcon bold = new ImageIcon("bold.png");
 +        ImageIcon italic = new ImageIcon("italic.png");
 +        ImageIcon strike = new ImageIcon("strike.png");
 +        ImageIcon underline = new ImageIcon("underline.png");
 +
 +        JButton boldb = new JButton(bold);
 +        JButton italb = new JButton(italic);
 +        JButton strib = new JButton(strike);
 +        JButton undeb = new JButton(underline);
 +
 +        toolbar.add(boldb);
 +        toolbar.add(italb);
 +        toolbar.add(strib);
 +        toolbar.add(undeb);
 +
 +        add(toolbar, BorderLayout.NORTH);
 +
 +        JPanel panel = new JPanel();
 +        panel.setLayout(new BorderLayout());
 +        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 +
 +        JScrollPane pane = new JScrollPane();
 +        textpane = new JTextPane(); 
 +        textpane.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
 +
 +        doc = textpane.getStyledDocument();
 +
 +        Style style = textpane.addStyle("Bold", null);
 +        StyleConstants.setBold(style, true);
 +
 +        style = textpane.addStyle("Italic", null);
 +        StyleConstants.setItalic(style, true);
 +
 +        style = textpane.addStyle("Underline", null);
 +        StyleConstants.setUnderline(style, true);
 +
 +        style = textpane.addStyle("Strike", null);
 +        StyleConstants.setStrikeThrough(style, true);
 +
 +
 +        boldb.addActionListener(new ActionListener() {
 +
 +            public void actionPerformed(ActionEvent e) {
 +                doc.setCharacterAttributes(textpane.getSelectionStart(), 
 +                    textpane.getSelectionEnd() - textpane.getSelectionStart(),
 +                    textpane.getStyle("Bold"), false);
 +            }
 +        });
 +
 +        italb.addActionListener(new ActionListener() {
 +
 +            public void actionPerformed(ActionEvent e) {
 +                doc.setCharacterAttributes(textpane.getSelectionStart(), 
 +                    textpane.getSelectionEnd() - textpane.getSelectionStart(),
 +                    textpane.getStyle("Italic"), false);
 +            }
 +
 +        });
 +
 +        strib.addActionListener(new ActionListener() {
 +
 +            public void actionPerformed(ActionEvent e) {
 +                doc.setCharacterAttributes(textpane.getSelectionStart(), 
 +                    textpane.getSelectionEnd() - textpane.getSelectionStart(),
 +                    textpane.getStyle("Strike"), false);
 +            }
 +
 +        });
 +
 +        undeb.addActionListener(new ActionListener() {
 +
 +            public void actionPerformed(ActionEvent e) {
 +                doc.setCharacterAttributes(textpane.getSelectionStart(), 
 +                    textpane.getSelectionEnd() - textpane.getSelectionStart(),
 +                    textpane.getStyle("Underline"), false);
 +            }
 +        });
 +
 +        pane.getViewport().add(textpane);
 +        panel.add(pane);
 +
 +        add(panel);
 +
 +        setSize(new Dimension(380, 320));
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new DocumentModel();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +The example has a text pane and a toolbar. In the toolbar, we have four buttons, that change attributes of the text.
 +
 +
 +
 +
 +<code java>
 + doc = textpane.getStyledDocument();
 +</code>
 +
 +
 +
 +
 +Here we get the styled document, which is a model for the text pane component. 
 +
 +
 +
 +
 +<code java>
 + Style style = textpane.addStyle("Bold", null);
 + StyleConstants.setBold(style, true);
 +</code>
 +
 +
 +
 +
 +A style is a set of text attributes, such as color, size. Here we register a bold style for the text pane component. The registered styles can be retrieved at any time. 
 +
 +
 +
 +
 +<code java>
 + doc.setCharacterAttributes(textpane.getSelectionStart(), 
 +     textpane.getSelectionEnd() - textpane.getSelectionStart(),
 +     textpane.getStyle("Bold"), false);
 +</code>
 +
 +
 +
 +
 +Here we change the attributes of the text. The parameters are the offset, length of the selection, the style and the boolean value replace. The offset is the beginning of the text, where we apply the bold text. We get the length value by substracting the selection end and selection start values. Boolean value false means, we are not replacing an old style with a new one, but we merge them. This means, if the text is underlined and we make it bold, the result is an underlined bold text. 
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/documentmodel.png |Document model}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
 +</script>
 +
 +
 +
 +
 +
 +
 +===== السحب و الإفلات فى المكتبة Swing =====
 +
 +
 +
 +
 +فى التطبيقات الرسومية فعل السحب و الإفلات عبارة عن النقر على عنصر مرئى و سحبه لمكان آخر أو داخل عنصر مرئى آخر و عموماً يمكن استخدامه لفعل الكثير من الأشياء أو لإنشاء العديد من طرق الربط بين عناصر معينة (إقتباس من الموسوعة الحرة WikiPedia أنظر المقال الأصلى ).
 +
 +
 +
 +
 +
 +
 +عملية السحب و الإفلات من أكثر الجوانب المهمة فى واجهة المستخدم الرسومية و هى تتيح لك تركيب الأشياء حدسياً. 
 +
 +
 +
 +
 +
 +
 +عادةً, يمكننا سحب و إفلات شيئين. مثل البيانات أو بعض العناصر الرسومية. عند سحب صورة من تطبيق لآخر فإننا نسحب و نفلت بيانات ثنائية binary data . و إذا سحبنا تبويب من برنامج firefox و حركناه إلى مكان آخر فإننا نسحب و نفلت مكونات رسومية. 
 +
 +
 +
 +
 +
 +
 +
 +كمية الفئات classes الموجودة  داخل المكتبة swing للتعامل مع عمليات السحب و الإفلات ربما تكون كتيرة جداً. و أفضل طريقة للتعامل مع هذا التعقيد هى إنشاء مثال لكل الحالات و ببطىء فعل الشىء نفسه مع أمثله أكثر تعقيداً. 
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/dragdrop1.png |}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +لا بد أن يكون للأداة أو المكون الذى سيتم عليه الإفلات عنصر **DragSource** مسجل. العنصر **DropTarget** هو العنصر المسئول عن قبول السحب فى عمليات السحب و الإفلات. **Transferable** يغلف البيانات المتقولة. هناك أنواع مختلقة من البيانات المنقولة, و عن طريق العنصر **DataFlavor** تتم معرفة معلومات عن البيانات المنقولة.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +العديد من مكونات\أداوت مكتبة swing بها دعم مدمج لعمليات السحب و الإفلات. فى بعض الأحيان عندما لا يكون هناك دعم مدمج بالأداة يتسخدم المبرمج **TransferHandler** لكى يتحكم فى عمليات السحب و الإفلات, و لهذا يقوم المبرمج ببناء كل شىء من الصفر.
 +
 +
 +
 +
 +
 +==== مثال بسيط على السحب و الإفلات ====
 +
 +
 +
 +
 +سنشرح مثال بسيط على السحب و الإفلات. و سوف نعمل بالدعم المدمج بعمليات السحب و الإفلات. سوف نستعمل الفئة **TransferHandler**.
 +
 +
 +
 +
 +
 +<code java>
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JTextField;
 +import javax.swing.TransferHandler;
 +
 +
 +public class SimpleDnD extends JFrame {
 +
 +    JTextField field;
 +    JButton button;
 +
 +    public SimpleDnD() {
 +
 +        setTitle("Simple Drag & Drop");
 +
 +        setLayout(null);
 +
 +        button = new JButton("Button");
 +        button.setBounds(200, 50, 90, 25);
 +
 +        field = new JTextField();
 +        field.setBounds(30, 50, 150, 25);
 +
 +        add(button);
 +        add(field);
 +
 +        field.setDragEnabled(true);
 +        button.setTransferHandler(new TransferHandler("text"));
 +
 +        setSize(330, 150);
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    public static void main(String[] args) {
 +        new SimpleDnD();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +فى هذا المثال لدينا حقل نص و زر.يمكننا سحب النص من حقل النص ثم فلته داخل الزر.
 +
 +
 +
 +
 +<code java>
 + field.setDragEnabled(true);
 +</code>
 +
 +
 +
 +
 +حقل النص به دعم سحب و إفلات مدمج. سوف نمكن هذا الدعم.
 +
 +
 +
 +
 +<code java>
 + button.setTransferHandler(new TransferHandler("text"));
 +</code>
 +
 +
 +
 +
 + الفئة **TransferHanlder** هى المسئولة عن نقل البيانات بين المكونين (الزر و حقل النص), و هنا يأخذ المنشىء اسم الخاصية كباراميتر.
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/simplednd.png |Simple drag & drop example}}
 +
 +
 +
 +==== سحب و إفلات أيكونة ====
 +
 +
 +
 +
 +بعض أدوات المكتبة swing ليس بها دعم مدمج للسحب و الإفلات. كمثال هناك الأداة **JLabel**. و لذلك لا بد كتابة كود عملية السحب و الإفلات بأنفسنا.
 +
 +
 +
 +
 +
 +
 +
 +سوف نقوم بعمليات السحب و الإفلات على الأيكونات. فى المثال السابق استخدمنا خاصية النص. أما هنا فسنستخدم خاصية الأيكونة.
 +
 +
 +
 +
 +<code java>
 +import java.awt.FlowLayout;
 +import java.awt.event.MouseAdapter;
 +import java.awt.event.MouseEvent;
 +import java.awt.event.MouseListener;
 +
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JComponent;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +import javax.swing.TransferHandler;
 +
 +
 +public class IconDnD extends JFrame {
 +
 +
 +    public IconDnD() {
 +
 +        setTitle("Icon Drag & Drop");
 +
 +        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 50, 15));
 +
 +        ImageIcon icon1 = new ImageIcon("sad.png");
 +        ImageIcon icon2 = new ImageIcon("plain.png");
 +        ImageIcon icon3 = new ImageIcon("crying.png");
 +
 +        JButton button = new JButton(icon2);
 +        button.setFocusable(false);
 +
 +        JLabel label1  = new JLabel(icon1, JLabel.CENTER);
 +        JLabel label2  = new JLabel(icon3, JLabel.CENTER);
 +
 +        MouseListener listener = new DragMouseAdapter();
 +        label1.addMouseListener(listener);
 +        label2.addMouseListener(listener);
 +
 +        label1.setTransferHandler(new TransferHandler("icon"));
 +        button.setTransferHandler(new TransferHandler("icon"));
 +        label2.setTransferHandler(new TransferHandler("icon"));
 +
 +        panel.add(label1);
 +        panel.add(button);
 +        panel.add(label2);
 +        add(panel);
 +
 +        pack();
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    class DragMouseAdapter extends MouseAdapter {
 +        public void mousePressed(MouseEvent e) {
 +            JComponent c = (JComponent) e.getSource();
 +            TransferHandler handler = c.getTransferHandler();
 +            handler.exportAsDrag(c, e, TransferHandler.COPY);
 +        }
 +    }
 +
 +    public static void main(String[] args) {
 +        new IconDnD();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +فى هذا المثال لدينا أداتى عنوان و زر. كل أداة تعرض أيكونة. أداتى العنوان تمكن إشارة السحب , و الزر يقبل إشارة الإفلات.
 +
 +
 +
 +
 +<code java>
 + MouseListener listener = new DragMouseAdapter();
 + label1.addMouseListener(listener);
 + label2.addMouseListener(listener);
 +</code>
 +
 +
 +
 +
 +افتراضياً, السحب غير مفعل لأداة العنوان.  سوف نجعل لكل أداة عنوان حدث فأرة مخصص.
 +
 +
 +
 +<code java>
 + label1.setTransferHandler(new TransferHandler("icon"));
 + button.setTransferHandler(new TransferHandler("icon"));
 + label2.setTransferHandler(new TransferHandler("icon"));
 +</code>
 +
 +
 +
 +
 +هناك فئة **TransferHandler** لكل من الأداوت الثلاثة لخاصية الأيكونة.
 +لابد من الفئة **TransferHandler** لكل من مصادر السحب و أهدافها.
 +
 +
 +
 +
 +<code java>
 + JComponent c = (JComponent) e.getSource();
 + TransferHandler handler = c.getTransferHandler();
 + handler.exportAsDrag(c, e, TransferHandler.COPY);
 +</code>
 +
 +
 +
 +
 +هذه السطور تبدأ دعم السحب. نحصل على مصدر السحب و فى هذه الحالة هو أداة العنوان.و نحصل أيضاً على عامل النقل (transfer handler)و فى النهاية نبدأ دعم الإفلات باستدعاء الدالة **exportAsDrag()**.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/icondnd.png |Icon drag & drop example}}
 +
 +
 +==== مثال مخصص على الإفلات فى القائمة JList ====
 +
 +
 +
 +
 +بعض الأدوات فى المكتبة swing لا تدعم الإفلات افتراضياً. و حدة من هذه الأداوت هى القائمة. و هناك سبب جيد لهذا و هو عد العلم بأن البيانات سوف تٌدخل فى صف واحد أو اثنين أو ثلاثة, و لذلك لا بد من الدعم اليدوى للإفلات فى هذه الأداة. 
 +
 +
 +
 +
 +
 +
 +
 +النصوص المقسمة عن طريق فاصلة "," سوف يتم إدخالها فى صفين أو أكثر, أما الخالية من الفاصلة فسوف يتم إدخالها فى صف واحد.
 +
 +
 +
 +
 +<code java>
 +import java.awt.Dimension;
 +import java.awt.FlowLayout;
 +import java.awt.datatransfer.DataFlavor;
 +import java.awt.datatransfer.Transferable;
 +
 +import javax.swing.DefaultListModel;
 +import javax.swing.DropMode;
 +import javax.swing.JFrame;
 +import javax.swing.JList;
 +import javax.swing.JPanel;
 +import javax.swing.JScrollPane;
 +import javax.swing.JTextField;
 +import javax.swing.ListSelectionModel;
 +import javax.swing.TransferHandler;
 +
 +
 +public class ListDrop extends JFrame {
 +
 +    JTextField field;
 +    DefaultListModel model;
 +
 +    public ListDrop() {
 +
 +        setTitle("ListDrop");
 +
 +        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 15, 15));
 +
 +        JScrollPane pane = new JScrollPane();
 +        pane.setPreferredSize(new Dimension(180, 150));
 +
 +        model = new DefaultListModel();
 +        JList list = new JList(model);
 +
 +        list.setDropMode(DropMode.INSERT);
 +        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 +        list.setTransferHandler(new ListHandler());
 +
 +        field = new JTextField("");
 +        field.setPreferredSize(new Dimension(150, 25));
 +        field.setDragEnabled(true);
 +
 +        panel.add(field);
 +        pane.getViewport().add(list); 
 +        panel.add(pane);
 +
 +        add(panel);
 +
 +        pack();
 +
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +
 +    private class ListHandler extends TransferHandler {
 +        public boolean canImport(TransferSupport support) {
 +             if (!support.isDrop()) {
 +                 return false;
 +             }
 +
 +             return support.isDataFlavorSupported(DataFlavor.stringFlavor);
 +         }
 +
 +         public boolean importData(TransferSupport support) {
 +             if (!canImport(support)) {
 +               return false;
 +             }
 +
 +             Transferable transferable = support.getTransferable();
 +             String line;
 +             try {
 +               line = (String) transferable.getTransferData(DataFlavor.stringFlavor);
 +             } catch (Exception e) {
 +               return false;
 +             }
 +
 +             JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
 +             int index = dl.getIndex();
 +
 +             String[] data = line.split(",");
 +             for (String item: data) {
 +                 if (!item.isEmpty())
 +                    model.add(index++, item.trim());
 +             }
 +             return true;
 +         }
 +    }
 +
 +    public static void main(String[] args) {
 +        new ListDrop();
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +فى المثال بالأعلى لدينا حقل نص و قائمة, و النص بحقل النص يمكن سحبه و إفلاته داخل القائمة. إذا كان النص مقسم عن طريق فاصلة فسوف يتم إدخاله على هئية صفوف, أما إذا كان لا يحتوى على فواصل فسوف يتم إدخاله على هئية صف واحد داخل القائمة.
 +
 +
 +
 +
 +
 +<code java>
 + list.setDropMode(DropMode.INSERT);
 +</code>
 +
 +
 +
 +
 +هنا نحدد طريقة الإفلات. **DropMode.INSERT** يحدد أننا سوف ندخل عناصر جديدة داخل القائمة. و إذا اخترنا **DropMode.insert** فسوف نفلت عناصر جديدة داخل العناصر الحالية.
 +
 +
 +
 +
 +<code java>
 + list.setTransferHandler(new ListHandler());
 +</code>
 +
 +
 +
 +
 +حددنا فئة عامل النقل المخصص. (custom transfer handler class) 
 +
 +
 +
 +
 +<code java>
 + field.setDragEnabled(true);
 +</code>
 +
 +
 +
 +
 +هنا فعلنا خاصية الإفلات لأداة حقل النص. 
 +
 +
 +
 +
 +<code java>
 + public boolean canImport(TransferSupport support) {
 +     if (!support.isDrop()) {
 +         return false;
 +     }
 +     return support.isDataFlavorSupported(DataFlavor.stringFlavor);
 +  }
 +</code>
 +
 +
 +
 +
 +هذه الدالة تختبر إلى أى مجة عملية الإفلات مناسبة. هنا رشحنا عمليات اللصق من الحافظة, و سمحنا فقط بعمليات إفلات النصوص. إذا كانت قيمة الدالة false فسوف تلغى عملية الإفلات.
 +
 +
 +
 +
 +<code java>
 + public boolean importData(TransferSupport support) {
 + ...
 + }
 +</code>
 +
 +
 +
 +
 +الدالة  **importData()** تنقل البيانات من الحافظة أو من مكان عملية السحب و الإفلات إلى مكان الإفلات.
 +
 +
 +
 +
 +<code java>
 + Transferable transferable = support.getTransferable();
 +</code>
 +
 +
 +
 +
 + الفئة **Transferable** هى مجمع البيانات.
 +
 +
 +
 +
 +<code java>
 + line = (String) transferable.getTransferData(DataFlavor.stringFlavor);
 +</code>
 +
 +
 +
 +
 +استلمنا البيانات. 
 +
 +
 +
 +
 +<code java>
 + JList.DropLocation dl = (JList.DropLocation) support.getDropLocation();
 + int index = dl.getIndex();
 +</code>
 +
 +
 +
 +
 +حصلنا على مكان الإفلات للقائمة. استرجعنا الدليل(index) حيث سيتم إدخال البيانات.
 +
 +
 +
 +
 +<code java>
 + String[] data = line.split(",");
 + for (String item: data) {
 +     if (!item.isEmpty())
 +         model.add(index++, item.trim());
 + }
 +</code>
 +
 +
 +
 +
 +قسمنا النص إلى أجزاء و أدخلناه على هيئة صف أو أكثر.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/listdrop.png |JList drop example}}
 +
 +
 +
 +
 +
 +
 +فى  المثال السابق استخدمنا أدوات بها دعم مدمج للسحب و الإفلات. فى المرة القادمة سوف سوف يتحتم علينا إنشاء خاصية السحب و الإفلات من الصفر.
 +
 +
 +
 +
 +
 +
 +==== إشارة السحب ====
 +
 +
 +
 +
 +فى المثال القادم سوف نشرح مثال بسيط على. سوف نعمل على العديد من الفئات الازمة لإنشاء إشاvة السحب مثل  **DragSource** و  **DragGestureEvent** **DragGestureListener** و  **Transferable**.
 +
 +
 +
 +
 +<code java>
 +import java.awt.Color;
 +import java.awt.Cursor;
 +import java.awt.Dimension;
 +import java.awt.FlowLayout;
 +import java.awt.datatransfer.DataFlavor;
 +import java.awt.datatransfer.Transferable;
 +import java.awt.dnd.DnDConstants;
 +import java.awt.dnd.DragGestureEvent;
 +import java.awt.dnd.DragGestureListener;
 +import java.awt.dnd.DragSource;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class DragGesture extends JFrame implements 
 +    DragGestureListener, Transferable {
 +
 +    public DragGesture() {
 +
 +        setTitle("Drag Gesture");
 +
 +        JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 50, 15));
 +
 +        JPanel left = new JPanel();
 +        left.setBackground(Color.red);
 +        left.setPreferredSize(new Dimension(120, 120));
 +
 +        DragSource ds = new DragSource();
 +        ds.createDefaultDragGestureRecognizer(left,
 +            DnDConstants.ACTION_COPY, this);
 +
 +        panel.add(left);
 +        add(panel);
 +
 +        pack();
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    public void dragGestureRecognized(DragGestureEvent event) {
 +        System.out.println("grag gesture");
 +        Cursor cursor = null;
 +        if (event.getDragAction() == DnDConstants.ACTION_COPY) {
 +            cursor = DragSource.DefaultCopyDrop;
 +        }
 +        event.startDrag(cursor, this);
 +    }
 +
 +    public static void main(String[] args) {
 +        new DragGesture();
 +    }
 +
 +    public Object getTransferData(DataFlavor flavor) {
 +        return null;
 +    }
 +
 +    public DataFlavor[] getTransferDataFlavors() {
 +        return new DataFlavor[0];
 +    }
 +
 +    public boolean isDataFlavorSupported(DataFlavor flavor) {
 +        return false;
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +هذا المثال البسيط يشرح اشارة السحب. يتم إنشاء الإشارة عندما ننقر على أداة أو نحرك مؤشر الفأرة, بينما نحن نضغط على الزر. و هذا المثال سوف يعرض كيفية إنشاء DragSource لأداة.
 +
 +
 +
 +
 +<code java>
 + public class DragGesture extends JFrame implements 
 +    DragGestureListener, Transferable {
 +</code>
 +
 +
 +
 +
 + DragGesture سوف تمثل واجهتى تعامل.أحدهما **DragGestureListener** و سوف يترصد لإشارات السحب. و الآخر **Transferable** و سوف يتعامل مع البيانات لأجل عملية النقل. و فى هذا المثال لن ننقل أية بيانات بل سننشىء فقط إشارة سحب. لذلك توجد ثلاثة دوال للواجهه Transferable لم يتم تنفيذهم.
 +
 +
 +
 +
 +<code java>
 + DragSource ds = new DragSource();
 + ds.createDefaultDragGestureRecognizer(left,
 +     DnDConstants.ACTION_COPY, this);
 +</code>
 +
 +
 +
 +
 +هنا أنشأنا عنصر  **DragSource** و سجلناه للوحة اليسرى. 
 + DragSource هو المسئول ن بدأ عملية السحب و الإفلات. 
 +createDefaultDragGestureRecognizer**** يضم **DragGestureListener** و مصدر السحب بأداة/مكون معين.
 +
 +
 +
 +
 +
 +<code java>
 + public void dragGestureRecognized(DragGestureEvent event) {
 +
 + }
 +</code>
 +
 +
 +
 +الدالة **dragGestureRecognized()** تستجيب لإشارة السحب. 
 +
 +
 +
 +
 +<code java>
 + Cursor cursor = null;
 + if (event.getDragAction() == DnDConstants.ACTION_COPY) {
 +     cursor = DragSource.DefaultCopyDrop;
 + }
 + event.startDrag(cursor, this);
 +</code>
 +
 +
 +
 +
 +بدأ الدالة **startDrag** عملية السحب و سوف نحدد باراميترين (عاملين) نوع المؤشر و العنصر Transferable.
 +
 +
 +
 +
 +<code java>
 + public Object getTransferData(DataFlavor flavor) {
 +     return null;
 + }
 +
 + public DataFlavor[] getTransferDataFlavors() {
 +    return new DataFlavor[0];
 + }
 +
 + public boolean isDataFlavorSupported(DataFlavor flavor) {
 +     return false;
 + }
 +</code>
 +
 +
 +
 +
 +العنصر المنفذ للواجهه Transferable لا بد و أن ينفذ الثلاثة دوال. و كما ذكرت آنفاً, لقد تركنا هذه الدوال و لم ننفذها حتى الآن.
 +
 +
 +
 +
 +
 +==== مثال أكثر تعقيداً على السحب و الإفلات  ====
 +
 +
 +
 +
 +فى المثال القادم سوف ننشىء مثال أكثر تعقيداً على السحب و الإفلات. سوف ننشأ مصدر سحب (drag source) و هدف إفلات (drop target) و عنصر transferable.
 +
 +
 +
 +<code java>
 +import java.awt.Color;
 +import java.awt.Cursor;
 +import java.awt.Dimension;
 +import java.awt.FlowLayout;
 +import java.awt.datatransfer.DataFlavor;
 +import java.awt.datatransfer.Transferable;
 +import java.awt.datatransfer.UnsupportedFlavorException;
 +import java.awt.dnd.DnDConstants;
 +import java.awt.dnd.DragGestureEvent;
 +import java.awt.dnd.DragGestureListener;
 +import java.awt.dnd.DragSource;
 +import java.awt.dnd.DropTarget;
 +import java.awt.dnd.DropTargetAdapter;
 +import java.awt.dnd.DropTargetDropEvent;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +
 +import javax.swing.JButton;
 +import javax.swing.JColorChooser;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class ComplexExample extends JFrame 
 +    implements DragGestureListener {
 +
 +    JPanel panel;
 +    JPanel left;
 +
 +    public ComplexExample() {
 +
 +        setTitle("Complex Example");
 +
 +        panel  = new JPanel(new FlowLayout(FlowLayout.LEFT, 50, 15));
 +
 +        JButton openb = new JButton("Choose Color");
 +        openb.setFocusable(false);
 +
 +        left = new JPanel();
 +        left.setBackground(Color.red);
 +        left.setPreferredSize(new Dimension(100, 100));
 +
 +        openb.addActionListener(new ActionListener() {
 +            public void actionPerformed(ActionEvent event) {
 +                JColorChooser clr = new JColorChooser();
 +                Color color = clr.showDialog(panel, "Choose Color", Color.white);
 +                left.setBackground(color);
 +            }
 +        });
 +
 +        JPanel right = new JPanel();
 +        right.setBackground(Color.white);
 +        right.setPreferredSize(new Dimension(100, 100));
 +
 +        new MyDropTargetListener(right);
 +
 +        DragSource ds = new DragSource();
 +        ds.createDefaultDragGestureRecognizer(left,
 +            DnDConstants.ACTION_COPY, this);
 +
 +        panel.add(openb);
 +        panel.add(left);
 +        panel.add(right);
 +        add(panel);
 +
 +        pack();
 +        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        setLocationRelativeTo(null);
 +        setVisible(true);
 +    }
 +
 +    public void dragGestureRecognized(DragGestureEvent event) {
 +        Cursor cursor = null;
 +        JPanel panel = (JPanel) event.getComponent();
 +
 +        Color color = panel.getBackground();
 +
 +        if (event.getDragAction() == DnDConstants.ACTION_COPY) {
 +            cursor = DragSource.DefaultCopyDrop;
 +        }
 +
 +        event.startDrag(cursor, new TransferableColor(color));
 +    }
 +
 +    class MyDropTargetListener extends DropTargetAdapter {
 +
 +        private DropTarget dropTarget;
 +        private JPanel panel;
 +
 +     public MyDropTargetListener(JPanel panel) {
 +        this.panel = panel;
 +
 +        dropTarget = new DropTarget(panel, DnDConstants.ACTION_COPY, 
 +            this, true, null);
 +      }
 +
 +
 +      public void drop(DropTargetDropEvent event) {
 +        try {
 +
 +          Transferable tr = event.getTransferable();
 +          Color color = (Color) tr.getTransferData(TransferableColor.colorFlavor);
 +
 +            if (event.isDataFlavorSupported(TransferableColor.colorFlavor)) {
 +
 +              event.acceptDrop(DnDConstants.ACTION_COPY);
 +              this.panel.setBackground(color);
 +              event.dropComplete(true);
 +              return;
 +            }
 +          event.rejectDrop();
 +        } catch (Exception e) {
 +          e.printStackTrace();
 +          event.rejectDrop();
 +        }
 +      }
 +    }
 +
 +    public static void main(String[] args) {
 +        new ComplexExample();
 +    }
 +}
 +
 +
 +class TransferableColor implements Transferable {
 + 
 +    protected static DataFlavor colorFlavor =
 +        new DataFlavor(Color.class, "A Color Object");
 +
 +    protected static DataFlavor[] supportedFlavors = {
 +        colorFlavor,
 +        DataFlavor.stringFlavor,
 +    };
 +
 +    Color color;
 +
 +    public TransferableColor(Color color) { this.color = color; }
 +
 +    public DataFlavor[] getTransferDataFlavors() { return supportedFlavors; }
 +
 +    public boolean isDataFlavorSupported(DataFlavor flavor) {
 +    if (flavor.equals(colorFlavor) || 
 +        flavor.equals(DataFlavor.stringFlavor)) return true;
 +    return false;
 +  }
 +
 +
 +   public Object getTransferData(DataFlavor flavor) 
 +        throws UnsupportedFlavorException
 +   {
 +     if (flavor.equals(colorFlavor))
 +         return color;
 +     else if (flavor.equals(DataFlavor.stringFlavor)) 
 +         return color.toString();
 +     else 
 +         throw new UnsupportedFlavorException(flavor);
 +   }
 +}
 +</code>
 +
 +
 +
 +
 +يعرض المثال زر و لوحتين. الزر يعرض مربع حوارى لإختيار الألون و منه نختار اللورن للورحة الأولى و من ثم يمكن سحب و إفلات اللون فى اللوحة الثانية.
 +
 +
 +
 +
 +
 +
 +
 +يحسن هذا المثال المثال السابق, فسوف نضيف هدف إفلات و عنصر transferable مخصص.
 +
 +
 +
 +
 +<code java>
 + new MyDropTargetListener(right);
 +</code>
 +
 +
 +
 +
 +هنا ربطنا مُترصد هدف الإفلات باللوحة اليمنى. 
 +
 +
 +
 +
 +<code java>
 +  event.startDrag(cursor, new TransferableColor(color));
 +</code>
 +
 +
 +
 +
 +الدالة  **startDrag()** لها باراميترين الأول مؤشر و الثانى  عنصر **Transferable**.  
 +
 +
 +
 +
 +<code java>
 + public MyDropTargetListener(JPanel panel) {
 +     this.panel = panel;
 +
 +     dropTarget = new DropTarget(panel, DnDConstants.ACTION_COPY, 
 +         this, true, null);
 + }
 +</code>
 +
 +
 +
 +
 +داخل MyDropTargetListener أنشأنا عنصر هدف إفلات (drop target).  
 +
 +
 +
 +
 +<code java>
 + Transferable tr = event.getTransferable();
 + Color color = (Color) tr.getTransferData(TransferableColor.colorFlavor);
 +
 + if (event.isDataFlavorSupported(TransferableColor.colorFlavor)) {
 +
 +     event.acceptDrop(DnDConstants.ACTION_COPY);
 +     this.panel.setBackground(color);
 +     event.dropComplete(true);
 +     return;
 +  }
 +</code>
 +
 +
 +
 +
 +حصلنا على البيانات التى ستنقل. و فى حالتنا هذه هو عنصر ألوان, و ها نحن نغير لون اللوحة الثانية.
 +
 +
 +
 +
 +<code java>
 + event.rejectDrop();
 +</code>
 +
 +
 +
 +
 +إذا كانت شروط عملية السحب و الإفلات غير كاملة, تلغى العملية.
 +
 +
 +
 +
 +<code java>
 + protected static DataFlavor colorFlavor =
 +     new DataFlavor(Color.class, "A Color Object");
 +</code>
 +
 +
 +
 +
 +بداخل **TransferableColor** أنشأنا عنصر **DataFlavor**.
 +
 +
 +
 +
 +<code java>
 + protected static DataFlavor[] supportedFlavors = {
 +     colorFlavor,
 +     DataFlavor.stringFlavor,
 + };
 +</code>
 +
 +
 +
 +
 +هنا حددنا أى نكهة/صفة بيانات صوف نستخدم. و فى حالتنا هذه سوف نستخدم لون معرف و مخصص و DataFlavor.stringFlavor****  محدد مسبقاً. 
 +
 +
 +
 +
 +
 +<code java>
 + public Object getTransferData(DataFlavor flavor) 
 +      throws UnsupportedFlavorException
 + {
 +   if (flavor.equals(colorFlavor))
 +       return color;
 +   else if (flavor.equals(DataFlavor.stringFlavor)) 
 +       return color.toString();
 +   else 
 +       throw new UnsupportedFlavorException(flavor);
 + }
 +</code>
 +
 +
 +
 +
 +يسترجع عنصر للبيانات المحددة.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/complexexample.png |A complex example}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
 +</script>
 +
 +
 +
 +
 +
 +===== الرسم فى المكتبة swing =====
 +
 +
 +
 +
 +
 +يستخدم الرسم عندما نريد أن نغير أو نحسن فى أداة موجودة بالفعل , أو عندما ننشىء أداة مخصصة من الصفر أيضاً. و لنبدأ فى الرسم سوف نستخدم API المتاحة بمكتبة .Swing
 +
 +
 +
 +
 +
 +
 +
 +يتم الرسم بالدلة **paintComponent()** . و فى عملية الرسم نستخدم العنصر **Graphics2D**.
 +
 +
 +
 +
 +
 +==== الرسومات المتجهة ثنائية الأبعاد ====
 +
 +
 +
 +
 +هنك نواعان مختلفان للرسومات على الحاسب, الرسم المتجهى و الرسم الخطى. و الرسم الخطى يمثل الصورة كمجموعة من البكسل. أما الرسم المتجهى فهو استخدام الأشكال الهندسية الأولية مصل النقاط و الخطوط و المنحنيات و المضلعات لتمثيل الصورة. و هذه الأشكال الألوية يتم إنشائها باستخدان المعادلات الرياضية.
 +
 +
 +
 +
 +
 +
 +
 +هذان النوعان لها مميزاتهما و عيوبهما و من مميزات الرسم المتجهى على الرسم الخطى:
 +
 +
 +
 +
 +
 +   * حجم أصغر
 +   * القدرة على التكبير الغير محدود
 +   * التحريك و التحجيم و القلب كل هذا لا يوثر على جودة الصورة.
 +
 +
 +=== أنواع الأشكال الأولية ===
 +
 +
 +  * النقاط
 +  * الخطوط
 +  * الخطوط المتعددة
 +  * المضلعات
 +  * الدوائر
 +  * القطاعات الناقصة
 +  * خطوط منحنيات
 +
 +
 +
 +==== Points ====
 +
 +
 +
 +
 +The most simple graphics primitive is point. It is a single dot on the window. Interesingly, there is no method
 +to draw a point in Swing. (Or I could not find it.) To draw a point, I used a **drawLine()**
 +method. I used one point twice. 
 +
 +
 +
 +
 +<code java>
 +import java.awt.Color;
 +import java.awt.Dimension;
 +import java.awt.Graphics;
 +import java.awt.Graphics2D;
 +import java.awt.Insets;
 +
 +import javax.swing.JPanel;
 +import javax.swing.JFrame;
 +
 +import java.util.Random;
 +
 +
 +
 +public class Points extends JPanel {
 +
 +    public void paintComponent(Graphics g) {
 +            super.paintComponent(g); 
 +
 +            Graphics2D g2d = (Graphics2D) g;
 +
 +            g2d.setColor(Color.blue);
 +
 +            for (int i=0; i<=1000; i++) {
 +                Dimension size = getSize();
 +                Insets insets = getInsets();
 +
 +                int w =  size.width - insets.left - insets.right;
 +                int h =  size.height - insets.top - insets.bottom;
 +
 +                Random r = new Random();
 +                int x = Math.abs(r.nextInt()) % w;
 +                int y = Math.abs(r.nextInt()) % h;
 +                g2d.drawLine(x, y, x, y);
 +            }
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        Points points = new Points();
 +        JFrame frame = new JFrame("Points");
 +        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        frame.add(points);
 +        frame.setSize(250, 200);
 +        frame.setLocationRelativeTo(null);
 +        frame.setVisible(true);
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +One point is difficult to observe. Why not paint 1000 of them. In our example, we do so. We draw 1000 blue points on the 
 +panel. 
 +
 +
 +
 +
 +<code java>
 + g2d.setColor(Color.blue);
 +</code>
 +
 +
 +
 +
 +We will paint our points in blue color.
 +
 +
 +
 +
 +
 +<code java>
 + Dimension size = getSize();
 + Insets insets = getInsets();
 +</code>
 +
 +
 +
 +
 +The size of the window includes borders and titlebar. We don't paint there.
 +
 +
 +
 +
 +
 +<code java>
 + int w =  size.width - insets.left - insets.right;
 + int h =  size.height - insets.top - insets.bottom;
 +</code>
 +
 +
 +
 +
 +Here we calculate the area, where we will effectively paint our points. 
 +
 +
 +
 +
 +<code java>
 + Random r = new Random();
 + int x = Math.abs(r.nextInt()) % w;
 + int y = Math.abs(r.nextInt()) % h;
 +</code>
 +
 +
 +
 +
 +We get a random number in range of the size of area, that we computed above.
 +
 +
 +
 +
 +
 +<code java>
 + g2d.drawLine(x, y, x, y);
 +</code>
 +
 +
 +
 +
 +Here we draw the point. As I already said, we use a **drawLine()** method. We specify the same point 
 +twice.
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/points.jpg |Points}}
 +
 +
 +
 +==== Lines ====
 +
 +
 +
 +
 +A line is a simple graphics primitive. It is drawn using two points. 
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BasicStroke;
 +import java.awt.Graphics;
 +import java.awt.Graphics2D;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class Lines extends JPanel {
 +
 +    public void paintComponent(Graphics g) {
 +            super.paintComponent(g); 
 +
 +            Graphics2D g2d = (Graphics2D) g;
 +
 +            float[] dash1 = { 2f, 0f, 2f };
 +            float[] dash2 = { 1f, 1f, 1f };
 +            float[] dash3 = { 4f, 0f, 2f };
 +            float[] dash4 = { 4f, 4f, 1f };
 +
 +            g2d.drawLine(20, 40, 250, 40);
 +
 +            BasicStroke bs1 = new BasicStroke(1, BasicStroke.CAP_BUTT, 
 +                BasicStroke.JOIN_ROUND, 1.0f, dash1, 2f );
 +
 +            BasicStroke bs2 = new BasicStroke(1, BasicStroke.CAP_BUTT, 
 +                BasicStroke.JOIN_ROUND, 1.0f, dash2, 2f );
 +
 +            BasicStroke bs3 = new BasicStroke(1, BasicStroke.CAP_BUTT, 
 +                BasicStroke.JOIN_ROUND, 1.0f, dash3, 2f );
 +
 +            BasicStroke bs4 = new BasicStroke(1, BasicStroke.CAP_BUTT, 
 +                BasicStroke.JOIN_ROUND, 1.0f, dash4, 2f );
 +
 +            g2d.setStroke(bs1);
 +            g2d.drawLine(20, 80, 250, 80);
 +
 +            g2d.setStroke(bs2);
 +            g2d.drawLine(20, 120, 250, 120);
 +
 +            g2d.setStroke(bs3);
 +            g2d.drawLine(20, 160, 250, 160);
 +
 +            g2d.setStroke(bs4);
 +            g2d.drawLine(20, 200, 250, 200);
 +
 +    }
 +
 +
 +    public static void main(String[] args) {
 +
 +        Lines lines = new Lines();
 +        JFrame frame = new JFrame("Lines");
 +        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        frame.add(lines);
 +        frame.setSize(280, 270);
 +        frame.setLocationRelativeTo(null);
 +        frame.setVisible(true);
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +In the example, we draw five lines. The first line is drawn using the default values. Other will have a different **stroke**. The stroke is created using
 +the **BasicStroke** class. It defines a basic set of rendering attributes for the outlines of graphics primitives. 
 +
 +
 +
 +
 +
 +<code java>
 + float[] dash1 = { 2f, 0f, 2f };
 +</code>
 +
 +
 +
 +
 +Here we create a dash, that we use in the stroke object.
 +
 +
 +
 +
 +<code java>
 + BasicStroke bs1 = new BasicStroke(1, BasicStroke.CAP_BUTT, 
 +     BasicStroke.JOIN_ROUND, 1.0f, dash1, 2f )
 +</code>
 +
 +
 +
 +
 +This code creates a stroke. The stroke defines the line width, end caps, line joins, miter limit, dash and the dash phase.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/lines.jpg |Lines}}
 +
 +
 +
 +==== Rectangles ====
 +
 +
 +
 +
 +To draw rectangles, we use the **drawRect()** method. To fill rectangles with the current color, we
 +use the **fillRect()** method.
 +
 +
 +
 +
 +<code java>
 +import java.awt.Color;
 +import java.awt.Graphics;
 +import java.awt.Graphics2D;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class Rectangles extends JPanel {
 +
 +    public void paintComponent(Graphics g) {
 +            super.paintComponent(g); 
 +
 +            Graphics2D g2d = (Graphics2D) g;
 +
 +            g2d.setColor(new Color(212, 212, 212));
 +            g2d.drawRect(10, 15, 90, 60);
 +            g2d.drawRect(130, 15, 90, 60);
 +            g2d.drawRect(250, 15, 90, 60);
 +            g2d.drawRect(10, 105, 90, 60);
 +            g2d.drawRect(130, 105, 90, 60);
 +            g2d.drawRect(250, 105, 90, 60);
 +            g2d.drawRect(10, 195, 90, 60);
 +            g2d.drawRect(130, 195, 90, 60);
 +            g2d.drawRect(250, 195, 90, 60);
 +
 +            g2d.setColor(new Color(125, 167, 116));
 +            g2d.fillRect(10, 15, 90, 60);
 +
 +            g2d.setColor(new Color(42, 179, 231));
 +            g2d.fillRect(130, 15, 90, 60);
 +
 +            g2d.setColor(new Color(70, 67, 123));
 +            g2d.fillRect(250, 15, 90, 60);
 +
 +            g2d.setColor(new Color(130, 100, 84));
 +            g2d.fillRect(10, 105, 90, 60);
 +
 +            g2d.setColor(new Color(252, 211, 61));
 +            g2d.fillRect(130, 105, 90, 60);
 +
 +            g2d.setColor(new Color(241, 98, 69));
 +            g2d.fillRect(250, 105, 90, 60);
 +
 +            g2d.setColor(new Color(217, 146, 54));
 +            g2d.fillRect(10, 195, 90, 60);
 +
 +            g2d.setColor(new Color(63, 121, 186));
 +            g2d.fillRect(130, 195, 90, 60);
 +
 +            g2d.setColor(new Color(31, 21, 1));
 +            g2d.fillRect(250, 195, 90, 60);
 +
 +
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        Rectangles rects = new Rectangles();
 +        JFrame frame = new JFrame("Rectangles");
 +        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        frame.add(rects);
 +        frame.setSize(360, 300);
 +        frame.setLocationRelativeTo(null);
 +        frame.setVisible(true);
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +In the example we draw nine colored rectangles. 
 +
 +
 +
 +
 +<code java>
 + g2d.setColor(new Color(212, 212, 212));
 + g2d.drawRect(10, 15, 90, 60);
 + ...
 +</code>
 +
 +
 +
 +
 +We set the color of the outline of the rectangle to a soft gray color, so that it does not interfere with 
 +the fill color. To draw the outline of the rectangle, we use the **drawRect()** method.
 +The first two parameters are the x and y values. The third and fourth are width and height. 
 +
 +
 +
 +
 +<code java>
 + g2d.fillRect(10, 15, 90, 60);
 +</code>
 +
 +
 +
 +
 +To fill the rectangle with a color, we use the **fillRect()** method.
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/rectangles.jpg |Rectangles}}
 +
 +
 +
 +==== Textures ====
 +
 +
 +
 +
 +A **texture** is a bitmap image applied to the surface in computer graphics. Besides colors and gradients, we can fill 
 +our graphics shapes with textures.
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.Color;
 +import java.awt.Graphics;
 +import java.awt.Graphics2D;
 +import java.awt.Rectangle;
 +import java.awt.TexturePaint;
 +import java.awt.image.BufferedImage;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +import java.io.IOException;
 +import java.net.URL;
 +import javax.imageio.ImageIO;
 +
 +
 +public class Textures extends JPanel {
 +
 +
 +    public void paintComponent(Graphics g) {
 +            super.paintComponent(g); 
 +
 +            Graphics2D g2d = (Graphics2D) g;
 +
 +            g2d.setColor(new Color(212, 212, 212));
 +            g2d.drawRect(10, 15, 90, 60);
 +            g2d.drawRect(130, 15, 90, 60);
 +            g2d.drawRect(250, 15, 90, 60);
 +            g2d.drawRect(10, 105, 90, 60);
 +            g2d.drawRect(130, 105, 90, 60);
 +            g2d.drawRect(250, 105, 90, 60);
 +
 +            BufferedImage bimage1 = null;
 +            BufferedImage bimage2 = null;
 +            BufferedImage bimage3 = null;
 +            BufferedImage bimage4 = null;
 +            BufferedImage bimage5 = null;
 +            BufferedImage bimage6 = null;
 +
 +            URL url1 = ClassLoader.getSystemResource("texture1.png");
 +            URL url2 = ClassLoader.getSystemResource("texture2.png");
 +            URL url3 = ClassLoader.getSystemResource("texture3.png");
 +            URL url4 = ClassLoader.getSystemResource("texture4.png");
 +            URL url5 = ClassLoader.getSystemResource("texture5.png");
 +            URL url6 = ClassLoader.getSystemResource("texture6.png");
 +
 +            try {
 +                bimage1 = ImageIO.read(url1);
 +                bimage2 = ImageIO.read(url2);
 +                bimage3 = ImageIO.read(url3);
 +                bimage4 = ImageIO.read(url4);
 +                bimage5 = ImageIO.read(url5);
 +                bimage6 = ImageIO.read(url6);
 +            } catch (IOException ioe) {
 +                ioe.printStackTrace();
 +            }
 +
 +            Rectangle rect1 = new Rectangle(0, 0,
 +                bimage1.getWidth(), bimage1.getHeight());
 +
 +            Rectangle rect2 = new Rectangle(0, 0,
 +                bimage2.getWidth(), bimage2.getHeight());
 +
 +            Rectangle rect3 = new Rectangle(0, 0,
 +                bimage3.getWidth(), bimage3.getHeight());
 +
 +            Rectangle rect4 = new Rectangle(0, 0,
 +                bimage4.getWidth(), bimage4.getHeight());
 +
 +            Rectangle rect5 = new Rectangle(0, 0,
 +                bimage5.getWidth(), bimage5.getHeight());
 +
 +            Rectangle rect6 = new Rectangle(0, 0,
 +                bimage6.getWidth(), bimage6.getHeight());
 +
 +            TexturePaint texture1 = new TexturePaint(bimage1, rect1);
 +            TexturePaint texture2 = new TexturePaint(bimage2, rect2);
 +            TexturePaint texture3 = new TexturePaint(bimage3, rect3);
 +            TexturePaint texture4 = new TexturePaint(bimage4, rect4);
 +            TexturePaint texture5 = new TexturePaint(bimage5, rect5);
 +            TexturePaint texture6 = new TexturePaint(bimage6, rect6);
 +
 +            g2d.setPaint(texture1);
 +            g2d.fillRect(10, 15, 90, 60);
 +
 +            g2d.setPaint(texture2);
 +            g2d.fillRect(130, 15, 90, 60);
 +
 +            g2d.setPaint(texture3);
 +            g2d.fillRect(250, 15, 90, 60);
 +
 +            g2d.setPaint(texture4);
 +            g2d.fillRect(10, 105, 90, 60);
 +
 +            g2d.setPaint(texture5);
 +            g2d.fillRect(130, 105, 90, 60);
 +
 +            g2d.setPaint(texture6);
 +            g2d.fillRect(250, 105, 90, 60);
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        Textures rects = new Textures();
 +        JFrame frame = new JFrame("Textures");
 +        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        frame.add(rects);
 +        frame.setSize(360, 210);
 +        frame.setLocationRelativeTo(null);
 +        frame.setVisible(true);
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +In our example, we will draw six rectangles filled with different textures. 
 +To work with textures, Java Swing has a **TexturePaint** class.
 +
 +
 +
 +
 +<code java>
 + BufferedImage bimage1 = null;
 + ...
 + URL url1 = ClassLoader.getSystemResource("texture1.png");
 + ...
 + bimage1 = ImageIO.read(url1);
 +</code>
 +
 +
 +
 +
 +We read an image into the memory.
 +
 +
 +
 +
 +<code java>
 + Rectangle rect1 = new Rectangle(0, 0,
 +     bimage1.getWidth(), bimage1.getHeight());
 +</code>
 +
 +
 +
 +
 +We get the size of the texture image.
 +
 +
 +
 +
 +<code java>
 + TexturePaint texture1 = new TexturePaint(bimage1, rect1);
 +</code>
 +
 +
 +
 +
 +Here we create a **TexturePaint** object. The parameters are a buffered image and a rectangle of the image. The rectangle is used to anchor and replicate the image. The images are tiled. 
 +
 +
 +
 +
 +<code java>
 + g2d.setPaint(texture1);
 + g2d.fillRect(10, 15, 90, 60);
 +</code>
 +
 +
 +
 +
 +Here we apply the texture and fill the rectangle with it.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/textures.jpg |Textures}}
 +
 +
 +
 +==== Gradients ====
 +
 +
 +
 +
 +In computer graphics, gradient is a smooth blending of shades from light to dark or from one color to another. In 2D drawing programs and paint programs, gradients are used to create colorful backgrounds and special effects as well as to simulate lights and shadows. (answers.com)
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BasicStroke;
 +import java.awt.Color;
 +import java.awt.GradientPaint;
 +import java.awt.Graphics;
 +import java.awt.Graphics2D;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class Gradients extends JPanel {
 +
 +
 +    public void paintComponent(Graphics g) {
 +            super.paintComponent(g); 
 +
 +            Graphics2D g2d = (Graphics2D) g;
 +
 +            GradientPaint gp1 = new GradientPaint(5, 5, 
 +                Color.red, 20, 20, Color.black, true);
 +
 +            g2d.setPaint(gp1);
 +            g2d.fillRect(20, 20, 300, 40);
 +
 +            GradientPaint gp2 = new GradientPaint(5, 25, 
 +            Color.yellow, 20, 2, Color.black, true);
 +
 +            g2d.setPaint(gp2);
 +            g2d.fillRect(20, 80, 300, 40);
 +
 +            GradientPaint gp3 = new GradientPaint(5, 25, 
 +             Color.green, 2, 2, Color.black, true);
 +
 +            g2d.setPaint(gp3);
 +            g2d.fillRect(20, 140, 300, 40);
 +
 +            GradientPaint gp4 = new GradientPaint(25, 25, 
 +            Color.blue, 15, 25, Color.black, true);
 +
 +            g2d.setPaint(gp4);
 +            g2d.fillRect(20, 200, 300, 40);
 +
 +            GradientPaint gp5 = new GradientPaint(0, 0, 
 +             Color.orange, 0, 20, Color.black, true);
 +
 +            g2d.setPaint(gp5);
 +            g2d.fillRect(20, 260, 300, 40);
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        Gradients gradients = new Gradients();
 +        JFrame frame = new JFrame("Gradients");
 +        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        frame.add(gradients);
 +        frame.setSize(350, 350);
 +        frame.setLocationRelativeTo(null);
 +        frame.setVisible(true);
 +
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +Our code example presents five rectangles with gradients. 
 +
 +
 +
 +
 +<code java>
 + GradientPaint gp4 = new GradientPaint(25, 25, 
 +     Color.blue, 15, 25, Color.black, true);
 +</code>
 +
 +
 +
 +
 +To work with gradients, we use Java Swing's **GradientPaint**  class.By manipulating the 
 +color values and the starting end ending points, we can get interesting results.
 +
 +
 +
 +
 +<code java>
 + g2d.setPaint(gp5);
 +</code>
 +
 +
 +
 +
 +The gradient is activated calling the **setPaint()** method.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/gradients.jpg |Gradients}}
 +
 +
 +==== Drawing text ====
 +
 +
 +
 +
 +Drawing is done with the **drawString()** method. We specify the string we want
 +to draw and the position of the text on the window area.
 +
 +
 +
 +
 +<code java>
 +import java.awt.Font;
 +import java.awt.Graphics;
 +import java.awt.Graphics2D;
 +import java.awt.RenderingHints;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class Text extends JPanel {
 +
 +    public void paintComponent(Graphics g) {
 +        super.paintComponent(g); 
 +
 +        Graphics2D g2d = (Graphics2D) g;
 +
 +
 +        RenderingHints rh = new RenderingHints(
 +            RenderingHints.KEY_ANTIALIASING,
 +            RenderingHints.VALUE_ANTIALIAS_ON);
 +
 +        rh.put(RenderingHints.KEY_RENDERING, 
 +            RenderingHints.VALUE_RENDER_QUALITY);
 +
 +        g2d.setRenderingHints(rh);
 +
 +        Font font = new Font("URW Chancery L", Font.BOLD, 21);
 +        g2d.setFont(font);
 +
 +        g2d.drawString("Not marble, nor the gilded monuments", 20, 30);
 +        g2d.drawString("Of princes, shall outlive this powerful rhyme;"
 +            ,20, 60);
 +        g2d.drawString("But you shall shine more bright in these contents",
 +            20, 90);
 +        g2d.drawString("Than unswept stone, besmear'd with sluttish time.", 
 +            20, 120);
 +        g2d.drawString("When wasteful war shall statues overturn,", 20, 150);
 +        g2d.drawString("And broils root out the work of masonry,", 20, 180);
 +        g2d.drawString("Nor Mars his sword, nor war's quick " +
 +            "fire shall burn", 20, 210);
 +        g2d.drawString("The living record of your memory.", 20, 240);
 +        g2d.drawString("'Gainst death, and all oblivious enmity", 20, 270);
 +        g2d.drawString("Shall you pace forth; your praise shall still " +
 +            "find room", 20, 300);
 +        g2d.drawString("Even in the eyes of all posterity", 20, 330);
 +        g2d.drawString("That wear this world out to the ending doom.", 20, 360);
 +        g2d.drawString("So, till the judgment that yourself arise,", 20, 390);
 +        g2d.drawString("You live in this, and dwell in lovers' eyes.", 20, 420);
 +
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        Text text = new Text();
 +        JFrame frame = new JFrame("Sonnet 55");
 +        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        frame.add(text);
 +        frame.setSize(500, 470);
 +        frame.setLocationRelativeTo(null);
 +        frame.setVisible(true);
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +In our example, we draw a sonnet on the panel component. 
 +
 +
 +
 +
 +<code java>
 + RenderingHints rh = new RenderingHints(
 +     RenderingHints.KEY_ANTIALIASING,
 +     RenderingHints.VALUE_ANTIALIAS_ON);
 +
 + rh.put(RenderingHints.KEY_RENDERING, 
 +     RenderingHints.VALUE_RENDER_QUALITY);
 +
 + g2d.setRenderingHints(rh);
 +</code>
 +
 +
 +
 +
 +This code is to make our text look better. We apply a technique called **antialiasing**.
 +
 +
 +
 +
 +<code java>
 + Font font = new Font("URW Chancery L", Font.BOLD, 21);
 + g2d.setFont(font);
 +</code>
 +
 +
 +
 +
 +We choose a nice font for our text. 
 +
 +
 +
 +
 +<code java>
 + g2d.drawString("Not marble, nor the gilded monuments", 20, 30);
 +</code>
 +
 +
 +
 +
 +This is the code, that actually draws the text.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/sonnet55.jpg |Sonnet 55}}
 +
 +
 +
 +==== Images ====
 +
 +
 +
 +
 +On of the most important capabililies of a toolkit is the ability to display images.
 +An image is an array of pixels. Each pixel represents a color at a given position.
 +We can use components like **JLabel** to display an image, or we can draw it using the **Java 2D API**.
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.Graphics;
 +import java.awt.Graphics2D;
 +import java.awt.Image;
 +
 +import javax.swing.ImageIcon;
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +public class AnImage extends JPanel {
 +
 +    public void paintComponent(Graphics g) {
 +        super.paintComponent(g); 
 +
 +        Graphics2D g2d = (Graphics2D) g;
 +        Image image = new ImageIcon("dumbier.jpg").getImage();
 +        g2d.drawImage(image, 10, 10, null);
 +    }
 +
 +    public static void main(String[] args) {
 +
 +        AnImage image = new AnImage();
 +        JFrame frame = new JFrame("Image");
 +        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +        frame.add(image);
 +        frame.setSize(380, 320);
 +        frame.setLocationRelativeTo(null);
 +        frame.setVisible(true);
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +This example will draw an image on the panel. 
 +
 +
 +
 +
 +<code java>
 + Image image = new ImageIcon("dumbier.jpg").getImage();
 + g2d.drawImage(image, 10, 10, null);
 +</code>
 +
 +
 +
 +
 +These two lines read and draw the image.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/image.jpg |Image}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== Resizable components in Java Swing =====
 +
 +
 +
 +
 +In this part of the Java Swing tutorial, we will create a resizable component. 
 +
 +
 +
 +
 +==== Resizable component ====
 +
 +
 +
 +
 +Resizable components are most often used when creating charts, diagrams and similar. The most common resizable component
 +is a chart in a spreadsheet application. For example, when we create a chart in a OpenOffice application. The chart can 
 +be moved over the grid widget of the application and resized. 
 +
 +
 +
 +
 +
 +
 +
 +In order to create a component that can be freely dragged over a panel, we need a panel with absolute positioning enabled.
 +We must not use a layout manager. 
 +In our example, we will create a component (a JPanel) that we can freely move over a parent window and resize. 
 +
 +
 +
 +
 +
 +
 +
 +In order to distinguish which component has a focus, we draw 8 small rectangles on the border of our resizable component. 
 +This way we know, that the component has focus. The rectangles serve as a dragging points, where we can draw the
 +component and start resizing. I have learnt to use resizable components from [[www.jroller.com/santhosh/category/Swing|this]]
 + blog.
 +
 +
 +
 +
 +
 +<code java>
 +package resizablecomponent;
 +
 +import java.awt.Color;
 +import java.awt.Dimension;
 +import java.awt.event.MouseAdapter;
 +import java.awt.event.MouseEvent;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JPanel;
 +
 +
 +/* ResizableComponent.java */
 +
 +public class ResizableComponent extends JFrame {
 +
 +  private JPanel panel = new JPanel(null);
 +  private Resizable resizer;
 +
 +
 +  public ResizableComponent() {
 +
 +      add(panel);
 +
 +      JPanel area = new JPanel(); 
 +      area.setBackground(Color.white);
 +      resizer = new Resizable(area);
 +      resizer.setBounds(50, 50, 200, 150);
 +      panel.add(resizer);
 +
 + 
 +      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 +      setSize(new Dimension(350, 300));
 +      setTitle("Resizable Component");
 +      setLocationRelativeTo(null);
 +
 +      addMouseListener(new MouseAdapter() {
 +        public void mousePressed(MouseEvent me) {
 +
 +          requestFocus();
 +          resizer.repaint();
 +        }
 +      });
 +  }
 +
 +  public static void main(String[] args) {
 +      ResizableComponent rc = new ResizableComponent();
 +      rc.setVisible(true);
 +  }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +The **ResizableComponent** sets up the panel and the component. 
 +
 +
 +
 +
 +
 +<code java>
 +private JPanel panel = new JPanel(null);
 +</code>
 +
 +
 +
 +
 +We have already mentioned, that we cannot use any layout manager. We must use absolute positioning for resizable component.
 +By providing null to the constructor, we create a panel with absolute positioning.
 +
 +
 +
 +
 +
 +<code java>
 + addMouseListener(new MouseAdapter() {
 +   public void mousePressed(MouseEvent me) {
 + 
 +     requestFocus();
 +     resizer.repaint();
 +   }
 + });
 +</code>
 +
 +
 +
 +
 +If we press on the parent panel, e.g outside the resizable component, we grab focus and repaint the component. The rectangles over the border will disappear. 
 +
 +
 +
 +
 +
 +
 +
 +<code java>
 +package resizablecomponent;
 +
 +import java.awt.Color;
 +import java.awt.Component;
 +import java.awt.Cursor;
 +import java.awt.Graphics;
 +import java.awt.Insets;
 +import java.awt.Rectangle;
 +import java.awt.event.MouseEvent;
 +
 +import javax.swing.SwingConstants;
 +import javax.swing.border.Border;
 +
 +// ResizableBorder.java 
 +
 +public class ResizableBorder implements Border {
 +  private int dist = 8;
 +
 +  int locations[] = 
 +  {
 +    SwingConstants.NORTH, SwingConstants.SOUTH, SwingConstants.WEST,
 +    SwingConstants.EAST, SwingConstants.NORTH_WEST,
 +    SwingConstants.NORTH_EAST, SwingConstants.SOUTH_WEST,
 +    SwingConstants.SOUTH_EAST
 +  };
 +
 +  int cursors[] =
 +  { 
 +    Cursor.N_RESIZE_CURSOR, Cursor.S_RESIZE_CURSOR, Cursor.W_RESIZE_CURSOR,
 +    Cursor.E_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR,
 +    Cursor.SW_RESIZE_CURSOR, Cursor.SE_RESIZE_CURSOR
 +  };
 +
 +  public ResizableBorder(int dist) {
 +    this.dist = dist;
 +  }
 +
 +  public Insets getBorderInsets(Component component) {
 +      return new Insets(dist, dist, dist, dist);
 +  }
 +
 +  public boolean isBorderOpaque() {
 +      return false;
 +  }
 +
 +  public void paintBorder(Component component, Graphics g, int x, int y,
 +                          int w, int h) {
 +      g.setColor(Color.black);
 +      g.drawRect(x + dist / 2, y + dist / 2, w - dist, h - dist);
 + 
 +      if (component.hasFocus()) {
 + 
 +
 +        for (int i = 0; i < locations.length; i++) {
 +          Rectangle rect = getRectangle(x, y, w, h, locations[i]);
 +          g.setColor(Color.WHITE);
 +          g.fillRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
 +          g.setColor(Color.BLACK);
 +          g.drawRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
 +        }
 +      }
 +  }
 +
 +  private Rectangle getRectangle(int x, int y, int w, int h, int location) {
 +      switch (location) {
 +      case SwingConstants.NORTH:
 +          return new Rectangle(x + w / 2 - dist / 2, y, dist, dist);
 +      case SwingConstants.SOUTH:
 +          return new Rectangle(x + w / 2 - dist / 2, y + h - dist, dist,
 +                               dist);
 +      case SwingConstants.WEST:
 +          return new Rectangle(x, y + h / 2 - dist / 2, dist, dist);
 +      case SwingConstants.EAST:
 +          return new Rectangle(x + w - dist, y + h / 2 - dist / 2, dist,
 +                               dist);
 +      case SwingConstants.NORTH_WEST:
 +          return new Rectangle(x, y, dist, dist);
 +      case SwingConstants.NORTH_EAST:
 +          return new Rectangle(x + w - dist, y, dist, dist);
 +      case SwingConstants.SOUTH_WEST:
 +          return new Rectangle(x, y + h - dist, dist, dist);
 +      case SwingConstants.SOUTH_EAST:
 +          return new Rectangle(x + w - dist, y + h - dist, dist, dist);
 +      }
 +      return null;
 +  }
 +
 +  public int getCursor(MouseEvent me) {
 +      Component c = me.getComponent();
 +      int w = c.getWidth();
 +      int h = c.getHeight();
 +
 +      for (int i = 0; i < locations.length; i++) {
 +          Rectangle rect = getRectangle(0, 0, w, h, locations[i]);
 +          if (rect.contains(me.getPoint()))
 +              return cursors[i];
 +      }
 +
 +      return Cursor.MOVE_CURSOR;
 +  }
 +}
 +</code>
 +
 +
 +
 +
 +The **ResizableBorder** is responsible for drawing the border of the component and determining 
 +the type of the cursor to use. 
 +
 +
 +
 +
 +<code java>
 +  int locations[] = 
 +  {
 +    SwingConstants.NORTH, SwingConstants.SOUTH, SwingConstants.WEST,
 +    SwingConstants.EAST, SwingConstants.NORTH_WEST,
 +    SwingConstants.NORTH_EAST, SwingConstants.SOUTH_WEST,
 +    SwingConstants.SOUTH_EAST
 +  };
 +</code>
 +
 +
 +
 +
 +These are locations, where we will draw rectangles. These locations are grabbing points, where we can grab the
 +component and resize it. 
 +
 +
 +
 +
 +<code java>
 +  g.setColor(Color.black);
 +  g.drawRect(x + dist / 2, y + dist / 2, w - dist, h - dist);
 +</code>
 +
 +
 +
 +
 +In the **paintBorder()** method, we draw the border of the resizable component. 
 +The upper code draws the outer border of the component. 
 +
 +
 +
 +
 +<code java>
 +  if (component.hasFocus()) {
 +
 +    for (int i = 0; i < locations.length; i++) {
 +      Rectangle rect = getRectangle(x, y, w, h, locations[i]);
 +      g.setColor(Color.WHITE);
 +      g.fillRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
 +      g.setColor(Color.BLACK);
 +      g.drawRect(rect.x, rect.y, rect.width - 1, rect.height - 1);
 +    }
 +  }
 +</code>
 +
 +
 +
 +
 +The eight rectangles are drawn only in case that the resizable component has currently focus.
 +
 +
 +
 +
 +
 +
 +
 +Finally, the **getRectangle()** method gets the coordinates of the rectangles and the **getCursor()** methods gets the
 +cursor type for the grab point in question.
 +
 +
 +
 +
 +
 +<code java>
 +package resizablecomponent;
 +
 +import java.awt.BorderLayout;
 +import java.awt.Component;
 +import java.awt.Cursor;
 +import java.awt.Point;
 +import java.awt.Rectangle;
 +import java.awt.event.MouseEvent;
 +
 +import javax.swing.JComponent;
 +import javax.swing.event.MouseInputAdapter;
 +import javax.swing.event.MouseInputListener;
 +
 +// Resizable.java 
 +
 +public class Resizable extends JComponent {
 +
 +  public Resizable(Component comp) {
 +    this(comp, new ResizableBorder(8));
 +  }
 +
 +  public Resizable(Component comp, ResizableBorder border) {
 +    setLayout(new BorderLayout());
 +    add(comp);
 +    addMouseListener(resizeListener);
 +    addMouseMotionListener(resizeListener);
 +    setBorder(border);
 +  }
 +
 +  private void resize() {
 +      if (getParent() != null) {
 +        ((JComponent)getParent()).revalidate();
 +      }
 +  }
 +
 +  MouseInputListener resizeListener = new MouseInputAdapter() {
 +    public void mouseMoved(MouseEvent me) {
 +      if (hasFocus()) {
 +          ResizableBorder border = (ResizableBorder)getBorder();
 +          setCursor(Cursor.getPredefinedCursor(border.getCursor(me)));
 +      }
 +    }
 +
 +    public void mouseExited(MouseEvent mouseEvent) {
 +       setCursor(Cursor.getDefaultCursor());
 +    }
 +
 +    private int cursor;
 +    private Point startPos = null;
 +
 +    public void mousePressed(MouseEvent me) {
 +      ResizableBorder border = (ResizableBorder)getBorder();
 +      cursor = border.getCursor(me);
 +      startPos = me.getPoint();
 +      requestFocus();
 +      repaint();
 +    }
 +
 +    public void mouseDragged(MouseEvent me) {
 +
 +      if (startPos != null) {
 +
 +        int x = getX();
 +        int y = getY();
 +        int w = getWidth();
 +        int h = getHeight();
 +
 +        int dx = me.getX() - startPos.x;
 +        int dy = me.getY() - startPos.y;
 + 
 +        switch (cursor) {
 +          case Cursor.N_RESIZE_CURSOR:
 +            if (!(h - dy < 50)) {
 +              setBounds(x, y + dy, w, h - dy);
 +              resize();
 +            }
 +            break;
 +
 +          case Cursor.S_RESIZE_CURSOR:
 +            if (!(h + dy < 50)) {
 +              setBounds(x, y, w, h + dy);
 +              startPos = me.getPoint();
 +              resize();
 +            }
 +            break;
 +
 +          case Cursor.W_RESIZE_CURSOR:
 +            if (!(w - dx < 50)) {
 +              setBounds(x + dx, y, w - dx, h);
 +              resize();
 +            }
 +            break;
 +
 +          case Cursor.E_RESIZE_CURSOR:
 +            if (!(w + dx < 50)) {
 +              setBounds(x, y, w + dx, h);
 +              startPos = me.getPoint();
 +              resize();
 +            }
 +            break;
 +
 +          case Cursor.NW_RESIZE_CURSOR:
 +            if (!(w - dx < 50) && !(h - dy < 50)) {
 +              setBounds(x + dx, y + dy, w - dx, h - dy);
 +              resize();
 +            }
 +            break;
 +
 +          case Cursor.NE_RESIZE_CURSOR:
 +            if (!(w + dx < 50) && !(h - dy < 50)) {
 +              setBounds(x, y + dy, w + dx, h - dy);
 +              startPos = new Point(me.getX(), startPos.y);
 +              resize();
 +            }
 +            break;
 +
 +          case Cursor.SW_RESIZE_CURSOR:
 +            if (!(w - dx < 50) && !(h + dy < 50)) {
 +              setBounds(x + dx, y, w - dx, h + dy);
 +              startPos = new Point(startPos.x, me.getY());
 +              resize();
 +            }
 +            break;
 +
 +          case Cursor.SE_RESIZE_CURSOR:
 +            if (!(w + dx < 50) && !(h + dy < 50)) {
 +              setBounds(x, y, w + dx, h + dy);
 +              startPos = me.getPoint();
 +              resize();
 +            }
 +          break;
 +
 +          case Cursor.MOVE_CURSOR:
 +            Rectangle bounds = getBounds();
 +            bounds.translate(dx, dy);
 +            setBounds(bounds);
 +            resize();
 +          }
 +
 +
 +          setCursor(Cursor.getPredefinedCursor(cursor));
 +        }
 +     }
 +
 +   public void mouseReleased(MouseEvent mouseEvent) {
 +     startPos = null;
 +    }
 +  };
 +}
 +</code>
 +
 +
 +
 +
 +
 +The **Resizable** class represents the component, that is being resized and moved on the window.
 +
 +
 +
 +
 +<code java>
 +  private void resize() {
 +      if (getParent() != null) {
 +        ((JComponent)getParent()).revalidate();
 +      }
 +  }
 +</code>
 +
 +
 +
 +
 +The **resize()** method is called, after we have resized the component. The **revalidate()** method
 +will cause the component to be redrawn. 
 +
 +
 +
 +
 +<code java>
 + MouseInputListener resizeListener = new MouseInputAdapter() {
 +   public void mouseMoved(MouseEvent me) {
 +     if (hasFocus()) {
 +         ResizableBorder border = (ResizableBorder)getBorder();
 +         setCursor(Cursor.getPredefinedCursor(border.getCursor(me)));
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +We change the cursor type, when we hover the cursor over the grip points. The cursor type changes only if the component has
 +focus.
 +
 +
 +
 +
 +<code java>
 + public void mousePressed(MouseEvent me) {
 +   ResizableBorder border = (ResizableBorder)getBorder();
 +     cursor = border.getCursor(me);
 +     startPos = me.getPoint();
 +     requestFocus();
 +     repaint();
 + }
 +</code>
 +
 +
 +
 +
 +If we click on the resizable component, we change the cursor, get the starting point of dragging, give focus to the
 +component and redraw it. 
 +
 +
 +
 +
 +<code java>
 + int x = getX();
 + int y = getY();
 + int w = getWidth();
 + int h = getHeight();
 +
 + int dx = me.getX() - startPos.x;
 + int dy = me.getY() - startPos.y;
 +</code>
 +
 +
 +
 +
 +In the **mouseDragged()** method, we determine the x, y coordinates of the cursor, width and height of the
 +component. We calculate the distances, that we make during the mouse drag event.  
 +
 +
 +
 +
 +<code java>
 + case Cursor.N_RESIZE_CURSOR:
 +   if (!(h - dy < 50)) {
 +    setBounds(x, y + dy, w, h - dy);
 +    resize();
 +   }
 +   break;
 +</code>
 +
 +
 +
 +
 +For all resizing we ensure, that the component is not smaller than 50 px. Otherwise, we could make it so small, that we
 +would eventually hide the component. The **setBounds()** method relocates and resizes the component. 
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/resizablecomponent.png |Resizable component}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== The Puzzle in Java Swing =====
 +
 +
 +
 +
 +
 +In this chapter, we will create a simple puzzle game in Java Swing toolkit. 
 +
 +
 +
 +
 +
 +==== Puzzle ====
 +
 +
 +
 +
 +
 +We have an image of a Sid character from the Ice Age movie. It is cut into 12 pieces. The goal is to form the picture. You can download the picture <a href="../images/icesid.jpg">here</a>
 +
 +
 +
 +
 +
 +<code java>
 +import java.awt.BorderLayout;
 +import java.awt.Dimension;
 +import java.awt.GridLayout;
 +import java.awt.Image;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.image.CropImageFilter;
 +import java.awt.image.FilteredImageSource;
 +
 +import javax.swing.Box;
 +import javax.swing.ImageIcon;
 +import javax.swing.JButton;
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +
 +
 +public class Puzzle extends JFrame implements ActionListener {
 +
 +    private JPanel centerPanel;
 +    private JButton button;
 +    private JLabel label;
 +    private Image source;
 +    private Image image;
 +    int[][] pos;
 +    int width, height;
 +
 +    public Puzzle() {
 +
 +        pos = new int[][] {
 +                            {0, 1, 2}, 
 +                            {3, 4, 5}, 
 +                            {6, 7, 8}, 
 +                            {9, 10, 11}
 +                        };
 +
 +
 +        centerPanel = new JPanel();
 +        centerPanel.setLayout(new GridLayout(4, 4, 0, 0));
 +
 +        ImageIcon sid = new ImageIcon(Puzzle.class.getResource("icesid.jpg"));
 +        source = sid.getImage();
 +
 +        width = sid.getIconWidth();
 +        height = sid.getIconHeight();
 +
 +
 +        add(Box.createRigidArea(new Dimension(0, 5)), BorderLayout.NORTH);    
 +        add(centerPanel, BorderLayout.CENTER);
 +
 +
 +        for ( int i = 0; i &lt; 4; i++) {
 +            for ( int j = 0; j &lt; 3; j++) {
 +                if ( j == 2 &amp;&amp; i == 3) {
 +                    label = new JLabel("");
 +                    centerPanel.add(label);
 +                } else {
 +                    button = new JButton();
 +                    button.addActionListener(this);
 +                    centerPanel.add(button);
 +                    image = createImage(new FilteredImageSource(source.getSource(),
 +                        new CropImageFilter(j*width/3, i*height/4, (width/3)+1, height/4)));
 +                    button.setIcon(new ImageIcon(image));
 +                }
 +            }
 +        }
 +
 +        setSize(325, 275);
 +        setTitle("Puzzle");
 +        setResizable(false);
 +        setLocationRelativeTo(null);
 +        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
 +        setVisible(true);
 +    }
 +
 +
 +    public static void main(String[] args) {
 +
 +        new Puzzle();
 +
 +    }
 +
 +    public void actionPerformed(ActionEvent e) {
 +        JButton button = (JButton) e.getSource();
 +        Dimension size = button.getSize();
 +
 +        int labelX = label.getX();
 +        int labelY = label.getY();
 +        int buttonX = button.getX();
 +        int buttonY = button.getY();
 +        int buttonPosX = buttonX / size.width;
 +        int buttonPosY = buttonY / size.height;
 +        int buttonIndex = pos[buttonPosY][buttonPosX];
 +
 +
 +
 +        if (labelX == buttonX &amp;&amp; (labelY - buttonY) == size.height ) {
 +
 +             int labelIndex = buttonIndex + 3;
 +
 +             centerPanel.remove(buttonIndex);
 +             centerPanel.add(label, buttonIndex);
 +             centerPanel.add(button,labelIndex);
 +             centerPanel.validate();
 +        }
 +
 +        if (labelX == buttonX &amp;&amp; (labelY - buttonY) == -size.height ) {
 +
 +             int labelIndex = buttonIndex - 3;
 +             centerPanel.remove(labelIndex);
 +             centerPanel.add(button,labelIndex);
 +             centerPanel.add(label, buttonIndex);
 +             centerPanel.validate();
 +        }
 +
 +        if (labelY == buttonY &amp;&amp; (labelX - buttonX) == size.width ) {
 +
 +             int labelIndex = buttonIndex + 1;
 +
 +             centerPanel.remove(buttonIndex);
 +             centerPanel.add(label, buttonIndex);
 +             centerPanel.add(button,labelIndex);
 +             centerPanel.validate();
 +        }
 +
 +        if (labelY == buttonY &amp;&amp; (labelX - buttonX) == -size.width ) {
 +
 +             int labelIndex = buttonIndex - 1;
 +
 +             centerPanel.remove(buttonIndex);
 +             centerPanel.add(label, labelIndex);
 +             centerPanel.add(button,labelIndex);
 +             centerPanel.validate();
 +        }
 +    }
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +The goal of this little game is to form the original picture. We move the buttons by clicking on them. Only buttons adjacent to the label can be moved. 
 +
 +
 +
 +
 +<code java>
 + pos = new int[][] {
 +       {0, 1, 2}, 
 +       {3, 4, 5}, 
 +       {6, 7, 8}, 
 +       {9, 10, 11}
 + };
 +</code>
 +
 +
 +
 +
 +These are the positions of the image parts.
 +
 +
 +
 +
 +<code java>
 + ImageIcon sid = new ImageIcon(Puzzle.class.getResource("icesid.jpg"));
 + source = sid.getImage();
 +</code>
 +
 +
 +
 +
 +We use the **ImageIcon** class to load the image. 
 +
 +
 +
 +
 +<code java>
 + for ( int i = 0; i &lt; 4; i++) {
 +     for ( int j = 0; j &lt; 3; j++) {
 +         if ( j == 2 &amp;&amp; i == 3) {
 +             label = new JLabel("");
 +             centerPanel.add(label);
 +         } else {
 +             button = new JButton();
 +             button.addActionListener(this);
 +             centerPanel.add(button);
 +             image = createImage(new FilteredImageSource(source.getSource(),
 +                 new CropImageFilter(j*width/3, i*height/4, (width/3)+1, height/4)));
 +             button.setIcon(new ImageIcon(image));
 +         }
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +The code creates 11 buttons and one label. We crop the image into pieces and place them on the buttons. 
 +
 +
 +
 +
 +<code java>
 + int labelX = label.getX();
 + int labelY = label.getY();
 + int buttonX = button.getX();
 + int buttonY = button.getY();
 +</code>
 +
 +
 +
 +
 +We get the x, y coordinates of the button that we hit and an empty label. The x, y coordinates are important in the logic of the program.  
 +
 +
 +
 +
 +<code java>
 + int buttonPosX = buttonX / size.width;
 + int buttonPosY = buttonY / size.height;
 + int buttonIndex = pos[buttonPosY][buttonPosX];
 +</code>
 +
 +
 +
 +
 +Here we get the index of the button in the two dimensional array of the button positions. 
 +
 +
 +
 +
 +<code java>
 + if (labelX == buttonX &amp;&amp; (labelY - buttonY) == size.height ) {
 +
 +      int labelIndex = buttonIndex + 3;
 +
 +      centerPanel.remove(buttonIndex);
 +      centerPanel.add(label, buttonIndex);
 +      centerPanel.add(button,labelIndex);
 +      centerPanel.validate();
 + }
 +</code>
 +
 +
 +
 +
 +In this case, we check if we clicked on the button, that is right above the empty label. If it is above the label, they share the x coordinate. If the button is right above the label, the equation  
 +‪ ''(labelY - buttonY) == size.height""
 +  is true. 
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/puzzle.png |Puzzle}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +===== The Tetris game =====
 +
 +
 +
 +
 +
 +In this chapter, we will create a Tetris game clone in Java Swing. The following example is based on the C++ code example available at [[doc.trolltech.com/|doc.trolltech.com]]
 +. It is modified and simplified.
 +
 +
 +
 +
 +
 +==== Tetris ====
 +
 +
 +
 +
 +The Tetris game is one of the most popular computer games ever created. The original game was designed and programmed
 +by a russian programmer **Alexey Pajitnov** in 1985. Since then, Tetris is available on almost every computer platform in lots of variations. Even my mobile phone has a modified version of the Tetris game. 
 +
 +
 +
 +
 +
 +
 +
 +Tetris is called a falling block puzzle game. In this game, we have seven different shapes called **tetrominoes**.
 +S-shape, Z-shape, T-shape, L-shape, Line-shape, MirroredL-shape and a Square-shape.
 +Each of these shapes is formed with four squares. 
 +The shapes are falling down the board.
 +The object of the Tetris game is to move and rotate the shapes, so that they fit as much as possible. 
 +If we manage to form a row, the row is destroyed and we score. We play the tetris game until we top out.
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/tetrominoes.png |Tetrominoes}}
 +
 +
 +==== The development ====
 +
 +
 +
 +
 +We do not have images for our tetris game, we draw the tetrominoes using Swing drawing API. Behind every computer game, there is a mathematical model. So it is in Tetris. 
 +
 +
 +
 +
 +
 +
 +
 +Some ideas behind the game.
 +
 +
 +
 +
 +
 +  * We use a **Timer** class to create a game cycle
 +  * The tetrominoes are drawn
 +  * The shapes move on a square by square basis (not pixel by pixel)
 +
 +  * Mathematically a board is a simple list of numbers
 +
 +
 +
 +
 +
 +
 +
 +I have simplified the game a bit, so that it is easier to understand. The game starts immediately, after it is launched. We can pause the game by pressing the p key. The space key will drop the tetris piece immediately to the bottom. The d key will drop the piece one line down. (It can be used to speed up the falling a bit.) The game goes at constant speed, no acceleration is implemented. The score is the number of lines, that we have removed.
 +
 +
 +
 +
 +<code java>
 +// Tetris.java
 +
 +package tetris;
 +
 +import java.awt.BorderLayout;
 +
 +import javax.swing.JFrame;
 +import javax.swing.JLabel;
 +
 +
 +public class Tetris extends JFrame {
 +
 +    JLabel statusbar;
 +
 +
 +    public Tetris() {
 +
 +        statusbar = new JLabel(" 0");
 +        add(statusbar, BorderLayout.SOUTH);
 +        Board board = new Board(this);
 +        add(board);
 +        board.start();
 +
 +        setSize(200, 400);
 +        setTitle("Tetris");
 +        setDefaultCloseOperation(EXIT_ON_CLOSE);
 +   }
 +
 +   public JLabel getStatusBar() {
 +       return statusbar;
 +   }
 +
 +    public static void main(String[] args) {
 +
 +        Tetris game = new Tetris();
 +        game.setLocationRelativeTo(null);
 +        game.setVisible(true);
 +
 +    } 
 +}
 +</code>
 +
 +
 +
 +
 +
 +
 +
 +In the Tetris.java file, we set up the game. We create a board on which we play the game. We create a statusbar. 
 +
 +
 +
 +
 +<code java>
 + board.start();
 +</code>
 +
 +
 +
 +
 +The **start()** method starts the Tetris game. Immediately, after the window appears on the screen. 
 +
 +
 +
 +
 +<code java>
 +// Shape.java
 +
 +package tetris;
 +
 +import java.util.Random;
 +import java.lang.Math;
 +
 +
 +public class Shape {
 +
 +    enum Tetrominoes { NoShape, ZShape, SShape, LineShape, 
 +               TShape, SquareShape, LShape, MirroredLShape };
 +
 +    private Tetrominoes pieceShape;
 +    private int coords[][];
 +    private int[][][] coordsTable;
 +
 +
 +    public Shape() {
 +
 +        coords = new int[4][2];
 +        setShape(Tetrominoes.NoShape);
 +
 +    }
 +
 +    public void setShape(Tetrominoes shape) {
 +
 +         coordsTable = new int[][][] {
 +            { { 0, 0 },   { 0, 0 },   { 0, 0 },   { 0, 0 } },
 +            { { 0, -1 },  { 0, 0 },   { -1, 0 },  { -1, 1 } },
 +            { { 0, -1 },  { 0, 0 },   { 1, 0 },   { 1, 1 } },
 +            { { 0, -1 },  { 0, 0 },   { 0, 1 },   { 0, 2 } },
 +            { { -1, 0 },  { 0, 0 },   { 1, 0 },   { 0, 1 } },
 +            { { 0, 0 },   { 1, 0 },   { 0, 1 },   { 1, 1 } },
 +            { { -1, -1 }, { 0, -1 },  { 0, 0 },   { 0, 1 } },
 +            { { 1, -1 },  { 0, -1 },  { 0, 0 },   { 0, 1 } }
 +        };
 +
 +        for (int i = 0; i &lt; 4 ; i++) {
 +            for (int j = 0; j &lt; 2; ++j) {
 +                coords[i][j] = coordsTable[shape.ordinal()][i][j];
 +            }
 +        }
 +        pieceShape = shape;
 +
 +    }
 +
 +    private void setX(int index, int x) { coords[index][0] = x; }
 +    private void setY(int index, int y) { coords[index][1] = y; }
 +    public int x(int index) { return coords[index][0]; }
 +    public int y(int index) { return coords[index][1]; }
 +    public Tetrominoes getShape()  { return pieceShape; }
 +
 +    public void setRandomShape()
 +    {
 +        Random r = new Random();
 +        int x = Math.abs(r.nextInt()) % 7 + 1;
 +        Tetrominoes[] values = Tetrominoes.values(); 
 +        setShape(values[x]);
 +    }
 +
 +    public int minX()
 +    {
 +      int m = coords[0][0];
 +      for (int i=0; i &lt; 4; i++) {
 +          m = Math.min(m, coords[i][0]);
 +      }
 +      return m;
 +    }
 +
 +
 +    public int minY() 
 +    {
 +      int m = coords[0][1];
 +      for (int i=0; i &lt; 4; i++) {
 +          m = Math.min(m, coords[i][1]);
 +      }
 +      return m;
 +    }
 +
 +    public Shape rotateLeft() 
 +    {
 +        if (pieceShape == Tetrominoes.SquareShape)
 +            return this;
 +
 +        Shape result = new Shape();
 +        result.pieceShape = pieceShape;
 +
 +        for (int i = 0; i &lt; 4; ++i) {
 +            result.setX(i, y(i));
 +            result.setY(i, -x(i));
 +        }
 +        return result;
 +    }
 +
 +    public Shape rotateRight()
 +    {
 +        if (pieceShape == Tetrominoes.SquareShape)
 +            return this;
 +
 +        Shape result = new Shape();
 +        result.pieceShape = pieceShape;
 +
 +        for (int i = 0; i &lt; 4; ++i) {
 +            result.setX(i, -y(i));
 +            result.setY(i, x(i));
 +        }
 +        return result;
 +    }
 +}
 +
 +
 +</code>
 +
 +
 +
 +
 +The **Shape** class provides information about a tetris piece. 
 +
 +
 +
 +
 +<code java>
 + enum Tetrominoes { NoShape, ZShape, SShape, LineShape, 
 +            TShape, SquareShape, LShape, MirroredLShape };
 +</code>
 +
 +
 +
 +
 +The **Tetrominoes** enum holds all seven tetris shapes. Plus the empty shape called here **NoShape**.
 +
 +
 +
 +
 +<code java>
 + public Shape() {
 +
 +     coords = new int[4][2];
 +     setShape(Tetrominoes.NoShape);
 +
 + }
 +</code>
 +
 +
 +
 +
 +This is the constructor of the **Shape** class. The **coords** array holds the actual coordinates of a tetris piece. 
 +
 +
 +
 +
 +<code java>
 + coordsTable = new int[][][] {
 +    { { 0, 0 },   { 0, 0 },   { 0, 0 },   { 0, 0 } },
 +    { { 0, -1 },  { 0, 0 },   { -1, 0 },  { -1, 1 } },
 +    { { 0, -1 },  { 0, 0 },   { 1, 0 },   { 1, 1 } },
 +    { { 0, -1 },  { 0, 0 },   { 0, 1 },   { 0, 2 } },
 +    { { -1, 0 },  { 0, 0 },   { 1, 0 },   { 0, 1 } },
 +    { { 0, 0 },   { 1, 0 },   { 0, 1 },   { 1, 1 } },
 +    { { -1, -1 }, { 0, -1 },  { 0, 0 },   { 0, 1 } },
 +    { { 1, -1 },  { 0, -1 },  { 0, 0 },   { 0, 1 } }
 + };
 +</code>
 +
 +
 +
 +
 +The **coordsTable** array holds all possible coordinate values of our tetris pieces. This is a template from which all pieces take their coordiate values. 
 +
 +
 +
 +
 +<code java>
 + for (int i = 0; i &lt; 4 ; i++) {
 +     for (int j = 0; j &lt; 2; ++j) {
 +         coords[i][j] = coordsTable[shape.ordinal()][i][j];
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +Here we put one row of the coordiate values from the **coordsTable** to a **coords**
 +array of a tetris piece. Note the use of the **ordinal()** method. In C++, an enum type is esencially an integer. Unlike in C++, Java enums are full classes. And the ordinal() method returns the current position of the enum type in the enum object. 
 +
 +
 +
 +
 +
 +
 +
 +The following image will help understand the coordinate values a bit more. The coords array saves the coordinates of the tetris piece. For example, numbers { 0, -1 }, { 0, 0 }, { 1, 0 }, { 1, 1 } , represent a rotated S-shape. The following diagram illustrates the shape.
 +
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/coordinates.png |Tetris}}
 +
 +
 +<code java>
 + public Shape rotateLeft() 
 + {
 +     if (pieceShape == Tetrominoes.SquareShape)
 +         return this;
 +
 +     Shape result = new Shape();
 +     result.pieceShape = pieceShape;
 +
 +     for (int i = 0; i &lt; 4; ++i) {
 +         result.setX(i, y(i));
 +         result.setY(i, -x(i));
 +     }
 +     return result;
 +  }
 +</code>
 +
 +
 +
 +
 +This code rotates the piece to the left. The square does not have to be rotated. That's why we simply return the reference to the current object. Looking at the previous image will help to understand the rotation. 
 +
 +
 +
 +
 +
 +
 +<code java>
 +// Board.java
 +
 +package tetris;
 +
 +import java.awt.Color;
 +import java.awt.Dimension;
 +import java.awt.Graphics;
 +import java.awt.event.ActionEvent;
 +import java.awt.event.ActionListener;
 +import java.awt.event.KeyAdapter;
 +import java.awt.event.KeyEvent;
 +
 +import javax.swing.JLabel;
 +import javax.swing.JPanel;
 +import javax.swing.Timer;
 +
 +import tetris.Shape.Tetrominoes;
 +
 +
 +public class Board extends JPanel implements ActionListener {
 +
 +
 +    final int BoardWidth = 10;
 +    final int BoardHeight = 22;
 +
 +    Timer timer;
 +    boolean isFallingFinished = false;
 +    boolean isStarted = false;
 +    boolean isPaused = false;
 +    int numLinesRemoved = 0;
 +    int curX = 0;
 +    int curY = 0;
 +    JLabel statusbar;
 +    Shape curPiece;
 +    Tetrominoes[] board;
 +
 +
 +
 +    public Board(Tetris parent) {
 +
 +       setFocusable(true);
 +       curPiece = new Shape();
 +       timer = new Timer(400, this);
 +       timer.start(); 
 +
 +       statusbar =  parent.getStatusBar();
 +       board = new Tetrominoes[BoardWidth * BoardHeight];
 +       addKeyListener(new TAdapter());
 +       clearBoard();  
 +    }
 +
 +    public void actionPerformed(ActionEvent e) {
 +        if (isFallingFinished) {
 +            isFallingFinished = false;
 +            newPiece();
 +        } else {
 +            oneLineDown();
 +        }
 +    }
 +
 +
 +    int squareWidth() { return (int) getSize().getWidth() / BoardWidth; }
 +    int squareHeight() { return (int) getSize().getHeight() / BoardHeight; }
 +    Tetrominoes shapeAt(int x, int y) { return board[(y * BoardWidth) + x]; }
 +
 +
 +    public void start()
 +    {
 +        if (isPaused)
 +            return;
 +
 +        isStarted = true;
 +        isFallingFinished = false;
 +        numLinesRemoved = 0;
 +        clearBoard();
 +
 +        newPiece();
 +        timer.start();
 +    }
 +
 +    private void pause()
 +    {
 +        if (!isStarted)
 +            return;
 +
 +        isPaused = !isPaused;
 +        if (isPaused) {
 +            timer.stop();
 +            statusbar.setText("paused");
 +        } else {
 +            timer.start();
 +            statusbar.setText(String.valueOf(numLinesRemoved));
 +        }
 +        repaint();
 +    }
 +
 +    public void paint(Graphics g)
 +    { 
 +        super.paint(g);
 +
 +        Dimension size = getSize();
 +        int boardTop = (int) size.getHeight() - BoardHeight * squareHeight();
 +
 +
 +        for (int i = 0; i &lt; BoardHeight; ++i) {
 +            for (int j = 0; j &lt; BoardWidth; ++j) {
 +                Tetrominoes shape = shapeAt(j, BoardHeight - i - 1);
 +                if (shape != Tetrominoes.NoShape)
 +                    drawSquare(g, 0 + j * squareWidth(),
 +                               boardTop + i * squareHeight(), shape);
 +            }
 +        }
 +
 +        if (curPiece.getShape() != Tetrominoes.NoShape) {
 +            for (int i = 0; i &lt; 4; ++i) {
 +                int x = curX + curPiece.x(i);
 +                int y = curY - curPiece.y(i);
 +                drawSquare(g, 0 + x * squareWidth(),
 +                           boardTop + (BoardHeight - y - 1) * squareHeight(),
 +                           curPiece.getShape());
 +            }
 +        }
 +    }
 +
 +    private void dropDown()
 +    {
 +        int newY = curY;
 +        while (newY > 0) {
 +            if (!tryMove(curPiece, curX, newY - 1))
 +                break;
 +            --newY;
 +        }
 +        pieceDropped();
 +    }
 +
 +    private void oneLineDown()
 +    {
 +        if (!tryMove(curPiece, curX, curY - 1))
 +            pieceDropped();
 +    }
 +
 +
 +    private void clearBoard()
 +    {
 +        for (int i = 0; i &lt; BoardHeight * BoardWidth; ++i)
 +            board[i] = Tetrominoes.NoShape;
 +    }
 +
 +    private void pieceDropped()
 +    {
 +        for (int i = 0; i &lt; 4; ++i) {
 +            int x = curX + curPiece.x(i);
 +            int y = curY - curPiece.y(i);
 +            board[(y * BoardWidth) + x] = curPiece.getShape();
 +        }
 +
 +        removeFullLines();
 +
 +        if (!isFallingFinished)
 +            newPiece();
 +    }
 +
 +    private void newPiece()
 +    {
 +        curPiece.setRandomShape();
 +        curX = BoardWidth / 2 + 1;
 +        curY = BoardHeight - 1 + curPiece.minY();
 +
 +        if (!tryMove(curPiece, curX, curY)) {
 +            curPiece.setShape(Tetrominoes.NoShape);
 +            timer.stop();
 +            isStarted = false;
 +            statusbar.setText("game over");
 +        }
 +    }
 +
 +    private boolean tryMove(Shape newPiece, int newX, int newY)
 +    {
 +        for (int i = 0; i &lt; 4; ++i) {
 +            int x = newX + newPiece.x(i);
 +            int y = newY - newPiece.y(i);
 +            if (x &lt; 0 || x >= BoardWidth || y &lt; 0 || y >= BoardHeight)
 +                return false;
 +            if (shapeAt(x, y) != Tetrominoes.NoShape)
 +                return false;
 +        }
 +
 +        curPiece = newPiece;
 +        curX = newX;
 +        curY = newY;
 +        repaint();
 +        return true;
 +    }
 +
 +    private void removeFullLines()
 +    {
 +        int numFullLines = 0;
 +
 +        for (int i = BoardHeight - 1; i >= 0; --i) {
 +            boolean lineIsFull = true;
 +
 +            for (int j = 0; j &lt; BoardWidth; ++j) {
 +                if (shapeAt(j, i) == Tetrominoes.NoShape) {
 +                    lineIsFull = false;
 +                    break;
 +                }
 +            }
 +
 +            if (lineIsFull) {
 +                ++numFullLines;
 +                for (int k = i; k &lt; BoardHeight - 1; ++k) {
 +                    for (int j = 0; j &lt; BoardWidth; ++j)
 +                         board[(k * BoardWidth) + j] = shapeAt(j, k + 1);
 +                }
 +            }
 +        }
 +
 +        if (numFullLines > 0) {
 +            numLinesRemoved += numFullLines;
 +            statusbar.setText(String.valueOf(numLinesRemoved));
 +            isFallingFinished = true;
 +            curPiece.setShape(Tetrominoes.NoShape);
 +            repaint();
 +        }
 +     }
 +
 +    private void drawSquare(Graphics g, int x, int y, Tetrominoes shape)
 +    {
 +        Color colors[] = { new Color(0, 0, 0), new Color(204, 102, 102), 
 +            new Color(102, 204, 102), new Color(102, 102, 204), 
 +            new Color(204, 204, 102), new Color(204, 102, 204), 
 +            new Color(102, 204, 204), new Color(218, 170, 0)
 +        };
 +
 +
 +        Color color = colors[shape.ordinal()];
 +
 +        g.setColor(color);
 +        g.fillRect(x + 1, y + 1, squareWidth() - 2, squareHeight() - 2);
 +
 +        g.setColor(color.brighter());
 +        g.drawLine(x, y + squareHeight() - 1, x, y);
 +        g.drawLine(x, y, x + squareWidth() - 1, y);
 +
 +        g.setColor(color.darker());
 +        g.drawLine(x + 1, y + squareHeight() - 1,
 +                         x + squareWidth() - 1, y + squareHeight() - 1);
 +        g.drawLine(x + squareWidth() - 1, y + squareHeight() - 1,
 +                         x + squareWidth() - 1, y + 1);
 +
 +    }
 +
 +    class TAdapter extends KeyAdapter {
 +         public void keyPressed(KeyEvent e) {
 +
 +             if (!isStarted || curPiece.getShape() == Tetrominoes.NoShape) {  
 +                 return;
 +             }
 +
 +             int keycode = e.getKeyCode();
 +
 +             if (keycode == 'p' || keycode == 'P') {
 +                 pause();
 +                 return;
 +             }
 +
 +             if (isPaused)
 +                 return;
 +
 +             switch (keycode) {
 +             case KeyEvent.VK_LEFT:
 +                 tryMove(curPiece, curX - 1, curY);
 +                 break;
 +             case KeyEvent.VK_RIGHT:
 +                 tryMove(curPiece, curX + 1, curY);
 +                 break;
 +             case KeyEvent.VK_DOWN:
 +                 tryMove(curPiece.rotateRight(), curX, curY);
 +                 break;
 +             case KeyEvent.VK_UP:
 +                 tryMove(curPiece.rotateLeft(), curX, curY);
 +                 break;
 +             case KeyEvent.VK_SPACE:
 +                 dropDown();
 +                 break;
 +             case 'd':
 +                 oneLineDown();
 +                 break;
 +             case 'D':
 +                 oneLineDown();
 +                 break;
 +             }
 +
 +         }
 +     }
 +}
 +</code>
 +
 +
 +
 +
 +Finally, we have the Board.java file. This is where the game logic is located. 
 +
 +
 +
 +
 +
 +
 +<code java>
 + ...
 + isFallingFinished = false;
 + isStarted = false;
 + isPaused = false;
 + numLinesRemoved = 0;
 + curX = 0;
 + curY = 0;
 + ...
 +</code>
 +
 +
 +
 +
 +We initialize some important variables. The **isFallingFinished** variable determines, if the tetris shape has finished falling and we then need to create a new shape. The **numLinesRemoved** counts the number of lines, we have removed so far. The **curX** and **curY** variables determine the actual position of the falling tetris shape.
 +
 +
 +
 +
 +<code java>
 + setFocusable(true);
 +</code>
 +
 +
 +
 +
 +We must explicitely call the **setFocusable()** method. From now, the board has the keyboard input. 
 +
 +
 +
 +
 +<code java>
 + timer = new Timer(400, this);
 + timer.start(); 
 +</code>
 +
 +
 +
 +
 +**Timer** object fires one or more action events after a specified delay. In our case, the timer calls the **actionPerformed()** method each 400 ms. 
 +
 +
 +
 +
 +<code java>
 + public void actionPerformed(ActionEvent e) {
 +     if (isFallingFinished) {
 +         isFallingFinished = false;
 +         newPiece();
 +     } else {
 +         oneLineDown();
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +The **actionPerformed()** method checks if the falling has finished. If so, a new piece is created. If not, the falling tetris piece goes one line down. 
 +
 +
 +
 +
 +
 +
 +
 +
 +Inside the **paint()** method, we draw the all objects on the board. The painting has two steps. 
 +
 +
 +
 +
 +<code java>
 + for (int i = 0; i &lt; BoardHeight; ++i) {
 +     for (int j = 0; j &lt; BoardWidth; ++j) {
 +         Tetrominoes shape = shapeAt(j, BoardHeight - i - 1);
 +         if (shape != Tetrominoes.NoShape)
 +             drawSquare(g, 0 + j * squareWidth(),
 +                        boardTop + i * squareHeight(), shape);
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +In the first step we paint all the shapes, or remains of the shapes, that have been dropped to the bottom of the board. All the squares are rememberd in the board array. We access it using the **shapeAt()** method.
 +
 +
 +
 +
 +<code java>
 + if (curPiece.getShape() != Tetrominoes.NoShape) {
 +     for (int i = 0; i &lt; 4; ++i) {
 +         int x = curX + curPiece.x(i);
 +         int y = curY - curPiece.y(i);
 +         drawSquare(g, 0 + x * squareWidth(),
 +                    boardTop + (BoardHeight - y - 1) * squareHeight(),
 +                    curPiece.getShape());
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +In the second step, we paint the actual falling piece. 
 +
 +
 +
 +
 +<code java>
 + private void dropDown()
 + {
 +     int newY = curY;
 +     while (newY > 0) {
 +         if (!tryMove(curPiece, curX, newY - 1))
 +             break;
 +         --newY;
 +     }
 +     pieceDropped();
 + }
 +</code>
 +
 +
 +
 +
 +If we press the space key, the piece is dropped to the bottom. We simply try to drop the piece one line down until it reaches the bottom or the top of another fallen tetris piece. 
 +
 +
 +
 +
 +<code java>
 + private void clearBoard()
 + {
 +     for (int i = 0; i &lt; BoardHeight * BoardWidth; ++i)
 +         board[i] = Tetrominoes.NoShape;
 + }
 +</code>
 +
 +
 +
 +
 +The **clearBoard()** method fills the board with empty NoSpapes. This is later used at collision detection.
 +
 +
 +
 +
 +<code java>
 + private void pieceDropped()
 + {
 +     for (int i = 0; i &lt; 4; ++i) {
 +         int x = curX + curPiece.x(i);
 +         int y = curY - curPiece.y(i);
 +         board[(y * BoardWidth) + x] = curPiece.getShape();
 +     }
 +
 +     removeFullLines();
 +
 +     if (!isFallingFinished)
 +         newPiece();
 + }
 +</code>
 +
 +
 +
 +
 +The **pieceDropped()** method puts the falling piece into the **board** array. Once again, the board holds all the squares of the pieces and remains of the pieces that has finished falling. When the piece has finished falling, it is time to check, if we can remove some lines off the board. This is the job of the **removeFullLines()** method. Then we create a new piece. More precisely, we try to create a new piece. 
 +
 +
 +
 +
 +<code java>
 + private void newPiece()
 + {
 +     curPiece.setRandomShape();
 +     curX = BoardWidth / 2 + 1;
 +     curY = BoardHeight - 1 + curPiece.minY();
 +
 +     if (!tryMove(curPiece, curX, curY)) {
 +         curPiece.setShape(Tetrominoes.NoShape);
 +         timer.stop();
 +         isStarted = false;
 +         statusbar.setText("game over");
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +The **newPiece()** method creates a new tetris piece. The piece gets a new random shape. Then we compute the initial **curX** and **curY** values. If we cannot move to the initial positions, the game is over. We top out. The timer is stopped. We put game over string on the statusbar. 
 +
 +
 +
 +
 +<code java>
 + private boolean tryMove(Shape newPiece, int newX, int newY)
 + {
 +     for (int i = 0; i &lt; 4; ++i) {
 +         int x = newX + newPiece.x(i);
 +         int y = newY - newPiece.y(i);
 +         if (x &lt; 0 || x &gt;= BoardWidth || y &lt; 0 || y &gt;= BoardHeight)
 +             return false;
 +         if (shapeAt(x, y) != Tetrominoes.NoShape)
 +             return false;
 +     }
 +
 +     curPiece = newPiece;
 +     curX = newX;
 +     curY = newY;
 +     repaint();
 +     return true;
 + }
 +</code>
 +
 +
 +
 +
 +The **tryMove()** method tries to move the tetris piece. The method returns false, if it has reached the board boundaries or it is adjacent to the already fallen tetris pieces. 
 +
 +
 +
 +
 +<code java>
 + for (int i = BoardHeight - 1; i >= 0; --i) {
 +     boolean lineIsFull = true;
 +
 +     for (int j = 0; j &lt; BoardWidth; ++j) {
 +         if (shapeAt(j, i) == Tetrominoes.NoShape) {
 +             lineIsFull = false;
 +             break;
 +         }
 +     }
 +
 +     if (lineIsFull) {
 +         ++numFullLines;
 +         for (int k = i; k &lt; BoardHeight - 1; ++k) {
 +             for (int j = 0; j &lt; BoardWidth; ++j)
 +                  board[(k * BoardWidth) + j] = shapeAt(j, k + 1);
 +         }
 +     }
 + }
 +</code>
 +
 +
 +
 +
 +Inside the **removeFullLines()** method, we check if there is any full row among all rows in the **board**. If there is at least one full line, it is removed.  After finding a full line we increase the counter. We move all the lines above the full row one line down. This way we destroy the full line. Notice, that in our Tetris game, we use so called naive gravity. This means, that the squares may be left floating above empty gaps. 
 +
 +
 +
 +
 +
 +
 +
 +Every tetris piece has four squares. Each of the squares is drawn with the **drawSquare()** method. Tetris pieces have different colors. 
 +
 +
 +
 +
 +<code java>
 + g.setColor(color.brighter());
 + g.drawLine(x, y + squareHeight() - 1, x, y);
 + g.drawLine(x, y, x + squareWidth() - 1, y);
 +</code>
 +
 +
 +
 +
 +The left and top sides of a square are drawn with a brighter color. Similarly, the bottom and right sides are drawn with 
 +darker colors. This is to simulate a 3D edge. 
 +
 +
 +
 +
 +
 +
 +
 +
 +We control the game with a keyboard. The control mechanism is implemented with a **KeyAdapter**.
 +This is an inner class that overrides the **keyPressed()** method. 
 +
 +
 +
 +
 +<code java>
 + case KeyEvent.VK_RIGHT:
 +     tryMove(curPiece, curX + 1, curY);
 +     break;
 +</code>
 +
 +
 +
 +
 +If we pressed the left arrow key, we try to move the falling piece one square to the left. 
 +
 +
 +
 +
 +
 +
 +
 +{{ http://zetcode.com/tutorials/javaswingtutorial/images/tetris.png |Tetris}}
 +
 +
 +
 +
 +
 +
 +
 +
 +
  
docs/javaswing.txt · آخر تعديل: 2015/04/23 03:20 بواسطة 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki