Skip to content

5. رابط‌های کاربری گرافیکی

در اینجا هدف ما نشان دادن نحوه ساخت رابط‌های کاربری گرافیکی با JAVA است. ابتدا، به کلاس‌های پایه‌ای که امکان ساخت یک رابط کاربری گرافیکی را برای ما فراهم می‌کنند، نگاهی خواهیم انداخت. در ابتدا، از هیچ ابزار تولید خودکار استفاده نخواهیم کرد. سپس از JBuilder، یک ابزار توسعه از Borland/Inprise که توسعه برنامه‌های جاوا و به ویژه ساخت رابط‌های کاربری گرافیکی را تسهیل می‌کند، استفاده خواهیم کرد.

5.1. مبانی رابط‌های کاربری گرافیکی

5.1.1. یک پنجره ساده

کد زیر را در نظر بگیرید:


//کلاس‌های واردشده
import javax.swing.*;
import java.awt.*;
    
    //کلاس فرم
  public class form1 extends JFrame {
    
      // سازنده
      public form1() {
            // عنوان پنجره
            this.setTitle("Mon premier formulaire");
            //ابعاد پنجره
            this.setSize(new Dimension(300,100));
      }//سازنده
  
      // تابع آزمایشی
      public static void main(String[] args) {
            // فرم نمایش داده می‌شود
            new form1().setVisible(true);
      }
  }//کلاس

اجرای کد بالا پنجره زیر را نمایش می‌دهد:

Image

یک رابط کاربری گرافیکی معمولاً از کلاس پایه JFrame مشتق می‌شود:


  public class form1 extends JFrame {

کلاس پایه JFrame یک پنجرهٔ پایه را با دکمه‌های بستن و حداکثر/حداقل کردن، اندازهٔ قابل تنظیم و غیره تعریف می‌کند و رویدادهای این اشیاء گرافیکی را مدیریت می‌کند. در اینجا با تنظیم عنوان، عرض (۳۰۰ پیکسل) و ارتفاع (۱۰۰ پیکسل) آن، کلاس پایه را تخصصی می‌کنیم. این کار در سازندهٔ آن انجام می‌شود:


      // سازنده
      public form1() {
            // عنوان پنجره
            this.setTitle("Mon premier formulaire");
            //ابعاد پنجره
            this.setSize(new Dimension(300,100));
      }//سازنده

عنوان پنجره توسط متد setTitle و ابعاد آن توسط متد setSize تعیین می‌شود. این متد یک شیء Dimension(largeur,hauteur) را به‌عنوان پارامتر می‌پذیرد، که در آن largeur و hauteur به‌ترتیب عرض و ارتفاع پنجره را به پیکسل نشان می‌دهند.

روش main برنامه گرافیکی را به شرح زیر راه‌اندازی می‌کند:


            new form1().setVisible(true);

سپس یک فرم از نوع form1 ایجاد می‌شود (new form1()) و نمایش داده می‌شود (setVisible(true))، و پس از آن، برنامه به رویدادهای رخ‌داده روی فرم (کلیک‌ها، حرکات ماوس، ... و رویدادهایی را که فرم مدیریت می‌کند، فعال می‌کند. در این مورد، فرم ما هیچ رویدادی را به جز رویدادهایی که توسط کلاس پایه JFrame مدیریت می‌شوند (کلیک روی دکمه‌های بستن و حداکثر/حداقل کردن، تغییر اندازه پنجره، جابجایی پنجره و غیره) مدیریت نمی‌کند.

هنگام تست این برنامه با اجرای آن از یک پنجره DOS با استفاده از:

java form1

هنگام اجرای فایل form1.class، متوجه خواهید شد که وقتی پنجره‌ای که نمایش داده شده را می‌بندید، کنترل به پنجره DOS بازنمی‌گردد، گویی که برنامه به پایان نرسیده است. این در واقع درست است. برنامه به شرح زیر اجرا می‌شود:

  • در ابتدا، یک نخ اجرای اول برای اجرای متد main راه‌اندازی می‌شود
  • هنگامی که این متد فرم را ایجاد و نمایش می‌دهد، یک نخ دوم برای رسیدگی به رویدادهای خاص مربوط به فرم ایجاد می‌شود
  • پس از انجام این کار، و در مثال ما، نخ مربوط به متد main متوقف می‌شود و تنها نخ اجرای رابط کاربری (GUI) باقی می‌ماند.
  • وقتی پنجره بسته می‌شود، ناپدید می‌شود اما نخ (thread)ی را که در آن اجرا می‌شد متوقف نمی‌کند.
  • فعلاً، ما مجبوریم این نخ را با فشردن Ctrl-C در پنجره DOS که برنامه از آن اجرا شده است، متوقف کنیم.

بیایید وجود دو نخ (thread) مجزا را بررسی کنیم: یکی نخی که متد main در آن در حال اجراست و دیگری نخی که پنجره گرافیکی در آن در حال اجراست:


//کلاس‌های واردشده
import javax.swing.*;
import java.awt.*;
import java.io.*;

// کلاس فرم
 public class form1 extends JFrame {
    
// سازنده
 public form1() {
   // عنوان پنجره
   this.setTitle("Mon premier formulaire");
   //ابعاد پنجره
   this.setSize(new Dimension(300,100));
}//سازنده
  
// تابع آزمایشی
 public static void main(String[] args) {
   // ردیابی
   System.out.println("Début du thread main");
   // فرم نمایش داده می‌شود
   new form1().setVisible(true);
   // ردیابی
   System.out.println("Fin du thread main");  
}//اصلی
}//کلاس

اجرای کد نتایج زیر را تولید می‌کند:

Image

مشاهده می‌شود که تِرد main در حالی که پنجره هنوز نمایش داده می‌شود، متوقف شده است. بستن پنجره، تِردی را که در آن در حال اجرا بود متوقف نمی‌کند. برای متوقف کردن این تِرد، دوباره کلیدهای Ctrl-C را در پنجره DOS فشار دهید.

برای پایان این مثال، به پکیج‌های واردشده توجه کنید:

  • javax.swing برای کلاس JFrame
  • java.awt برای کلاس Dimension

5.1.2. پردازش یک رویداد

در مثال قبلی، ما باید خودمان بسته‌شدن پنجره را مدیریت می‌کردیم تا وقتی این اتفاق می‌افتد، برنامه خاتمه یابد – کاری که در حال حاضر انجام نمی‌شود. برای این کار، باید یک شیء ایجاد کنیم که به رویدادهای رخ‌داده روی پنجره «گوش فرا دهد» و رویداد «بسته‌شدن پنجره» را تشخیص دهد. این شیء «گوش‌دهنده» یا پردازشگر رویداد نامیده می‌شود. انواع مختلفی از پردازشگرها برای رویدادهای گوناگونی که ممکن است در اجزای یک رابط کاربری گرافیکی رخ دهند، وجود دارد. برای مؤلفه JFrame، گوش‌دهنده WindowListener نامیده می‌شود و یک رابط است که متدهای زیر را تعریف می‌کند (به مستندات جاوا مراجعه کنید)

خلاصه متدها
 
void
windowActivated(WindowEvent e)
          پنجره فعال می‌شود
 
خالی
پنجره بسته شد(WindowEvent e)
          پنجره بسته شد
 
خالی
windowClosing(WindowEvent e)
          کاربر یا برنامه درخواست بسته‌شدن پنجره را داد
 
void
پنجره غیرفعال شد(WindowEvent e)
          پنجره دیگر پنجره فعال نیست
 
void
windowDeiconified(WindowEvent e)
          پنجره از حالت کوچک‌شده به حالت عادی بازمی‌گردد
 
void
windowIconified(WindowEvent e)
          پنجره از وضعیت عادی به وضعیت کوچک‌شده تغییر می‌کند
 
void
windowOpened(WindowEvent e)
          پنجره برای اولین بار قابل مشاهده می‌شود
 

بنابراین هفت رویداد وجود دارد که می‌توان آن‌ها را مدیریت کرد. همهٔ رویدادپردازها یک شیء از نوع WindowEvent را به‌عنوان پارامتر دریافت می‌کنند که فعلاً آن را نادیده می‌گیریم. رویداد مورد نظر در اینجا بسته‌شدن پنجره است که باید توسط متد windowClosing مدیریت شود. برای مدیریت این رویداد، می‌توانیم یک شیء Windowlistener را با استفاده از یک کلاس ناشناس به صورت زیر ایجاد کنیم:


   //ایجاد یک رویدادپرداز
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//تعریف Win

پردازشگر رویداد ما که رابط WindowListener را پیاده‌سازی می‌کند، باید هر هفت متد این رابط را تعریف کند. از آنجا که ما تنها می‌خواهیم بسته‌شدن پنجره را مدیریت کنیم، تنها برای متد windowClosing کد تعریف می‌کنیم. وقتی رویدادهای دیگر رخ دهند، به ما اطلاع داده خواهد شد اما هیچ اقدامی انجام نخواهیم داد. وقتی به ما اطلاع داده شود که پنجره در حال بسته شدن است (windowClosing)، چه خواهیم کرد؟ برنامه را خاتمه خواهیم داد:


     public void windowClosing(WindowEvent e){System.exit(0);}

در اینجا یک شیء داریم که قادر به رسیدگی به رویدادهای پنجره به طور کلی است. چگونه آن را با یک پنجرهٔ خاص مرتبط کنیم؟ کلاس JFrame دارای متدی به نام addWindowListener(WindowListener win) است که امکان اختصاص یک شنونده رویداد «پنجره» به یک پنجرهٔ مشخص را فراهم می‌کند. بنابراین در اینجا، در سازندهٔ پنجره، خواهیم نوشت:


   //ایجاد یک رویدادپرداز
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//تعریف ویندوز
    // این دست‌پرداز رویدادها رویدادهای پنجرهٔ جاری را مدیریت خواهد کرد
   this.addWindowListener(win);

برنامه کامل به شرح زیر است:


//کلاس‌های واردشده
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// کلاس فرم
 public class form2 extends JFrame {
    
// سازنده
 public form2() {
   // عنوان پنجره
   this.setTitle("Mon premier formulaire");
   //ابعاد پنجره
   this.setSize(new Dimension(300,100));
   // ایجاد یک رویدادپرداز
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//تعریف وین
   // این دست‌پرداز رویداد، رویدادها را برای پنجرهٔ جاری مدیریت خواهد کرد
   this.addWindowListener(win);
}//سازنده
  
// تابع آزمایشی
 public static void main(String[] args) {
   // فرم نمایش داده می‌شود
   new form2().setVisible(true);
}//اصلی
}//کلاس

پکیج java.awt.event شامل رابط WindowListener است. هنگامی که این برنامه اجرا می‌شود و پنجره‌ای که ظاهر شده بسته می‌شود، پنجره فرمان که برنامه از آن اجرا شده است، پیامی را نمایش می‌دهد که نشان می‌دهد برنامه به پایان رسیده است، که این امر قبلاً رخ نمی‌داد.

در برنامه ما، ایجاد ابجکتی که مسئول رسیدگی به رویدادهای پنجره است، تا حدی دست‌وپاگیر است، زیرا مجبوریم متدهایی را حتی برای رویدادهایی که نمی‌خواهیم رسیدگی کنیم، تعریف کنیم. در این مورد، به جای استفاده از رابط WindowListener، می‌توانیم از کلاس WindowAdapter استفاده کنیم. این کلاس رابط WindowListener را با هفت متد خالی پیاده‌سازی می‌کند. با ارث‌بری از کلاس WindowAdapter و بازتعریف تنها متدهایی که به آن‌ها علاقه‌مند هستیم، به همان نتیجهٔ رابط WindowListener می‌رسیم، اما بدون نیاز به تعریف متدهایی که به آن‌ها علاقه‌ای نداریم. توالی

  • تعریف رویدادپرداز
  • وابسته‌سازی هندلر به پنجره

می‌تواند در مثال ما به شرح زیر انجام شود:


   //ایجاد یک رویدادپرداز
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//تعریف Win
   // این دست‌پرداز رویدادها رویدادهای پنجرهٔ جاری را مدیریت خواهد کرد
   this.addWindowListener(win);

در اینجا ما از یک کلاس ناشناس استفاده می‌کنیم که از کلاس WindowAdapter ارث می‌برد و متد windowClosing آن را مجدداً تعریف می‌کند. برنامه سپس به این صورت درمی‌آید:


//کلاس‌های واردشده
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

//کلاس فرم
 public class form2 extends JFrame {
    
// سازنده
 public form2() {
   // عنوان پنجره
   this.setTitle("Mon premier formulaire");
   //ابعاد پنجره
   this.setSize(new Dimension(300,100));
   // ایجاد یک رویدادپرداز
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//تعریف Win
   // این دست‌پرداز رویدادها رویدادهای پنجرهٔ جاری را مدیریت خواهد کرد
   this.addWindowListener(win); }//سازنده
  
// تابع آزمایشی
 public static void main(String[] args) {
   // فرم نمایش داده می‌شود
   new form2().setVisible(true);
}//اصلی
}//کلاس

این برنامه همان نتایج برنامه قبلی را تولید می‌کند اما نوشتن آن ساده‌تر است.

5.1.3. یک فرم با یک دکمه

حال بیایید یک دکمه به پنجره خود اضافه کنیم:


//کلاس‌های واردشده
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

//کلاس فرم
 public class form3 extends JFrame {
 
     // یک دکمه
  JButton btnTest=null;
  Container conteneur=null;
  
  // سازنده
  public form3() {
     // عنوان پنجره
    this.setTitle("Formulaire avec bouton");
     //ابعاد پنجره
    this.setSize(new Dimension(300,100));
    // ایجاد یک رویدادگیر
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//تعریف Win
     // این دست‌پرداز رویداد برای پنجرهٔ جاری رویدادها را مدیریت خواهد کرد
    this.addWindowListener(win);
     // بازیابی کانتینر پنجره
    conteneur=this.getContentPane();
     // ما یک مدیر چیدمان مؤلفه را برای این کانتینر انتخاب می‌کنیم
    conteneur.setLayout(new FlowLayout());
    // ما یک دکمه ایجاد می‌کنیم
    btnTest=new JButton();
    // برچسب آن را تنظیم کنید
    btnTest.setText("Test");
    // افزودن دکمه به کانتینر
    conteneur.add(btnTest);
  }//سازنده
  
  // توابع آزمایشی
 public static void main(String[] args) {
    // نمایش فرم
   new form3().setVisible(true);
}//اصلی
}//کلاس

یک پنجره JFrame دارای یک کانتینر است که می‌توان اجزای گرافیکی (دکمه‌ها، چک‌باکس‌ها، لیست‌های کشویی و غیره) را در آن قرار داد. این کانتینر از طریق متد getContentPane کلاس JFrame قابل دسترسی است:


  Container conteneur=null;
..........
     // بازیابی کانتینر پنجره
    conteneur=this.getContentPane();

هر مؤلفه با استفاده از متد add از کلاس Container در کانتینر قرار می‌گیرد. بنابراین، برای قرار دادن مؤلفه C در شیء قبلی conteneur، خواهیم نوشت:

conteneur.add(C)

این کامپوننت در کجای کانتینر قرار می‌گیرد؟ مدیرهای چیدمان کامپوننت مختلفی با نام XXXLayout وجود دارند، که برای مثال XXX معادل Border، Flow، ... هر مدیر چیدمان ویژگی‌های خاص خود را دارد. برای مثال، مدیر چیدمان FlowLayout اجزا را در ردیف‌هایی از بالای فرم مرتب می‌کند. پس از پر شدن یک ردیف، اجزا در ردیف بعدی قرار می‌گیرند. برای مرتبط کردن یک مدیر چیدمان با یک پنجره JFrame، از متد setLayout از کلاس JFrame به شکل زیر استفاده کنید:

    setLayout(objet XXXLayout);

بنابراین، در مثال ما، برای مرتبط کردن یک دستگیره از نوع FlowLayout با پنجره، نوشتیم:


     // یک مدیر چیدمان مؤلفه برای این کانتینر انتخاب کنید
    conteneur.setLayout(new FlowLayout());

امکان حذف هندلر چیدمان و نوشتن به شکل زیر وجود دارد:

    setLayout(null);

در این حالت، شما باید مختصات دقیق کامپوننت را در داخل کانتینر به صورت (x, y, width, height) مشخص کنید، که در آن (x, y) مختصات گوشه بالا سمت چپ کامپوننت در داخل کانتینر هستند. این روشی است که از این پس بیشترین استفاده را از آن خواهیم کرد.

اکنون می‌دانیم که اجزا چگونه در داخل کانتینر (add) و در کجا (setLayout) قرار می‌گیرند. تنها کاری که باقی مانده، شناسایی ... است.

کامپوننت‌هایی که می‌توان آن‌ها را در یک کانتینر قرار داد. در اینجا، ما یک دکمه را که توسط کلاس javax.swing.JButton مدل‌سازی شده است، قرار می‌دهیم:



  JButton btnTest=null;
..........
     // ایجاد یک دکمه
    btnTest=new JButton();
    // برچسب آن را تنظیم کنید
    btnTest.setText("Test");
    // افزودن دکمه به کانتینر
    conteneur.add(btnTest);

هنگامی که این برنامه را اجرا می‌کنید، پنجره زیر ظاهر می‌شود:

Image

اگر اندازه فرم بالا را تغییر دهید، مدیر چیدمان کانتینر به‌طور خودکار برای جابجایی مجدد اجزا فراخوانی می‌شود:

Image

این اصلی‌ترین مزیت مدیران چیدمان است: آن‌ها چیدمان یکنواخت اجزا را هنگام تغییر اندازهٔ کانتینر حفظ می‌کنند. بیایید از مدیر چیدمان null استفاده کنیم تا تفاوت را ببینیم. دکمه اکنون با دستورالعمل‌های زیر درون کانتینر قرار می‌گیرد:


// یک مدیر چیدمان کامپوننت برای این کانتینر انتخاب کنید
conteneur.setLayout(null);
    // ایجاد یک دکمه
btnTest=new JButton();
    // برچسب آن را تنظیم کنید
btnTest.setText("Test");
    // موقعیت و ابعاد آن را تنظیم کنید
btnTest.setBounds(10,20,100,20);
     // افزودن دکمه به کانتینر
conteneur.add(btnTest);

در اینجا، ما صراحتاً دکمه را در نقطه (10,20) روی فرم قرار می‌دهیم و ابعاد آن را به عرض 100 پیکسل و ارتفاع 20 پیکسل تنظیم می‌کنیم. پنجره جدید به شکل زیر است:

Image

اگر پنجره تغییر اندازه دهد، دکمه در همان موقعیت باقی می‌ماند.

Image

اگر روی دکمه Test کلیک کنید، هیچ اتفاقی نمی‌افتد. این به این دلیل است که ما هنوز یک رویدادپرداز به دکمه اختصاص نداده‌ایم. برای پی بردن به اینکه چه نوع رویدادپردازهایی برای یک کامپوننت مشخص در دسترس هستند، می‌توانید در تعریف کلاس به دنبال متدهایی مانند addXXXListener بگردید که به شما امکان می‌دهند یک رویدادپرداز را با آن کامپوننت مرتبط کنید. کلاس javax.swing.JButton از کلاس javax.swing.AbstractButton ارث می‌برد که شامل متدهای زیر است:

خلاصه متدها
 
void
addActionListener(ActionListener l)
 
void
addChangeListener(ChangeListener l)
 
void
addItemListener(ItemListener l)
 

در اینجا باید به مستندات مراجعه کنید تا بفهمید کدام رویدادپرداز، کلیک دکمه را مدیریت می‌کند. این رابط ActionListener است. این رابط تنها یک متد را تعریف می‌کند:

خلاصه متدها
 
void
actionPerformed(ActionEvent e)
 

این متد یک پارامتر به نام ActionEvent می‌گیرد که فعلاً آن را نادیده می‌گیریم. برای رسیدگی به کلیک‌های دکمه btntest در برنامه خود، ابتدا یک رویدادپرداز به آن اختصاص می‌دهیم:


        btnTest.addActionListener(new ActionListener()
         {
                public void actionPerformed(ActionEvent evt){
                  btnTest_clic(evt);
              }
            }//کلاس ناشناس
    );//دست‌پرداز رویداد

در اینجا، متد actionPerformed به متد btnTest_clic اشاره دارد که به شرح زیر تعریف می‌کنیم:


public void btnTest_clic(ActionEvent evt){
  // لاگ‌گیری کنسول
System.out.println("clic sur bouton");
}//btnTest_click

هر بار که کاربر دکمه Test را کلیک می‌کند، پیامی به کنسول نوشته می‌شود. این موضوع در اجرای زیر نشان داده شده است:

Image

برنامه کامل به شرح زیر است:


//کلاس‌های واردشده
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

//کلاس فرم
 public class form4 extends JFrame {
 
     //یک دکمه
  JButton btnTest=null;
  Container conteneur=null;
  
  // سازنده
  public form4() {
     // عنوان پنجره
    this.setTitle("Formulaire avec bouton");
     //ابعاد پنجره
    this.setSize(new Dimension(300,100));
    // ایجاد یک رویدادپرداز
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//تعریف ویندوز
     // این دست‌پرداز رویداد برای پنجرهٔ جاری رویدادها را مدیریت خواهد کرد
    this.addWindowListener(win);
     // ما کانتینر پنجره را بازیابی می‌کنیم
    conteneur=this.getContentPane();
     // ما یک مدیر چیدمان برای اجزا در این کانتینر انتخاب می‌کنیم
    conteneur.setLayout(null);
    // ما یک دکمه ایجاد می‌کنیم
    btnTest=new JButton();
    // برچسب آن را تنظیم کنید
    btnTest.setText("Test");
    //موقعیت و ابعاد آن را تنظیم کنید
    btnTest.setBounds(10,20,100,20);
     // یک رویدادپرداز به آن اختصاص دهید
    btnTest.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt){
              btnTest_clic(evt);
          }
        }//کلاس ناشناس
    );//دست‌پرداز رویداد
     // افزودن دکمه به کانتینر
    conteneur.add(btnTest);
  }//سازنده

    public void btnTest_clic(ActionEvent evt){
       //ردیابی کنسول
    System.out.println("clic sur bouton");
  }//btnTest_click
    
  // تابع آزمایشی
 public static void main(String[] args) {
    // فرم نمایش داده می‌شود
   new form4().setVisible(true);
}//اصلی
}//کلاس

5.1.4. پردازشگرهای رویداد

کامپوننت‌های اصلی Swing که بررسی خواهیم کرد عبارتند از پنجره‌ها (JFrame)، دکمه‌ها (JButton)، چک‌باکس‌ها (JCheckBox)، دکمه‌های رادیویی (JButtonRadio)، لیست‌های کشویی (JComboBox)، لیست‌ها (JList)، اسلایدرها (JScrollBar)، برچسب‌ها (JLabel)، کادرهای متنی تک‌خطی (JTextField) یا کادرهای متنی چندخطی (JTextArea)، منوها (JMenuBar)، موارد منو (JMenuItem).

جدول‌های زیر برخی از دستگیرکننده‌های رویداد و رویدادهایی را که به آن‌ها مرتبط هستند، فهرست می‌کنند.

پردازشگر
کامپوننت(ها)
روش ثبت‌نام
رویداد
ActionListener
JButton, JCheckbox, JButtonRadio, JMenuItem
public void addActionListener(ActionListener)
روی دکمه، چک‌باکس، دکمهٔ رادیویی یا آیتم منو کلیک کنید
 
JTextField
ItemListener
JComboBox, JList
public void addItemListener(ItemListener)
مورد انتخابی تغییر کرده است
InputMethodListener
JTextField, JTextArea
public void addMethodInputListener(InputMethodListener)
متن در فیلد ورودی تغییر کرده است یا مکان‌نما جابجا شده است
CaretListener
JTextField, JTextArea
public void addcaretListener(CaretListener)
موقعیت نشانگر ورودی تغییر کرده است
AdjustmentListener
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
مقدار درایو تغییر کرده است
MouseMotionListener
 
public void addMouseMotionListener(MouseMotionListener)
موشواره جابجا شده است
WindowListener
JFrame
public void addWindowlistener(WindowListener)
رویداد پنجره
MouseListener
 
public void addMouselistener(MouseListener)
رویدادهای ماوس (کلیک، ورود/خروج از ناحیهٔ یک مؤلفه، فشرده شدن دکمه، رها کردن)
FocusListener
 
public void addFocuslistener(FocusListener)
رویداد فوکوس (به دست آمدن، از دست رفتن)
KeyListener
 
public void addKeylistener(KeyListener)
رویداد صفحه‌کلید (کلید تایپ‌شده، فشرده، رهاشده)
کامپوننت
روش ثبت رسیدگی‌کننده‌های رویداد
JButton
public void addActionListener(ActionListener)
JCheckbox
public void addItemListener(ItemListener)
JCheckboxMenuItem
public void addItemListener(ItemListener)
JComboBox
public void addItemListener(ItemListener)
public void addActionListener(ActionListener)
Container
public void addContainerListener(ContainerListener)
JComponent
public void addComponentListener(ComponentListener)
public void addFocusListener(FocusListener)
public void addKeyListener(KeyListener)
public void addMouseListener(MouseListener)
public void addMouseMotionListener(MouseMotionListener)
JFrame
public void addWindowlistener(WindowListener)
JList
public void addItemListener(ItemListener)
JMenuItem
public void addActionListener(ActionListener)
JPanel
به عنوان کانتینر
JScrollPane
به‌عنوان کانتینر
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
JTextComponent
public void addInputMethodListener(InputMethodListener)
public void addCaretListener(CaretListener)
JTextArea
comme JTextComponent
JTextField
مانند JTextComponent
public void addActionListener(ActionListener)

تمام کامپوننت‌ها، به جز آن‌هایی که از نوع TextXXX هستند، از کلاس JComponent مشتق شده‌اند و بنابراین متدهای مرتبط با آن کلاس را نیز در اختیار دارند.

5.1.5. متدهای دست‌پرداز رویداد

جدول زیر متدهایی را که پردازشگرهای رویداد مختلف باید پیاده‌سازی کنند، فهرست می‌کند.

رابط
متدها
ActionListener
public void actionPerformed(ActionEvent)
AdjustmentListener
public void adjustmentValueChanged(AdjustmentEvent)
ComponentListener
public void componentHidden(ComponentEvent)
public void componentMoved(ComponentEvent)
public void componentResized(ComponentEvent)
public void componentShown(ComponentEvent)
ContainerListener
public void componentAdded(ContainerEvent)
public void componentRemoved(ContainerEvent)
FocusListener
public void focusGained(FocusEvent)
public void focusLost(FocusEvent)
ItemListener
public void itemStateChanged(ItemEvent)
KeyListener
public void keyPressed(KeyEvent)
public void keyReleased(KeyEvent)
public void keyTyped(KeyEvent)
MouseListener
public void mouseClicked(MouseEvent)
public void mouseEntered(MouseEvent)
public void mouseExited(MouseEvent)
public void mousePressed(MouseEvent)
public void mouseReleased(MouseEvent)
MouseMotionListener
public void mouseDragged(MouseEvent)
public void mouseMoved(MouseEvent)
TextListener
public void textValueChanged(TextEvent)
InputmethodListener
public void InputMethodTextChanged(InputMethodEvent)
public void caretPositionChanged(InputMethodEvent)
CaretLisetner
public void caretUpdate(CaretEvent)
WindowListener
public void windowActivated(WindowEvent)
public void windowClosed(WindowEvent)
public void windowClosing(WindowEvent)
public void windowDeactivated(WindowEvent)
public void windowDeiconified(WindowEvent)
public void windowIconified(WindowEvent)
public void windowOpened(WindowEvent)

5.1.6. کلاس‌های آداپتور

همان‌طور که در رابط WindowListener دیدیم، کلاس‌هایی با نام XXXAdapter وجود دارند که رابط‌های XXXListener را با متدهای خالی پیاده‌سازی می‌کنند. بنابراین یک رویدادپرداز مشتق‌شده از کلاس XXXAdapter می‌تواند تنها برخی از متدهای رابط XXXListener را پیاده‌سازی کند – به‌طور مشخص، آن‌هایی که توسط برنامه کاربردی مورد نیاز هستند.

فرض کنید می‌خواهیم کلیک‌های ماوس روی یک کامپوننت Frame به نام f1 را مدیریت کنیم. می‌توانیم یک رویدادپرداز را به صورت زیر به آن مرتبط کنیم:

    f1.addMouseListener(new gestionnaireSouris());

و بنویسیم:


    public class gestionnaireSouris implements MouseListener{
         // نوشتن ۵ متد رابط MouseListener
        //mouseClicked, ..., mouseReleased)
    }//پایان کلاس

با این حال، از آنجایی که ما فقط می‌خواهیم کلیک‌های ماوس را مدیریت کنیم، بهتر است بنویسیم:


public class gestionnaireSouris extends MouseAdapter{
        // ما فقط یک متد می‌نویسیم، متدی که کلیک‌های ماوس را مدیریت می‌کند
        public void mouseClicked(MouseEvent evt){

        }
}//پایان کلاس

جدول زیر کلاس‌های آداپتور برای دستگیرکننده‌های رویداد مختلف را فهرست می‌کند:

پردازشگر رویداد
آداپتور
ComponentListener
ComponentAdapter
ContainerListener
ContainerAdapter
FocusListener
FocusAdapter
KeyListener
KeyAdapter
MouseListener
MouseAdapter
MouseMotionListener
MouseMotionAdapter
WindowListener
WindowAdapter

5.1.7. نتیجه‌گیری

ما به تازگی مفاهیم پایه‌ای ایجاد رابط‌های کاربری گرافیکی در جاوا را تشریح کردیم:

  • ایجاد یک پنجره
  • ایجاد کامپوننت‌ها
  • ارتباط دادن کامپوننت‌ها با پنجره با استفاده از یک مدیر چیدمان
  • ارتباط‌دادن رسیدگی‌کننده‌های رویداد با کامپوننت‌ها

اکنون، به جای ساخت دستی رابط‌های کاربری گرافیکی همان‌طور که به تازگی انجام دادیم، از JBuilder، یک ابزار توسعه جاوا از Borland/Inprise (نسخه 4)، و supérieure.Nous استفاده خواهیم کرد؛ ما از کامپوننت‌های کتابخانه java.swing که در حال حاضر توسط Sun، خالق جاوا، توصیه می‌شود، استفاده خواهیم کرد.

5.2. ساخت یک رابط کاربری گرافیکی با JBuilder

5.2.1. اولین پروژه JBuilder ما

برای آشنایی با JBuilder، بیایید یک برنامه بسیار ساده بسازیم: یک پنجره خالی.

  1. JBuilder را راه‌اندازی کنید و File/New Project را انتخاب کنید. سپس صفحهٔ اول جادوگر ظاهر می‌شود:

Image

  1. میدان‌های زیر را پر کنید:
نام پروژه
شروع
این کار یک فایل پروژه به نام début.jpr در پوشه‌ای که در فیلد «نام دایرکتوری پروژه» مشخص شده است، ایجاد می‌کند.
مسیر ریشه
پوشه‌ای را که پوشه پروژه شما قرار است در زیر آن ایجاد شود، مشخص کنید.
نام پوشه پروژه
نام پوشه‌ای را که تمام فایل‌های پروژه در آن قرار خواهند گرفت، مشخص کنید. این پوشه در داخل دایرکتوری مشخص‌شده در فیلد «مسیر ریشه» ایجاد خواهد شد.

فایل‌های منبع (.java، .html و غیره)، فایل‌های مقصد (.class و غیره) و فایل‌های پشتیبان می‌توانند در دایرکتوری‌های مجزا قرار گیرند. اگر این فیلدها را خالی بگذارید، در همان دایرکتوری پروژه قرار خواهند گرفت.

[suivant] را وارد کنید

  1. یک صفحه تأیید، انتخاب‌های انجام‌شده در مرحله قبلی را تأیید می‌کند

Image

[suivant] را وارد کنید

  1. یک صفحه جدید از شما می‌خواهد جزئیات پروژه خود را مشخص کنید:

Image

[terminer] را انتخاب کنید

  1. مطمئن شوید که گزینه Voir/projet تیک خورده است. باید ساختار پروژه خود را در پنجره سمت چپ مشاهده کنید.

Image

  1. حالا بیایید یک رابط کاربری گرافیکی برای این پروژه بسازیم. گزینه Fichier/Nouveau/Application را انتخاب کنید:

Image

در فیلد classe، نام کلاسی را که باید ایجاد شود وارد کنید. در اینجا، ما از همان نام پروژه استفاده کرده‌ایم.

[suivant] را انتخاب کنید

  1. صفحه زیرین ظاهر می‌شود:

Image

کلاس
interfaceDébut
این نام کلاس مربوط به پنجره‌ای است که باید ایجاد شود
عنوان
این متنی است که در نوار عنوان پنجره نمایش داده خواهد شد

توجه داشته باشید که در بالا مشخص کرده‌ایم که پنجره باید هنگام راه‌اندازی برنامه در مرکز صفحه نمایش قرار گیرد.

[Terminer] را وارد کنید

  1. اینجاست که JBuilder به کار می‌آید.
  • این فایل‌های منبع .java را برای دو کلاسی که نام‌گذاری کرده‌ایم تولید می‌کند: کلاس برنامه و کلاس رابط کاربری گرافیکی. این دو فایل در ساختار پروژه در پنجره سمت چپ ظاهر می‌شوند.

Image

  • برای دسترسی به کد تولید شده برای این دو کلاس، کافی است روی فایل .java مربوطه دوبار کلیک کنید. بعداً به سراغ کد تولید شده باز خواهیم گشت.
  • اطمینان حاصل کنید که گزینه Voir/Structure تیک خورده باشد. این به شما امکان می‌دهد ساختار کلاس انتخاب‌شده فعلی را مشاهده کنید (روی فایل .java دوبار کلیک کنید). در اینجا، به‌عنوان مثال، ساختار کلاس début آمده است:

Image

در اینجا می‌توانید ببینید:

  • کتابخانه‌های واردشده (imports)

  • اینکه یک سازنده با نام début() وجود دارد

  • اینکه یک متد استاتیک main() وجود دارد

  • که یک ویژگی به نام packFrame وجود دارد

دسترسی به ساختار یک کلاس چه فایده‌ای دارد؟

  • این به شما نمایی کلی از کلاس می‌دهد. این زمانی مفید است که کلاس شما پیچیده باشد.

  • می‌توانید با کلیک روی آن در پنجره ساختار کلاس، به کد یک متد دسترسی پیدا کنید. باز هم، این زمانی مفید است که کلاس شما صدها خط کد داشته باشد. لازم نیست برای پیدا کردن کدی که به دنبال آن هستید، همه خطوط را پیمایش کنید.

کدی که توسط JBuilder تولید می‌شود، از قبل قابل استفاده است. Run/Run Project یا F9 را انتخاب کنید تا پنجره‌ای را که به دنبال آن هستید ببینید:

Image

علاوه بر این، وقتی روی دکمه بستن پنجره کلیک می‌کنید، به درستی بسته می‌شود. ما به تازگی اولین رابط کاربری گرافیکی خود را ساخته‌ایم. می‌توانیم پروژه خود را با استفاده از گزینه File/Close Projects ذخیره کنیم:

Image

با فشردن Tous، تمام پروژه‌های نمایش داده شده در پنجره بالا تیک خورده خواهند شد. OK آنها را می‌بندد. اگر به اندازه کافی کنجکاو باشیم که با استفاده از ویندوز اکسپلورر به پوشه پروژه خود (همان پوشه‌ای که در ابتدای راه‌اندازی پروژه به ویزارد مشخص شده است) برویم، فایل‌های زیر را در آنجا پیدا خواهیم کرد:

Image

در مثال ما، مشخص کرده بودیم که تمام فایل‌ها (منبع .java، مقصد .class، پشتیبان .jpr~) باید در همان پوشه پروژه .jpr باشند.

5.2.2. فایل‌های تولیدشده توسط JBuilder برای یک رابط کاربری گرافیکی

حال بیایید نگاهی به فایل‌های منبع .java تولیدشده توسط JBuilder بیندازیم. مهم است که بتوانیم آنچه تولید شده را بخوانیم، زیرا اغلب لازم است به این فایل‌های تولیدشده کد اضافه کنیم. بیایید با باز کردن پروژهٔ خود شروع کنیم: File/Open Project و پروژهٔ début.jpr را انتخاب کنید. پروژه‌ای را که قبلاً ساختیم می‌یابیم.

5.2.2.1. کلاس اصلی

بیایید با دوبار کلیک روی نام کلاس début.java در پنجره‌ای که فهرست فایل‌های پروژه را نمایش می‌دهد، آن را بررسی کنیم. کد زیر را داریم:

import javax.swing.UIManager;
import java.awt.*;

public class début {
  boolean packFrame = false;

   /**برنامه را بسازید*/
  public début() {
    interfaceDébut frame = new interfaceDébut();

     //اعتبارسنجی فریم‌ها با اندازه‌های از پیش تعریف‌شده
     //تغییر اندازه فریم‌ها با اطلاعات اندازه ترجیحی – مثلاً بر اساس چیدمان آن‌ها
    if (packFrame) {
      frame.pack();
    }
    else {
      frame.validate();
    }
    //مرکز پنجره
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = frame.getSize();
    if (frameSize.height > screenSize.height) {
      frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
      frameSize.width = screenSize.width;
    }
    frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
    frame.setVisible(true);
  }
   /**روش اصلی*/
  public static void main(String[] args) {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    new début();
  }
}

بیایید روی کد تولید شده نظر بدهیم:

  1. تابع main ظاهر پنجره (setLookAndFeel) را تنظیم می‌کند و یک نمونه از کلاس début ایجاد می‌کند.
  2. سازنده début() سپس اجرا می‌شود. این سازنده یک نمونه frame از کلاس پنجره ایجاد می‌کند (new interfaceDébut()). این نمونه ساخته می‌شود اما نمایش داده نمی‌شود.
  3. سپس پنجره بر اساس اطلاعات موجود برای هر یک از اجزای آن (frame.validate) تغییر اندازه می‌دهد. سپس با نمایش داده شدن و پاسخ به ورودی کاربر، وجود مستقل خود را آغاز می‌کند.
  4. پنجره در مرکز صفحه نمایش قرار می‌گیرد زیرا این مورد هنگام پیکربندی پنجره با استفاده از ویزارد مشخص شده است.

بیایید ببینیم اگر کد début.java را به حداقل‌های لازم کاهش دهیم، چه اتفاقی می‌افتد، همانطور که در ابتدای این فصل انجام دادیم. بیایید یک کلاس جدید ایجاد کنیم. File/New Class را انتخاب کنید:

Image

کلاس جدید را début2 نامگذاری کنید و نام [Terminer] را تغییر دهید. یک فایل جدید در پروژه ظاهر می‌شود:

Image

فایل début2.java به ساده‌ترین شکل خود کاهش یافته است:

public class début2 {
}

بیایید کلاس را به صورت زیر تکمیل کنیم:

public class début2 {
   // تابع اصلی
  public static void main(String args[]){
    //پنجره را ایجاد می‌کند
    new interfaceDébut().show();    // یا interfaceDébut.setVisible(true);
  }//main
}//class start2

تابع main یک نمونه از پنجره interfaceDébut ایجاد می‌کند و آن را نمایش می‌دهد (show). قبل از اجرای پروژهٔ خود، باید توجه داشته باشیم که کلاسی که شامل تابع main است که باید اجرا شود، اکنون کلاس début2 است. روی پروژه début.jpr کلیک راست کرده و گزینه propriétés را انتخاب کنید، سپس برگه Exécution:

21

Image

در اینجا نشان داده شده است که کلاس اصلی début (1) است. برای انتخاب یک کلاس اصلی متفاوت، دکمه (2) را فشار دهید:

Image

début2 را انتخاب کرده و آن را روی [OK] تنظیم کنید.

Image

برای تأیید این انتخاب، [OK] را وارد کنید، سپس پروژه را از طریق Run/Run Project یا F9 اجرا کنید. شما همان پنجره‌ای را که با کلاس début مشاهده کردید خواهید دید، با این تفاوت که این پنجره مرکزیت ندارد، زیرا این مورد در اینجا مشخص نشده است. از این پس، دیگر کلاس اصلی تولید شده توسط JBuilder را نمایش نخواهیم داد، زیرا همیشه یک کار انجام می‌دهد: ایجاد یک پنجره. اکنون بر خود کلاس پنجره تمرکز خواهیم کرد.

5.2.2.2. کلاس پنجره

اکنون بیایید نگاهی به کدی که برای کلاس interfaceDébut تولید شده است، بیندازیم:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceDébut extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

  /**ساخت فریم*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**ابتدایی‌سازی مؤلفه*/
  private void jbInit() throws Exception  {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Ma première interface graphique avec Jbuilder");
  }
   /**جایگزین شد، تا بتوانیم هنگام بسته‌شدن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
}

5.2.2.2.1. کتابخانه‌های وارداتی
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

اینها کتابخانه‌های java.awt، java.awt.event و javax.swing هستند. دو مورد اول تنها کتابخانه‌های موجود برای ساخت رابط‌های کاربری گرافیکی در نسخه‌های اولیهٔ جاوا بودند. کتابخانهٔ javax.swing جدیدتر است. در اینجا برای نوع پنجرهٔ JFrame که در اینجا استفاده می‌شود، ضروری است.

5.2.2.2.2. ویژگی‌ها
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

JPanel یک نوع کانتینر است که می‌توان کامپوننت‌ها را در آن قرار داد. BorderLayout یکی از انواع مدیر چیدمان موجود برای قرار دادن کامپوننت‌ها در داخل کانتینر است. در تمام مثال‌های ما، از مدیر چیدمان استفاده نخواهیم کرد و اجزا را خودمان در یک مکان مشخص درون کانتینر قرار خواهیم داد. برای این کار، از مدیر چیدمان null استفاده خواهیم کرد.

5.2.2.2.3. سازنده پنجره
   /**ایجاد فریم*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**ابتدایی‌سازی مؤلفه*/
  private void jbInit() throws Exception  {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Ma première interface graphique avec Jbuilder");
  }
  1. سازنده با بیان اینکه رویدادهای پنجره (enableEvents) را مدیریت خواهد کرد شروع می‌شود، سپس متد jbInit را فراخوانی می‌کند.
  2. کانتینر (JPanel) برای پنجره (JFrame) بازیابی می‌شود (getContentPane)
  3. مدیر چیدمان تنظیم می‌شود (setLayout)
  4. اندازه پنجره تنظیم شده است (setSize)
  5. عنوان پنجره تنظیم شده است (setTitle)

5.2.2.2.4. پردازشگر رویداد
   /**جایگزین شد، تا بتوانیم هنگام بستن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }

توسعه‌دهنده اشاره کرده بود که این کلاس رویدادهای پنجره را مدیریت خواهد کرد. متد processWindowEvent این وظیفه را انجام می‌دهد. این متد با ارسال رویداد دریافت‌شده WindowEvent به کلاس والد خود (JFrame) آغاز می‌شود؛ اگر این رویداد همان رویداد WINDOW_CLOSING باشد که با کلیک روی دکمه بستن پنجره ایجاد می‌شود، برنامه خاتمه می‌یابد.

5.2.2.2.5. نتیجه‌گیری

کد کلاس پنجره با آنچه در مثال ابتدای فصل نشان داده شده متفاوت است. اگر ما از یک تولیدکننده کد جاوا به غیر از JBuilder استفاده کنیم، بدون شک با کدی کاملاً متفاوت روبرو خواهیم شد. در عمل، ما کد تولیدشده توسط JBuilder را برای ساخت پنجره می‌پذیریم تا بتوانیم تمام تمرکز خود را بر نوشتن رویدادپردازها برای رابط کاربری گرافیکی معطوف کنیم.

5.2.3. طراحی یک رابط کاربری گرافیکی

5.2.3.1. یک مثال

در مثال قبلی، ما هیچ کامپوننتی را در پنجره قرار ندادیم. اکنون بیایید یک پنجره با یک دکمه، یک برچسب و یک فیلد ورودی بسازیم:

Image

میدان‌ها به شرح زیر هستند:

خیر.
name
نوع
نقش
1
lblSaisie
JLabel
یک توضیح
2
txtSaisie
JTextField
یک فیلد ورودی
3
cmdAfficher
JButton
برای نمایش محتویات فیلد ورودی در یک کادر محاوره‌ای txtSaisie

طبق همان رویه‌ای که برای پروژه قبلی انجام شد، پروژه interface2.jpr را ایجاد کنید، اما فعلاً هیچ کامپوننتی به پنجره اضافه نکنید.

Image

در پنجره بالا، کلاس interface2.java را از پنجره انتخاب کنید. در سمت راست این پنجره یک پوشه زبانه دار وجود دارد:

Image

زبانه‌ی Source دسترسی به کد منبع کلاس interface2.java را فراهم می‌کند. زبانه‌ی Conception به شما امکان می‌دهد پنجره‌ی را به‌صورت بصری بسازید. این زبانه‌ی را انتخاب کنید. اکنون کانتینر پنجره‌ی را مشاهده خواهید کرد که قرار است اجزایی را که قصد دارید در آن قرار دهید، در خود جای دهد. در حال حاضر خالی است. پنجره‌ی سمت چپ ساختار کلاس را نشان می‌دهد:

Image

این
نماینده پنجره است
contentPane
ظرفی که اجزا در آن قرار می‌گیرند، و همچنین چیدمان این اجزا در داخل ظرف (BorderLayout به‌صورت پیش‌فرض)
borderLayout1
یک نمونه از مدیر چیدمان

شیء this را انتخاب کنید. پنجرهٔ ویژگی‌های آن سپس در سمت راست ظاهر می‌شود:

Image

برخی از این ویژگی‌ها قابل توجه هستند:

پس‌زمینه
برای تنظیم رنگ پس‌زمینه پنجره
foreground
برای تنظیم رنگ گرافیک‌ها در پنجره
JMenuBar
برای مرتبط کردن یک منو با پنجره
عنوان
برای دادن عنوان به پنجره
قابل تغییر اندازه
برای تنظیم نوع پنجره
فونت
برای تنظیم قلم متن نمایش‌داده‌شده در پنجره

در حالی که شیء this هنوز انتخاب شده است، می‌توانید با کشیدن نقاط لنگر‌دار اطراف کانتینر، اندازهٔ آن را در صفحه نمایش تغییر دهید:

Image

اکنون آماده هستیم تا کامپوننت‌ها را در کانتینر بالا قرار دهیم. قبل از انجام این کار، مدیر چیدمان را تغییر می‌دهیم. در پنجره ساختار، شیء contentPane را انتخاب کنید:

Image

سپس، در پنجرهٔ ویژگی‌های این شیء، ویژگی layout را انتخاب کرده و مقدار null را از میان گزینه‌های موجود برگزینید:

Image

عدم وجود مدیر چیدمان به ما اجازه می‌دهد تا اجزا را آزادانه در داخل کانتینر قرار دهیم. اکنون زمان انتخاب آن‌هاست.

هنگامی که پنل Conception انتخاب می‌شود، کامپوننت‌ها در یک پوشهٔ برگه‌ای در بالای پنجرهٔ طراحی در دسترس قرار می‌گیرند:

Image

برای ساخت رابط کاربری گرافیکی، ما کامپوننت‌های swing (1) و کامپوننت‌های awt (2) را داریم. در اینجا، از کامپوننت‌های swing استفاده خواهیم کرد. از نوار کامپوننت در بالا، یک کامپوننت JLabel (۳)، یک کامپوننت JTextField (۴) و یک کامپوننت JButton (۵) را انتخاب کرده و آنها را در کانتینر پنجره طراحی قرار دهید.

Image

اکنون بیایید هر یک از این سه مؤلفه را سفارشی کنیم:

  • برچسب (JLabel) jLabel1

برای باز کردن پنجرهٔ ویژگی‌ها، مؤلفه را انتخاب کنید. در این پنجره، ویژگی‌های زیر را تغییر دهید: name: lblSaisie text: Input

  • میدان ورودی (JTextField) jTextfield1

کامپوننت را برای باز کردن پنجرهٔ ویژگی‌های آن انتخاب کنید. در این پنجره، ویژگی‌های زیر را اصلاح کنید: name: txtSaisie, text: خالی بگذارید

  • دکمه (JButton): name: cmdAfficher, text: نمایش

اکنون پنجره زیر را داریم:

Image

و ساختار زیر:

Image

می‌توانیم پروژه (F9) را اجرا کنیم تا پیش‌نمایش اولیه‌ای از پنجره در عمل مشاهده کنیم:

Image

پنجره را ببندید. اکنون باید رویهٔ مربوط به کلیک روی دکمهٔ Afficher را بنویسیم. دکمه را انتخاب کنید تا به پنجرهٔ ویژگی‌های آن دسترسی پیدا کنید. این پنجره دو زبانه دارد: propriétés و événements. événements را انتخاب کنید.

Image

ستون سمت چپ پنجره، رویدادهای ممکن برای دکمه را فهرست می‌کند. کلیک کردن روی یک دکمه با رویداد actionPerformed مطابقت دارد. ستون سمت راست حاوی نام رویه‌ای است که هنگام وقوع رویداد مربوطه فراخوانی می‌شود. روی سلول سمت راست رویداد actionPerformed کلیک کنید:

Image

JBuilder برای هر رویدادپرداز یک نام پیش‌فرض در قالب nomComposant_nomEvénement تولید می‌کند – در این مورد، cmdAfficher_actionPerformed. می‌توانید نام پیش‌فرض را حذف کرده و نام دیگری وارد کنید. برای دسترسی به کد دستگیرکننده cmdAfficher_actionPerformed، کافی است روی نام آن در بالا دوبار کلیک کنید. این کار به‌طور خودکار شما را به پنجره منبع کلاس می‌برد که روی اسکلت کد دستگیرکننده رویداد قرار دارد:

  void cmdAfficher_actionPerformed(ActionEvent e) {
 }

تنها کاری که باقی مانده تکمیل این کد است. در اینجا، می‌خواهیم یک کادر محاوره‌ای را نمایش دهیم که حاوی محتویات فیلد txtSaisie است:

  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), 
"Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
 }

JOptionPane یک کلاس در کتابخانه javax.swing است. این کلاس امکان نمایش پیام‌ها در کنار یک آیکون یا درخواست اطلاعات از کاربر را فراهم می‌کند. در اینجا، ما از یک متد استاتیک این کلاس استفاده می‌کنیم:

Image

parentComponent
شیء محفظهٔ «والد» (parent) کادر گفتگو: در این مورد، this.
پیام
یک شیء برای نمایش. در اینجا، محتوای فیلد ورودی
عنوان
عنوان کادر گفتگو
messageType
نوع پیامی که باید نمایش داده شود. آیکونی را که در کادر کنار پیام نمایش داده می‌شود، تعیین می‌کند. مقادیر ممکن:
INFORMATION_MESSAGE, QUESTION_MESSAGE, ERROR_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE

بیایید اپلیکیشن خود را اجرا کنیم (F9):

Image

Image

5.2.3.2. کد کلاس پنجره

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import javax.swing.event.*;


public class interface2 extends JFrame {
  JPanel contentPane;
  JLabel lblSaisie = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmdAfficher = new JButton();

  /**ساخت فریم*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**ابتدایی‌سازی کامپوننت*/
  private void jbInit() throws Exception  {
    lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }
   /**جایگزین شد، تا بتوانیم هنگام بسته‌شدن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
  }
}

5.2.3.2.1. ویژگی‌ها
  JPanel contentPane;
  JLabel lblSaisie = new JLabel();
  JButton cmdAfficher = new JButton();

ظرف برای اجزای نوع JPanel و سه جزء موجود هستند.

5.2.3.2.2. تولیدکننده
   /**ساخت فریم*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**ابتدایی‌سازی کامپوننت*/
  private void jbInit() throws Exception  {
    lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }

سازنده interface2 مشابه سازنده رابط کاربری گرافیکی قبلی است که بررسی کردیم. تفاوت‌ها در متد jbInit نهفته است: کد ساخت پنجره به کامپوننت‌های قرار گرفته درون آن بستگی دارد. می‌توانیم کد jbInit را مجدداً استفاده کنیم و نظرات خود را اضافه کنیم:

  private void jbInit() throws Exception  {
       // خود پنجره (اندازه، عنوان)
this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
         // کانتینر کامپوننت
    contentPane = (JPanel) this.getContentPane();
         // هیچ مدیر چیدمانی برای این کانتینر وجود ندارد
    contentPane.setLayout(null);
         // برچسب lblSaisie (متن، موقعیت، اندازه)
         lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
        // میدان ورودی (موقعیت، اندازه)
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
         // دکمه «نمایش» (برچسب، موقعیت، اندازه)
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
         // پردازشگر رویداد دکمه
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
         // افزودن ۳ مؤلفه به کانتینر
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }//jbInit

دو نکته قابل توجه است:

  • این کد می‌توانست به‌صورت دستی نوشته شود. این بدان معناست که JBuilder برای ساخت یک رابط کاربری گرافیکی ضروری نیست.
  • نحوهٔ تعیین رویدادپرداز برای دکمهٔ cmdAfficher. رویدادپرداز برای کامپوننت cmdAfficher می‌توانست به صورت cmdAfficher.addActionListener اعلام شود.(new handler()) که در آن gestionnaire کلاسی با متد عمومی actionPerformed خواهد بود که مسئول رسیدگی به کلیک‌های روی دکمه Afficher است. در اینجا، JBuilder از یک نمونه از یک کلاس ناشناس به عنوان دستگیرکننده استفاده می‌کند:
 new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }

یک نمونه جدید از رابط ActionListener ایجاد می‌شود و متد actionPerformed آن همزمان تعریف می‌گردد. این متد به سادگی یک متد از کلاس interface2 را فراخوانی می‌کند. تمام این‌ها صرفاً یک راه‌حل موقت است تا در همان کلاسی که پنجره در آن تعریف شده، رویه‌های مدیریت رویدادهای اجزای آن پنجره را تعریف کند. می‌توان به روش دیگری عمل کرد:

cmdAfficher.addActionListener(this)

که یعنی متد actionPerformed در this، یعنی در کلاس پنجره، جستجو خواهد شد. این متد دوم ساده‌تر به نظر می‌رسد، اما متد اول یک مزیت نسبت به آن دارد: این امکان را می‌دهد که برای دکمه‌های مختلف از هندلرهای متفاوتی استفاده شود، در حالی که متد دوم این امکان را ندارد. در مورد دوم، یک متد واحد actionPeformed باید کلیک روی دکمه‌های مختلف را مدیریت کند و بنابراین باید ابتدا تشخیص دهد که کدام دکمه رویداد را فعال کرده است، پیش از آنکه بتواند پردازش را آغاز کند.

5.2.3.2.3. پردازنده‌های رویداد

این‌ها همان‌هایی هستند که قبلاً بررسی کرده‌ایم:

   /**جایگزین شده، تا بتوانیم هنگام بستن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }

     // کلیک روی دکمه «Show»
  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
  }

5.2.3.3. Conclusion

از دو پروژه مورد مطالعه، می‌توان نتیجه گرفت که پس از ساخت رابط کاربری گرافیکی با استفاده از JBuilder، وظیفه توسعه‌دهنده نوشتن رویدادپردازها برای رویدادهایی است که می‌خواهد برای آن رابط کاربری گرافیکی مدیریت کند.

5.2.4. درخواست کمک

در جاوا، اغلب به کمک نیاز دارید، به‌ویژه به دلیل تعداد بسیار زیاد کلاس‌های موجود. در اینجا چند نکته برای یافتن کمک در مورد یک کلاس آورده شده است. از منو گزینه Help/Help Topics را انتخاب کنید.

Image

صفحه کمک معمولاً دو پنجره دارد:

  • یکی در سمت چپ که در آن عبارت مورد نظر خود را وارد می‌کنید. این پنجره سه زبانه دارد: Sommaire، Index و Chercher.
  • پنجره سمت راست که نتایج جستجو را نمایش می‌دهد

راهنما در مورد نحوه استفاده از سیستم راهنمای JBuilder در دسترس است. در راهنمای JBuilder، گزینه Help/Using Help را انتخاب کنید. این بخش نحوه استفاده از سیستم راهنما را توضیح می‌دهد. برای مثال، اجزای مختلف نمایشگر راهنما را به شما نشان خواهد داد:

Image

بیایید نگاهی دقیق‌تر به صفحات Sommaire و Index بیندازیم.

5.2.4.1. راهنما: فهرست مطالب

Image

5.2.4.1.1. فهرست مطالب: مقدمه‌ای بر جاوا

در اینجا اصول اولیهٔ جاوا را خواهید یافت، اما نه تنها آن، همان‌طور که از فهرست موضوعات پوشش‌داده‌شده در این ماژول پیداست:

Image

5.2.4.1.2. فهرست: آموزش‌ها

اگر گزینه «آموزش‌ها» را از فهرست مطالب بالا انتخاب کنیم، پنجره سمت راست فهرستی از آموزش‌های موجود را نمایش می‌دهد:

Image

آموزش‌های پایه به‌ویژه برای تسلط بر JBuilder بسیار مفید هستند. آموزش‌های بسیاری غیر از موارد نمایش‌داده‌شده در بالا وجود دارد، و هنگامی که می‌خواهید یک برنامه کاربردی توسعه دهید، ممکن است ارزش داشته باشد که ابتدا بررسی کنید آیا آموزشی وجود دارد که بتواند به شما کمک کند.

5.2.4.1.3. فهرست: JDK

با انتخاب گزینه Java 2 JDK 1.3، به تمام کتابخانه‌های موجود در JDK دسترسی خواهید داشت. به‌طور کلی، اگر به دنبال اطلاعاتی درباره یک کلاس خاص هستید و نمی‌دانید در کدام کتابخانه قرار دارد، اینجا جای مناسبی نیست. با این حال، این گزینه زمانی مفید است که می‌خواهید دید کلی از کتابخانه‌های جاوا به دست آورید.

5.2.4.2. راهنما: نمایه

در پنل سمت چپ پنجرهٔ راهنما، زبانهٔ «فهرست» را انتخاب کنید. این گزینه به شما امکان می‌دهد، برای مثال، راهنمای یک کلاس را پیدا کنید. فرض کنید می‌خواهید دربارهٔ متدهای فیلدهای ورودی swing و JTextField اطلاعات کسب کنید. JTextField را در کادر متن جستجو تایپ کنید:

Image

تابع راهنما ورودی‌های شاخص را که با متنی که وارد کرده‌اید شروع می‌شوند، بازخواهد گرداند:

Image

کافی است روی مدخلی که به آن علاقه‌مند هستید، در این مورد کلاس JTextField، دوبار کلیک کنید. راهنمای این کلاس سپس در پنجره سمت راست نمایش داده خواهد شد:

Image

سپس توضیح کاملی از کلاس ارائه می‌شود.

5.2.5. برخی از کامپوننت‌های Swing

اکنون به بررسی برنامه‌های مختلفی می‌پردازیم که شامل رایج‌ترین اجزای swing هستند، تا روش‌ها و ویژگی‌های اصلی آن‌ها را کشف کنیم. برای هر برنامه، رابط کاربری گرافیکی و کد مربوطه، به‌ویژه کد دستگیرکننده‌های رویداد، را ارائه خواهیم داد.

5.2.5.1. کامپوننت‌های JLabel و JTextField

ما قبلاً با این دو کامپوننت آشنا شده‌ایم. JLabel یک کامپوننت متنی است و JTextField یک کامپوننت فیلد ورودی است. دو متد اصلی آن‌ها عبارتند از

String getText()
برای بازیابی محتوای فیلد ورودی یا متن برچسب
void setText(String unTexte)
برای تنظیم unTexte در فیلد یا برچسب

رویدادهای معمولاً استفاده شده برای JTextField به شرح زیر است:

actionPerformed
نشان می‌دهد که کاربر (با فشردن Enter) متن وارد شده را تأیید کرده است
caretUpdate
نشان می‌دهد که کاربر مکان‌نما را جابه‌جا کرده است
inputMethodChanged
نشان می‌دهد که کاربر فیلد ورودی را تغییر داده است

در اینجا مثالی آورده شده است که از رویداد caretUpdate برای ردیابی تغییرات یک فیلد ورودی استفاده می‌کند:

Image

خیر.
نوع
نام
نقش
1
JTextField
txtSaisie
میدان ورودی
2
JTextField
txtControle
متن ۱ را به‌صورت بلادرنگ نمایش می‌دهد
۳
JButton
cmdEffacer
برای پاک کردن فیلدهای ۱ و ۲
4
JButton
cmdQuitter
برای خروج از برنامه

کد مربوطه برای این برنامه به شرح زیر است:

import java.awt.*;
....


public class Cadre1 extends JFrame {
  JPanel contentPane;
  JTextField txtSaisie = new JTextField();
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JTextField txtControle = new JTextField();
  JButton CmdEffacer = new JButton();
  JButton CmdQuitter = new JButton();

  /**چارچوب را بسازید*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**ابتدایی‌سازی کامپوننت*/
  private void jbInit() throws Exception  {
    ....
    txtSaisie.addCaretListener(new javax.swing.event.CaretListener() {
      public void caretUpdate(CaretEvent e) {
        txtSaisie_caretUpdate(e);
      }
    });

...
    CmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdEffacer_actionPerformed(e);
      }
    });
...
    CmdQuitter.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdQuitter_actionPerformed(e);
      }
    });
....
}

   /**جایگزین شد، تا بتوانیم هنگام بستن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_caretUpdate(CaretEvent e) {
         // نشانگر ورودی جابجا شده است
    txtControle.setText(txtSaisie.getText());
  }

  void CmdQuitter_actionPerformed(ActionEvent e) {
        //خروج از برنامه
    System.exit(0);
  }

  void CmdEffacer_actionPerformed(ActionEvent e) {
        // پاک کردن محتویات فیلد ورودی
    txtSaisie.setText("");
  }
}

در اینجا نمونه‌ای از خروجی آورده شده است:

Image

5.2.5.2. کامپوننت JComboBox

Image

Image

یک کامپوننت JComboBox یک لیست کشویی است که با یک فیلد ورودی ترکیب شده است: کاربر می‌تواند یا یک مورد را از (2) انتخاب کند یا متن را در (1) تایپ کند. به طور پیش‌فرض، کامپوننت‌های JComboBox قابل ویرایش نیستند. برای قابل ویرایش کردن آن‌ها، باید صراحتاً متد setEditable(true) را فراخوانی کنید. برای کسب اطلاعات بیشتر درباره کلاس JComboBox، عبارت JComboBox را در نمایه راهنما تایپ کنید.

شیء JComboBox را می‌توان به روش‌های مختلفی ایجاد کرد:

new JComboBox()
یک کادر ترکیبی خالی ایجاد می‌کند
new JComboBox (Object[] items)
یک کادر ترکیبی حاوی آرایه‌ای از اشیاء ایجاد می‌کند
new JComboBox(Vector items)
همانند مورد بالا، اما با یک بردار از اشیاء

شاید تعجب‌آور باشد که یک کادر ترکیبی می‌تواند اشیاء را در خود جای دهد، در حالی که معمولاً حاوی رشته‌ها است. از نظر بصری، این امر واقعاً صادق است. اگر یک JComboBox حاوی یک شیء obj باشد، رشته obj.toString را نمایش می‌دهد(). به یاد داشته باشید که هر شیء دارای متد toString است که از کلاس Object به ارث رسیده و یک رشتهٔ کاراکتری را بازمی‌گرداند که «نماینده» آن شیء است.

متدهای مفید کلاس JCombobox به شرح زیر هستند:

void addItem(Object unObjet)
یک شیء را به لیست کشویی اضافه می‌کند
int getItemCount()
تعداد موارد موجود در کادر ترکیبی را برمی‌گرداند
Object getItemAt(int i)
شیء i-ام در کادر ترکیبی را برمی‌گرداند
void insertItemAt(Object unObjet, int i)
مقدار unObjet را در موقعیت i در کادر ترکیبی درج می‌کند
integer getSelectedIndex()
تعداد آیتم انتخاب‌شده در کادر ترکیبی را برمی‌گرداند
شئ getSelectedItem()
شیء انتخاب‌شده در کادر ترکیبی را برمی‌گرداند
void setSelectedIndex(int i)
مورد i را از لیست کشویی انتخاب می‌کند
void setSelectedItem(Object unObjet)
شیء مشخص‌شده را از لیست کشویی انتخاب می‌کند
void removeAllItems()
کادر ترکیبی را پاک می‌کند
void removeItemAt(int i)
مورد شماره i را از لیست کشویی حذف می‌کند
void removeItem(Object unObjet)
شیء مشخص‌شده را از کادر ترکیبی حذف می‌کند
void setEditable(boolean val)
کادر ترکیبی را قابل ویرایش (val=true) یا غیرقابل ویرایش (val=false) تنظیم می‌کند

هنگامی که یک آیتم از لیست کشویی انتخاب می‌شود، رویداد actionPerformed فعال می‌شود که می‌توان از آن برای اطلاع از تغییر در انتخاب داخل کادر ترکیبی استفاده کرد. در برنامه زیر، ما از این رویداد برای نمایش آیتمی که از لیست انتخاب شده است، استفاده می‌کنیم.

Image

ما فقط کد مرتبط با پنجره را نمایش می‌دهیم.

public class Cadre1 extends JFrame {
  JPanel contentPane;
  JComboBox jComboBox1 = new JComboBox();
  JLabel jLabel1 = new JLabel();

   /**فرم را بسازید*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     //پردازش – پر کردن لیست کشویی
    String[] infos={"un","deux","trois","quatre"};
    for(int i=0;i<infos.length;i++)
      jComboBox1.addItem(infos[i]);
  }
   /**کامپوننت را راه‌اندازی کنید*/
  private void jbInit() throws Exception  {
        ....

    jComboBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jComboBox1_actionPerformed(e);
      }
    });
       .... 
  }

  void jComboBox1_actionPerformed(ActionEvent e) {
        //یک آیتم جدید انتخاب شده است – آن را نمایش دهید
    JOptionPane.showMessageDialog(this,jComboBox1.getSelectedItem(),
"actionPerformed",JOptionPane.INFORMATION_MESSAGE);
  }

}

5.2.5.3. کامپوننت JList

کامپوننت Swing JList پیچیده‌تر از معادل خود در کتابخانه، awt است. دو تفاوت مهم وجود دارد:

  • محتوای لیست توسط ابجکت متفاوتی از خود لیست مدیریت می‌شود. در اینجا از یک شیء DefaultListModel استفاده خواهیم کرد که همانند Vector عمل می‌کند، اما همچنین به محض تغییر محتوای خود، شیء JList را مطلع می‌سازد تا نمایش بصری لیست نیز متناسب با آن تغییر کند.
  • فهرست به‌طور پیش‌فرض پیمایش نمی‌شود. شما باید فهرست را در یک کانتینر ScrollPane قرار دهید تا پیمایش فعال شود.

در کد منبع، یک لیست می‌تواند به صورت زیر تعریف شود:

      // آرایه مقادیر در لیست 
DefaultlistModel valeurs=new DefaultListModel();
//خود لیست، که بردار مقادیر آن به آن مرتبط است
  JList jList1 = new JList(valeurs);
     // کانتینر پیمایشی که لیست در آن قرار می‌گیرد تا یک لیست پیمایشی ایجاد شود
  JScrollPane jScrollPane1 = new JScrollPane(jList1);

برای درج لیست jList1 در کانتینر jScrollPane1، کدی که توسط JBuilder تولید می‌شود به شیوه‌ای متفاوت عمل می‌کند:

  • اعلام کانتینر در ویژگی‌های پنجره
  JScrollPane jScrollPane1 = new JScrollPane();
  • سپس، در کد مربوط به jbInit، لیست با کانتینر مرتبط می‌شود
    jScrollPane1.getViewport().add(jList1, null);

برای افزودن مقادیر به لیست JList1 بالا، کافی است آن‌ها را به بردار مقدار آن valeurs اضافه کنید:

    // ابتدایی‌سازی لیست
    for(int i=0;i<10;i++)
      valeurs.addElement(""+i);

و سپس پنجره زیر را مشاهده خواهید کرد:

Image

این رابط چگونه ساخته شده است؟

  • یک کامپوننت JScrollPane را از صفحه «Swing containers» در بخش کامپوننت‌ها انتخاب کرده و آن را بکشید و در پنجره رها کنید، سپس ابعاد آن را به اندازه دلخواه تنظیم کنید
  • یک کامپوننت JList را از صفحه «Swing» کامپوننت‌ها انتخاب کرده و آن را به داخل کانتینر JScrollPane بکشید و رها کنید، جایی که سپس کل فضا را اشغال خواهد کرد.

کد تولید شده توسط JBuilder نیاز به اصلاح جزئی دارد تا کد زیر تولید شود:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  DefaultListModel valeurs=new DefaultListModel();
  JList jList1 = new JList(valeurs);
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel2 = new JLabel();


   /**ساخت فریم*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     //پردازش
     // فهرست در scrollPane گنجانده شده است
    // فهرست اولیه
    for(int i=0;i<10;i++)
      valeurs.addElement(""+i);
  }

   /**ابتدا کردن مؤلفه*/
  private void jbInit() throws Exception  {
        ....
         // فهرست jList1 با کانتینر jcrollPane1 مرتبط است
    jScrollPane1.getViewport().add(jList1, null);
  }
   /**جایگزین شد، تا بتوانیم هنگام بسته‌شدن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
        ....
  }
}

بیایید اکنون با جستجو برای JList در نمایه‌ی راهنما، روش‌های اصلی کلاس JList را بررسی کنیم. شیء JList را می‌توان به روش‌های مختلفی ایجاد کرد:

Image

یک روش ساده همان روشی است که ما استفاده کرده‌ایم: ایجاد یک V خالی از نوع DefaultListModel و سپس مرتبط کردن آن با لیست مورد نظر با استفاده از new JList(V). محتوای لیست توسط شی JList مدیریت نمی‌شود، بلکه توسط شی‌ای که مقادیر لیست را در خود دارد، مدیریت می‌شود. اگر محتوا با استفاده از یک شیء DefaultListModel مبتنی بر کلاس Vector ساخته شده باشد، می‌توان از متدهای کلاس Vector برای افزودن، درج و حذف موارد از لیست استفاده کرد. یک لیست می‌تواند تک‌انتخابی یا چند‌انتخابی باشد. این توسط متد setSelectionMode تعیین می‌شود:

Image

می‌توان حالت انتخاب فعلی را با استفاده از getSelectionMode تعیین کرد:

Image

موارد انتخاب‌شده را می‌توان با استفاده از روش‌های زیر بازیابی کرد:

Image

ما می‌توانیم با استفاده از سازنده JList(DefaultListModel)، یک بردار از مقادیر را به یک لیست مرتبط کنیم. برعکس، ما می‌توانیم با استفاده از: شیء DefaultListModel را از یک لیست JList به دست آوریم.

Image

اکنون اطلاعات کافی برای نوشتن برنامه زیر را داریم:

Image

اجزای این پنجره به شرح زیر است:

خیر.
نوع
name
نقش
1
JTextField
txtSaisie
میدان ورودی
2
JList
jList1
لیست قرار گرفته در داخل یک کانتینر jScrollPane1
3
JList
jList2
فهرست موجود در یک کانتینر jScrollPane2
4
JButton
cmd1To2
موارد انتخاب‌شده را از لیست ۱ به لیست ۲ منتقل می‌کند
5
JButton
cmd2To1
معکوس آن را انجام می‌دهد
۶
JButton
cmdRaz1
فهرست 1 را پاک کنید
7
JButton
cmdRaz2
پاک کردن لیست ۲

کاربر متن را در فیلد (1) تایپ کرده و آن را ارسال می‌کند. این کار رویداد actionPerformed را در فیلد ورودی فعال می‌کند که برای افزودن متن واردشده به فهرست 1 استفاده می‌شود. در اینجا کد مورد نیاز برای این اولین تابع آمده است:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**ساخت فریم*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**اجرای اولیهٔ کامپوننت*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         // Jlist1 در کانتینر jScrollPane1 قرار می‌گیرد
    jScrollPane1.getViewport().add(jList1, null);
        //Jlist2 در کانتینر jScrollPane2 قرار داده شده است
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**جایگزین شد، تا بتوانیم هنگام بستن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
     //متن واردشده اعتبارسنجی شده است
     // متن وارد شده با حذف فاصله‌های ابتدایی و انتهایی بازیابی می‌شود
    String texte=txtSaisie.getText().trim();
     // اگر خالی باشد، آن را نمی‌خواهیم
    if(texte.equals("")){
      // پیام خطا
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      // پایان
      return;
    }//اگر
    // اگر خالی نباشد، آن را به مقادیر در لیست 1 اضافه کنید
    v1.addElement(texte);
     // و فیلد ورودی را پاک کنید
    txtSaisie.setText("");
  }/// txtSaisie_actionperformed
}//کلاس

کد برای انتقال موارد انتخاب‌شده از یک لیست به لیست دیگر به شرح زیر است:

  void cmd1To2_actionPerformed(ActionEvent e) {
    //موارد منتخب را از فهرست ۱ به فهرست ۲ منتقل کنید
    transfert(jList1,jList2);
  }//cmd1To2

  void cmd2To1_actionPerformed(ActionEvent e) {
    //انتقال موارد منتخب از jList2 به jList1
      transfert(jList2,jList1);
  }//cmd2TO1

  private void transfert(JList L1, JList L2){
      //انتقال موارد منتخب از لیست ۱ به لیست ۲
       //آرایهٔ شاخص‌های موارد انتخاب‌شده را از L1 بازیابی کنید
      int[] indices=L1.getSelectedIndices();
      // آیا کاری با آن دارد؟
      if (indices.length==0) return;
      //مقادیر را از L1 بازیابی می‌کند
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      //و آن‌هایی از L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // ما مقادیر انتخاب‌شده از L1 را به L2 اضافه می‌کنیم
        v2.addElement(v1.elementAt(indices[i]));
        // عناصر از L1 که به L2 کپی شده‌اند باید از L1 حذف شوند
        v1.removeElementAt(indices[i]);
      }//برای
  }//انتقال

کد مرتبط با دکمه‌های Raz بسیار ساده است:

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // فهرست ۱ را پاک کنید
    v1.removeAllElements();
  }//فرمان Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // فهرست ۲ را پاک کنید
    v2.removeAllElements();
  }///cmd Raz2

5.2.5.4. تیک‌باکس‌های JCheckBox، دکمه‌های رادیویی JButtonRadio

ما پیشنهاد می‌کنیم برنامه زیر را بنویسیم:

Image

اجزای پنجره به شرح زیر هستند:

خیر.
نوع
نام
نقش
1
JButtonRadio
jButtonRadio1
jButtonRadio2
jButtonRadio3
۳ دکمهٔ رادیویی متعلق به گروه buttonGroup1
۲
JCheckBox
jCheckBox1
jCheckBox2
jCheckBox3
۳ کادر تیک‌دار
۳
JList
jList1
یک لیست درون یک کانتینر jScrollPane1
۴
ButtonGroup
buttonGroup1
جزء غیرقابل مشاهده – برای گروه‌بندی سه دکمه رادیویی استفاده می‌شود تا وقتی یکی انتخاب می‌شود، بقیه غیرفعال شوند.

یک گروه از دکمه‌های رادیویی را می‌توان به صورت زیر ایجاد کرد:

  • هر دکمه رادیویی را بدون نگرانی در مورد گروه‌بندی آن‌ها قرار دهید
  • یک کامپوننت Swing به نام ButtonGroup را داخل کانتینر قرار دهید. این کامپوننت غیرقابل مشاهده است. بنابراین در ویزور دیزاینر پنجره نمایش داده نمی‌شود. با این حال، در ساختار پنجره ظاهر می‌شود:

Image

همانطور که در بالا در شاخه Autre نشان داده شده است، این‌ها ویژگی‌های غیرنمایشی پنجره هستند. پس از ایجاد یک گروه از دکمه های رادیویی، هر دکمه رادیویی را می‌توان به آن مرتبط کرد. برای این کار، ویژگی‌های دکمه رادیویی را انتخاب کنید:

Image

و در ویژگی buttonGroup دکمه رادیویی، نام گروهی را که می‌خواهید دکمه رادیویی را به آن اختصاص دهید وارد کنید—در این مورد، buttonGroup1. این فرآیند را برای هر سه دکمه رادیویی تکرار کنید.

روش اصلی برای دکمه‌های رادیویی و چک‌باکس‌ها، متد isSelected() است که نشان می‌دهد آیا چک‌باکس یا دکمه رادیویی انتخاب شده است. متن مرتبط با کامپوننت را می‌توان با استفاده از getText() بازیابی کرد و با استفاده از setText تنظیم نمود.(String unTexte). دکمهٔ رادیویی یا تیک‌باکس را می‌توان با استفاده از متد setSelected(boolean value) انتخاب کرد.

وقتی دکمه رادیویی یا تیک‌باکس کلیک می‌شود، رویداد actionPerformed فعال می‌شود. در کد زیر، از این رویداد برای ردیابی تغییرات در مقادیر دکمه‌های رادیویی و تیک‌باکس‌ها استفاده می‌کنیم:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JRadioButton jRadioButton1 = new JRadioButton();
  JRadioButton jRadioButton2 = new JRadioButton();
  JRadioButton jRadioButton3 = new JRadioButton();
  JCheckBox jCheckBox1 = new JCheckBox();
  JCheckBox jCheckBox2 = new JCheckBox();
  JCheckBox jCheckBox3 = new JCheckBox();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel valeurs=new DefaultListModel();
  JList jList1 = new JList(valeurs);

   /**ساخت فریم*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**ابتدایی‌سازی مؤلفه*/
  private void jbInit() throws Exception  {
    jRadioButton1.setSelected(true);
    jRadioButton1.setText("un");
    jRadioButton1.setBounds(new Rectangle(57, 31, 49, 23));
    jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });

    jRadioButton2.setBounds(new Rectangle(113, 30, 49, 23));
    jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });
    jRadioButton2.setText("deux");

    jRadioButton3.setBounds(new Rectangle(168, 30, 49, 23));
    jRadioButton3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });
    jRadioButton3.setText("trois");

//دکمه‌های رادیویی گروه‌بندی شده‌اند
    buttonGroup1.add(jRadioButton1);
    buttonGroup1.add(jRadioButton2);
    buttonGroup1.add(jRadioButton3);

// تیک‌باکس‌ها
    jCheckBox1.setText("A");
    jCheckBox1.setBounds(new Rectangle(58, 69, 32, 17));
    jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });

    jCheckBox2.setBounds(new Rectangle(112, 69, 40, 17));
    jCheckBox2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });
    jCheckBox2.setText("B");

    jCheckBox3.setText("C");
    jCheckBox3.setBounds(new Rectangle(170, 69, 37, 17));
    jCheckBox3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });

    ....
  }
   /**جایگزین شد، تا بتوانیم هنگام بستن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
        ...
  }

  private void afficheRadioButtons(ActionEvent e){
     //مقادیر ۳ دکمه رادیویی را نمایش می‌دهد
    valeurs.addElement("boutons radio=("+jRadioButton1.isSelected()+","+
      jRadioButton2.isSelected()+","+jRadioButton3.isSelected()+")");
  }//afficheRadioButtons

  void afficheCases(ActionEvent e) {
     //مقادیر چک‌باکس‌ها را نمایش می‌دهد
    valeurs.addElement("cases à cocher=["+jCheckBox1.isSelected()+","+
      jCheckBox2.isSelected()+","+jCheckBox3.isSelected()+")");
  }//afficheCases

}//مرتب‌سازی

در اینجا نمونه‌ای از خروجی آورده شده است:

Image

5.2.5.5. کامپوننت JScrollBar

بیایید اپلیکیشن زیر را ایجاد کنیم:

Image

خیر.
نوع
نام
نقش
1
JScrollBar
jScrollBar1
یک واریاتور افقی
2
JScrollBar
jScrollBar2
یک واریاتور عمودی
۳
JTextField
txtvaleurHS
مقدار درایو افقی ۱ را نمایش می‌دهد – همچنین امکان تنظیم این مقدار را فراهم می‌کند
۴
JTextField
txtvaleurVS
مقدار اسلایدر عمودی ۲ را نمایش می‌دهد – همچنین امکان تنظیم این مقدار را فراهم می‌کند
  • اسلایدر JScrollBar به کاربر اجازه می‌دهد از میان بازه‌ای از مقادیر صحیح، مقداری را انتخاب کند که با «باند» اسلایدر نشان داده می‌شود و نشانگر روی آن حرکت می‌کند.
  • برای یک اسلایدر افقی، انتهای سمت چپ نشان‌دهنده حداقل مقدار محدوده، انتهای سمت راست نشان‌دهنده حداکثر مقدار و مکان‌نما نشان‌دهنده مقدار انتخاب‌شده فعلی است. برای یک اسلایدر عمودی، حداقل مقدار با انتهای بالایی و حداکثر مقدار با انتهای پایینی نشان داده می‌شود. زوج (min,max) به صورت پیش‌فرض روی (0,100) تنظیم شده است.
  • کلیک کردن روی انتهای اسلایدر، مقدار را به اندازه یک گام (مثبت یا منفی) بسته به انتهای کلیک شده تغییر می‌دهد، که به آن unitIncrement گفته می‌شود و به طور پیش‌فرض روی 1 تنظیم شده است.
  • کلیک کردن در هر دو طرف اسلایدر، بسته به اینکه کدام انتها کلیک شود، مقدار را به اندازه یک گام (مثبت یا منفی) تغییر می‌دهد، که به آن blockIncrement گفته می‌شود و به طور پیش‌فرض روی 10 تنظیم شده است.
  • این پنج مقدار (min, max, value, unitIncrement, blockIncrement) را می‌توان با استفاده از متدهای getMinimum(), getMaximum(), به دست آورد. getValue()، getUnitIncrement()، getBlockIncrement()، که همگی یک عدد صحیح بازمی‌گردانند و می‌توان آن‌ها را با متدهای setMinimum(int min) مقداردهی کرد، setMaximum(int max), setValue(int val), setUnitIncrement(int uInc), setBlockIncrement(int bInc)

چند نکته وجود دارد که هنگام استفاده از کامپوننت‌های JScrollBar باید در نظر گرفت. اول اینکه، می‌توان آن را در نوار کامپوننت Swing یافت:

Image

وقتی آن را به داخل کانتینر می‌کشید و رها می‌کنید، به‌طور پیش‌فرض عمودی است. می‌توانید با استفاده از ویژگی orientation زیر آن را افقی کنید:

Image

در برگهٔ ویژگی‌ها در بالا، می‌توانیم ببینیم که به ویژگی‌های minimum، maximum، value دسترسی داریم، unitIncrement، blockIncrement از JScrollbar. بنابراین می‌توانیم این‌ها را در زمان طراحی تنظیم کنیم. وقتی یک نوار پیمایش روی کانتینر قرار می‌گیرد، «دامنه پیمایش» آن ظاهر نمی‌شود:

Image

این مشکل را می‌توان با افزودن یک حاشیه به کامپوننت حل کرد. این کار با استفاده از خاصیت border آن انجام می‌شود که می‌تواند مقادیر مختلفی داشته باشد:

Image

در اینجا مثالی از شکل RaisedBevel آورده شده است:

Image

وقتی روی انتهای بالایی یک اسلایدر عمودی کلیک می‌کنید، مقدار آن کاهش می‌یابد. این موضوع ممکن است کاربر عادی را غافلگیر کند، زیرا او معمولاً انتظار دارد مقدار «افزایش» یابد. این مشکل با تنظیم مقادیر unitIncrement و blockIncrement به مقادیر منفی حل می‌شود.

چگونه می‌توانید تغییرات یک اسلایدر را نظارت کنید؟ هنگامی که مقدار آن تغییر می‌کند، رویداد adjustmentValueChanged فعال می‌شود. به سادگی یک رویه را به این رویداد مرتبط کنید تا از هر تغییر در مقدار اسلایدر مطلع شوید.

Image

کد مربوطه برای برنامه ما به شرح زیر است:

....

public class cadreAppli extends JFrame {
  JPanel contentPane;
  JScrollBar jScrollBar1 = new JScrollBar();
  Border border1;
  JTextField txtValeurHS = new JTextField();
  JScrollBar jScrollBar2 = new JScrollBar();
  JTextField txtValeurVS = new JTextField();
  TitledBorder titledBorder1;

   /**ساخت فریم*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**ابتدایی‌سازی مؤلفه*/
  private void jbInit() throws Exception  {
...

// یک مرز برای نوارهای پیمایش
    border1 = BorderFactory.createBevelBorder(BevelBorder.RAISED,Color.white,Color.white,new Color(134, 134, 134),new Color(93, 93, 93));
        // بدون نوار عنوان یا حاشیه
    titledBorder1 = new TitledBorder("");

    jScrollBar1.setOrientation(JScrollBar.HORIZONTAL);
    jScrollBar1.setBorder(BorderFactory.createRaisedBevelBorder());
    jScrollBar1.setAutoscrolls(true);
    jScrollBar1.setBounds(new Rectangle(37, 17, 218, 20));
    jScrollBar1.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar1_adjustmentValueChanged(e);
      }
    });

    txtValeurHS.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtValeurHS_actionPerformed(e);
      }
    });

    jScrollBar2.setBounds(new Rectangle(39, 51, 30, 27));
    jScrollBar2.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar2_adjustmentValueChanged(e);
      }
    });
    jScrollBar2.setAutoscrolls(true);
    jScrollBar2.setUnitIncrement(-1);
    jScrollBar2.setBorder(BorderFactory.createRaisedBevelBorder());

    txtValeurVS.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtValeurVS_actionPerformed(e);
      }
    });

    ......
  }

   /**تعویض شد، تا بتوانیم هنگام بسته‌شدن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
    // مقدار نوار پیمایش ۱ تغییر کرده است
    txtValeurHS.setText(""+jScrollBar1.getValue());
  }

  void jScrollBar2_adjustmentValueChanged(AdjustmentEvent e) {
    // مقدار نوار پیمایش ۲ تغییر کرده است
    txtValeurVS.setText(""+jScrollBar2.getValue());
  }

  void txtValeurHS_actionPerformed(ActionEvent e) {
    //مقدار نوار پیمایش افقی را تنظیم می‌کند
    setValeur(jScrollBar1,txtValeurHS);
  }

  void txtValeurVS_actionPerformed(ActionEvent e) {
    //مقدار نوار پیمایش عمودی را تنظیم می‌کند
    setValeur(jScrollBar2,txtValeurVS);
  }

  private void setValeur(JScrollBar jS, JTextField jT){
     //مقدار نوار پیمایش jS را به متنی که در فیلد jT قرار دارد تنظیم می‌کند
    int valeur=0;
    try{
      valeur=Integer.parseInt(jT.getText());
      jS.setValue(valeur);
    }
    catch (Exception e){
      //خطا را نمایش می‌دهد
      afficher(""+e);
    }//try-catch
  }//setValeur

  void afficher(String message){
    //پیامی را در یک کادر نمایش می‌دهد
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//نمایش

}

در اینجا نمونه‌ای از خروجی آورده شده است:

Image

5.2.5.6. کامپوننت JTextArea

کامپوننت JTextArea به شما امکان می‌دهد چندین خط متن وارد کنید، برخلاف کامپوننت JTextField که فقط یک خط را مجاز می‌داند. اگر این کامپوننت در داخل یک کانتینر قابل پیمایش (JScrollPane) قرار گیرد، یک فیلد ورودی متن قابل پیمایش ایجاد می‌کند. این نوع کامپوننت ممکن است، برای مثال، در یک برنامه ایمیل یافت شود که در آن متن پیام ارسالی در یک کامپوننت JTextArea تایپ می‌شود. روش‌های استاندارد عبارتند از String getText() برای بازیابی محتویات فیلد متن، و setText(String unTexte) برای تنظیم unTexte در فیلد متن، و append(String unTexte) برای الحاق unTexte به متن موجود در فیلد متن. برنامه زیر را در نظر بگیرید:

Image

خیر.
نوع
نام
نقش
1
JTextArea
txtTexte
یک کادر متن چندخطی
2
JButton
cmdAfficher
محتویات 1 را در یک کادر محاوره‌ای نمایش می‌دهد
3
JButton
cmdEffacer
محتویات 1 را پاک می‌کند
4
JTextField
txtAjout
متن اضافه شده به متن در 1 هنگام تأیید با فشردن کلید Enter.
۵
JScrollPane
jScrollPane1
یک کانتینر پیمایشی که در آن متن‌جعبه‌ی 1 قرار گرفته است تا یک متن‌جعبه‌ی پیمایشی ایجاد شود.

کد مربوطه به شرح زیر است:

.....

public class cadreAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JButton cmdAfficher = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea txtTexte = new JTextArea();
  JLabel jLabel2 = new JLabel();
  JTextField txtAjout = new JTextField();
  JButton cmdEffacer = new JButton();

  /**ساخت فریم*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**ابتدایی‌سازی مؤلفه*/
  private void jbInit() throws Exception  {

    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    txtAjout.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtAjout_actionPerformed(e);
      }
    });
    cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdEffacer_actionPerformed(e);
      }
    });
    .......
    jScrollPane1.getViewport().add(txtTexte, null);
  }
   /**جایگزین شد، تا بتوانیم هنگام بستن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
        ........
  }

  void cmdAfficher_actionPerformed(ActionEvent e) {
    //محتویات TextArea را نمایش می‌دهد
    afficher(txtTexte.getText());
  }

    void afficher(String message){
     //یک پیام را در یک کادر نمایش می‌دهد
    JOptionPane.showMessageDialog(this,message,"Suivi",JOptionPane.INFORMATION_MESSAGE);
  }//نمایش

  void cmdEffacer_actionPerformed(ActionEvent e) {
    txtTexte.setText("");
  }//cmdEffacer_actionPerformed

  void txtAjout_actionPerformed(ActionEvent e) {
    // افزودن متن
    txtTexte.append(txtAjout.getText());
     //پاک کردن و افزودن
    txtAjout.setText("");
  }//
}

5.2.6. رویدادهای ماوس

هنگام ترسیم در داخل یک کانتینر، دانستن موقعیت ماوس مهم است تا برای مثال، هنگام کلیک روی ماوس بتوان یک نقطه نمایش داد. حرکات ماوس، رویدادهایی را در کانتینری که ماوس در آن در حال حرکت است، فعال می‌کند. در اینجا، برای مثال، رویدادهایی که توسط JBuilder برای یک کانتینر JPanel ارائه می‌شوند، آورده شده است:

Image

mouseClicked
کلیک ماوس
mouseDragged
حرکت ماوس، فشرده شدن دکمه چپ
mouseEntered
موش به تازگی وارد ناحیه کانتینر شده است
mouseExited
موش به تازگی سطح ظرف را ترک کرده است
mouseMoved
موش در حال حرکت است
mousePressed
دکمه چپ ماوس فشرده شد
mouseReleased
رها شدن دکمه چپ ماوس

در اینجا برنامه‌ای برای کمک به شما جهت درک بهتر زمان وقوع رویدادهای مختلف ماوس آورده شده است:

Image

خیر.
نوع
نام
نقش
۱
JTextField
txtPosition
برای نمایش موقعیت ماوس در داخل کانتینر (احتمالاً MouseMoved)
2
JList
lstAffichage
برای نمایش رویدادهای ماوس غیر از MouseMoved
۳
JButton
cmdEffacer
برای پاک کردن محتویات 2

وقتی این برنامه اجرا می‌شود، خروجی برای یک کلیک به این صورت است:

Image

رویدادها از بالای لیست روی هم انباشته می‌شوند. بنابراین اسکرین‌شات بالا نشان می‌دهد که یک کلیک واحد سه رویداد را به ترتیب زیر فعال می‌کند:

  1. MousePressed وقتی دکمه فشرده می‌شود
  2. MouseReleased هنگام رها کردن دکمه
  3. MouseClicked، که نشان می‌دهد توالی دو رویداد قبلی به‌عنوان یک کلیک در نظر گرفته می‌شود. این می‌تواند یک دابل‌کلیک باشد. با این حال، اطلاعات clickCount=1 در بالا نشان می‌دهد که این یک کلیک ساده است.

اکنون، اگر دکمه را فشار دهید، ماوس را حرکت دهید و دکمه را رها کنید:

Image

در اینجا می‌توانیم سه رویداد را مشاهده کنیم:

  1. MousePressed زمانی که دکمه برای اولین بار فشرده می‌شود
  2. MouseDragged هنگام حرکت ماوس در حالی که دکمه نگه داشته شده است
  3. MouseReleased زمانی که دکمه رها می‌شود

در دو مثال بالا، می‌بینیم که یک رویداد ماوس اطلاعات مختلفی از جمله مختصات (x,y) ماوس را در خود دارد، برای مثال (408,65) در خط اول بالا.

اگر به همین ترتیب ادامه دهیم، متوجه می‌شویم که رویداد MouseExited به محض اینکه ماوس از کانتینر خارج می‌شود یا روی یکی از اجزای آن قرار می‌گیرد، فعال می‌شود. در مورد دوم، کانتینر رویداد MouseExited را دریافت می‌کند و کامپوننت رویداد MouseEntered را دریافت می‌کند. وقتی ماوس از کامپوننت خارج شده و به کانتینر بازمی‌گردد، عکس این عمل رخ خواهد داد.

وقتی دوبار کلیک می‌کنید چه اتفاقی می‌افتد؟

Image

رویدادها دقیقاً مانند یک کلیک ساده هستند. تنها تفاوت این است که رویداد اطلاعات clickCount=2 (به بالا مراجعه کنید) را حمل می‌کند که نشان می‌دهد در واقع یک کلیک دوگانه رخ داده است.

کد مربوطه برای این برنامه به شرح زیر است:

public class Cadre1 extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtPosition = new JTextField();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel valeurs=new DefaultListModel();
  JList lstAffichage = new JList(valeurs);
  JButton cmdEffacer = new JButton();

  /**چارچوب را بسازید*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**ابتدایی‌سازی مؤلفه*/
  private void jbInit() throws Exception  {

    contentPane.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
      public void mouseMoved(MouseEvent e) {
        contentPane_mouseMoved(e);
      }
      public void mouseDragged(MouseEvent e) {
        contentPane_mouseDragged(e);
      }
    });

    contentPane.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseEntered(MouseEvent e) {
        contentPane_mouseEntered(e);
      }
      public void mouseExited(MouseEvent e) {
        contentPane_mouseExited(e);
      }
      public void mousePressed(MouseEvent e) {
        contentPane_mousePressed(e);
      }
      public void mouseClicked(MouseEvent e) {
        contentPane_mouseClicked(e);
      }
      public void mouseReleased(MouseEvent e) {
        contentPane_mouseReleased(e);
      }
    });

    cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdEffacer_actionPerformed(e);
      }
    });

    jScrollPane1.getViewport().add(lstAffichage, null);

...............
  }
   /**جایگزین شد، تا بتوانیم هنگام بسته‌شدن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
    .........
  }

  void contentPane_mouseMoved(MouseEvent e) {
    txtPosition.setText("("+e.getX()+","+e.getY()+")");
  }

  void contentPane_mouseDragged(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseEntered(MouseEvent e) {
    afficher(e);
  }

  void afficher(MouseEvent e){
     //رویداد را در لیست نمایش می‌دهد lstAffichage
    valeurs.insertElementAt(e,0);
  }

  void contentPane_mouseExited(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mousePressed(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseClicked(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseReleased(MouseEvent e) {
    afficher(e);
  }

  void cmdEffacer_actionPerformed(ActionEvent e) {
     // فهرست را پاک می‌کند
    valeurs.removeAllElements();
  }
}

5.2.7. ایجاد یک پنجره با منو

حال ببینیم چگونه با استفاده از JBuilder یک پنجره با منو ایجاد کنیم. ما قصد داریم پنجره زیر را ایجاد کنیم:

Image

Image

یک پروژه جدید را با یک پنجره خالی ایجاد کنید. از لیست کامپوننت‌های «Swing Containers»، کامپوننت JMenuBar (به شکل ۱ در زیر مراجعه کنید) را انتخاب کرده و آن را بکشید و روی پنجره‌ای که در حال طراحی آن هستید رها کنید.

Image

هیچ چیزی در پنجره طراحی ظاهر نمی‌شود، اما کامپوننت JMenuBar در پنل ساختار پنجره شما ظاهر می‌شود:

Image

روی عنصر jMenuBar1 بالا دوبار کلیک کنید تا منوی حالت طراحی باز شود:

Image

۱
یک آیتم منو درج کنید
2
وارد کردن جداکننده
۳
وارد کردن منوی تو در تو
۴
حذف یک مورد منو
۵
غیرفعال کردن یک مورد منو
۶
مورد منوی چک‌باکس
7
دکمهٔ رادیویی را جابجا کنید

برای ایجاد اولین مورد منوی خود، عبارت «Options A» را در کادر A بالا تایپ کنید، سپس در زیر آن به ترتیب زیر: A1, A2، جداکننده، A3، A4.

Image

سپس در کنار آن:

Image

از ابزار ۳ استفاده کنید تا نشان دهید B3 یک زیرمنوی تو در تو است.

با طراحی منو، ساختار منطقی پنجرهٔ ما تکامل می‌یابد:

Image

اگر اکنون برنامه‌مان را اجرا کنیم، پنجره‌ای خالی بدون منو خواهیم دید. باید منویی را که ایجاد کرده‌ایم با پنجره‌مان مرتبط کنیم. برای این کار، در ساختار پنجره، شیء this را انتخاب کنید:

Image

سپس به ویژگی‌های this دسترسی خواهید داشت:

Image

یکی از این موارد JMenuBar است که برای مشخص کردن منویی که باید با پنجره مرتبط شود، استفاده می‌شود. در سلول سمت راست JMenuBar کلیک کنید. سپس تمام منوهایی که ایجاد کرده‌اید نمایش داده خواهند شد. در این مورد، ما فقط jMenuBar1 را خواهیم داشت. آن را انتخاب کنید.

برنامه را اجرا کنید (F9):

Image

اکنون یک منو داریم، اما گزینه‌ها در حال حاضر هیچ کاری انجام نمی‌دهند. گزینه‌های منو مانند کامپوننت‌ها رفتار می‌کنند: آن‌ها دارای خواص و رویدادها هستند. در ساختار منو، گزینه jMenuItem1 را انتخاب کنید:

Image

سپس می‌توانید به خواص و رویدادهای آن دسترسی پیدا کنید:

Image

صفحه رویدادها را انتخاب کرده و روی سلول سمت راست رویداد actionPerformed کلیک کنید: این رویدادی است که هنگام کلیک روی یک مورد منو رخ می‌دهد. یک دستگیره (handler) به طور پیش‌فرض فراهم شده است. برای مشاهده کد آن، روی آن دوبار کلیک کنید:

Image

ما کد ساده زیر را می‌نویسیم:

  void jMenuItem1_actionPerformed(ActionEvent e) {
    afficher("L'option A1 a été sélectionnée");
  }

  void afficher(String message){
     // یک پیام را در یک کادر نمایش می‌دهد
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//نمایش

برنامه را اجرا کرده و گزینه A1 را برای نمایش پیام زیر انتخاب کنید:

Image

کد مربوطه برای این برنامه به شرح زیر است:

.....

public class Cadre1 extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem jMenuItem1 = new JMenuItem();
  JMenuItem jMenuItem2 = new JMenuItem();
  JMenuItem jMenuItem3 = new JMenuItem();
  JMenuItem jMenuItem4 = new JMenuItem();
  JMenu jMenu2 = new JMenu();
  JMenuItem jMenuItem5 = new JMenuItem();
  JMenuItem jMenuItem6 = new JMenuItem();
  JMenu jMenu3 = new JMenu();
  JMenuItem jMenuItem7 = new JMenuItem();
  JMenuItem jMenuItem8 = new JMenuItem();
  JMenuItem jMenuItem9 = new JMenuItem();

  /**ساخت فریم*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**کامپوننت را راه‌اندازی کنید*/
  private void jbInit() throws Exception  {
        //پنجره با یک منو مرتبط است
    this.setJMenuBar(jMenuBar1);

    jMenu1.setText("Options A");
    jMenuItem1.setText("A1");
    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jMenuItem1_actionPerformed(e);
      }
    });
    jMenuItem2.setText("A2");
    jMenuItem3.setText("A3");
    jMenuItem4.setText("A4");
    jMenu2.setText("Options B");
    jMenuItem5.setText("B1");
    jMenuItem6.setText("B2");
    jMenu3.setText("B3");
    jMenuItem7.setText("B31");
    jMenuItem8.setText("B32");
    jMenuItem9.setText("B4");
    jMenuBar1.add(jMenu1);
    jMenuBar1.add(jMenu2);
    jMenu1.add(jMenuItem1);
    jMenu1.add(jMenuItem2);
    jMenu1.addSeparator();
    jMenu1.add(jMenuItem3);
    jMenu1.add(jMenuItem4);
    jMenu2.add(jMenuItem5);
    jMenu2.add(jMenuItem6);
    jMenu2.add(jMenu3);
    jMenu2.add(jMenuItem9);
    jMenu3.add(jMenuItem7);
    jMenu3.add(jMenuItem8);
  }
   /**جایگزین شد، تا بتوانیم هنگام بسته‌شدن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
....
  }

  void jMenuItem1_actionPerformed(ActionEvent e) {
    afficher("L'option A1 a été sélectionnée");
  }

  void afficher(String message){
     // پیامی را در یک کادر نمایش می‌دهد
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//نمایش

}

5.3. جعبه‌های گفتگو

5.3.1. جعبه‌های پیام

ما قبلاً از کلاس JOptionPane برای نمایش پیام‌ها استفاده کرده‌ایم. برای مثال، کد زیر:

import javax.swing.*;

public class dialog1 {
  public static void main(String arg[]){
    JOptionPane.showMessageDialog(null,"Un message","Titre de la boîte",JOptionPane.INFORMATION_MESSAGE);
  }
}

جعبه‌ی زیر را نمایش می‌دهد:

Image

هنگامی که این پنجره بسته می‌شود، ناپدید می‌شود اما نخ اجرایی که در آن در حال اجرا بود، خاتمه نمی‌یابد. این حالت به طور معمول رخ نمی‌دهد. کادرهای محاوره در یک برنامه کاربردی استفاده می‌شوند که در مقطعی از دستور System.exit(n) برای خاتمه دادن به تمام نخ‌ها استفاده می‌کند. در مثال‌های بعدی که همه بر اساس یک مدل یکسان هستند، این نکته را مد نظر خواهیم داشت. در سیستم عامل DOS، می‌توان برنامه را با استفاده از کلید Ctrl-C خاتمه داد. با JBuilder، از گزینه Run/Reset Programme (Ctrl-F2) استفاده خواهیم کرد. علاوه بر این، آرگومان اول showMessageDialog در اینجا null است. به طور کلی، اینطور نیست. در عوض، این this است، که در آن this به پنجره اصلی برنامه اشاره دارد.

5.3.2. ظاهر و رفتار

ظاهر کادر بالا ممکن است متفاوت باشد. می‌توان این ظاهر را از طریق کلاس javax.swing.UIManager پیکربندی کرد. وقتی کد تولیدشده توسط JBuilder را برای پنجره اولمان بررسی کردیم، به بیانیه‌ای برخوردیم که روی آن تأمل نکردیم:

      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

متد setLookAndFeel از کلاس UIManager (UI = رابط کاربری) به شما امکان می‌دهد ظاهر رابط‌های کاربری گرافیکی را تنظیم کنید. کلاس UIManager دارای متدی برای تعیین «ظاهرهای» ممکن برای رابط‌ها است:

static UIManager.LookAndFeelInfo[]
getInstalledLookAndFeels()

این متد آرایه‌ای از عناصر از نوع LookAndFeelInfo را برمی‌گرداند. این کلاس یک متد دارد:

رشته
getClassName()

که نام کلاسی را که یک ظاهر و حس معین را «پیاده‌سازی» می‌کند، بازمی‌گرداند. بیایید برنامه زیر را امتحان کنیم:

import javax.swing.*;

public class LookAndFeels {
  //نماهای ظاهری موجود را نمایش می‌دهد
  public static void main(String[] args) {
    //فهرست نماها و حس‌وحالات نصب‌شده را نمایش می‌دهد
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    //نمایش
    for(int i=0;i<lf.length;i++){
      System.out.println(lf[i].getClassName());
    }//برای
  }//اصلی
}//مرتب‌سازی

این نتایج زیر را تولید می‌کند:

javax.swing.plaf.metal.MetalLookAndFeel
com.sun.java.swing.plaf.motif.MotifLookAndFeel
com.sun.java.swing.plaf.windows.WindowsLookAndFeel

بنابراین به نظر می‌رسد سه «سبک» «متفاوت» وجود دارد. بیایید به برنامه نمایش پیام خود بازگردیم و سبک‌های مختلف ممکن را امتحان کنیم:

import javax.swing.*;

public class LookAndFeel2 {
  //نماهای ظاهری موجود را نمایش می‌دهد
  public static void main(String[] args) {
    // فهرست ظاهرها و حس‌های نصب‌شده
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    //نمایش
    for(int i=0;i<lf.length;i++){
      // مدیر ظاهر
      try{
        UIManager.setLookAndFeel(lf[i].getClassName());
      }catch(Exception ex){
        System.err.println(ex.getMessage());
      }//catch
      // پیام
      JOptionPane.showMessageDialog(null,"Un message",lf[i].getClassName(),JOptionPane.INFORMATION_MESSAGE);
    }//برای
  }//اصلی
}//کلاس

اجرای کد خروجی زیر را تولید می‌کند:

مطابق با، از راست به چپ، تم‌های «فلز»، «الگو» و «پنجره‌ها».

5.3.3. جعبه‌های تأیید

کلاس JOptionPane دارای متدی به نام showConfirmDialog برای نمایش جعبه‌های تأیید با دکمه‌های Oui است، Non و Annuler. چندین متد showConfirmDialog بازنویسی شده‌اند. ما یکی از آن‌ها را بررسی خواهیم کرد:

ثابت int
showConfirmDialog(Component parentComponent, Object message, String title, int optionType)
parentComponent
کامپوننت والدِ کادرِ گفتگو. اغلب پنجره یا مقدار null
message
پیامی که باید نمایش داده شود
title
عنوان کادر گفتگو
optionType
JOptionPane.YES_NO_OPTION: دکمه‌های بله، نه
JOptionPane.YES_NO_CANCEL_OPTION: دکمه‌های «بله»، «خیر»، «لغو»

نتیجه‌ای که توسط متد بازگردانده می‌شود:

JOptionPane.YES_OPTION
کاربر روی «بله» کلیک کرد
JOptionPane.NO_OPTION
کاربر روی «خیر» کلیک کرد
JOptionPane.CANCEL_OPTION
کاربر روی «لغو» کلیک کرد
JOptionPane.CLOSED_OPTION
کاربر پنجره را بست

در اینجا یک مثال آورده شده است:

import javax.swing.*;

public class confirm1 {
  public static void main(String[] args) {
    // نمایش جعبه‌های تأیید
    int réponse;
    affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_OPTION));
    affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_CANCEL_OPTION));
  }//اصلی

  private static void affiche(int réponse){
     // نوع پاسخی را که دریافت شده است نشان می‌دهد
    switch(réponse){
      case JOptionPane.YES_OPTION :
        System.out.println("Oui");
        break;
      case JOptionPane.NO_OPTION :
        System.out.println("Non");
        break;
      case JOptionPane.CANCEL_OPTION :
        System.out.println("Annuler");
        break;
      case JOptionPane.CLOSED_OPTION :
        System.out.println("Fermeture");
        break;
    }//سوئیچ
  }//نمایش
}//مرتب‌سازی

در کنسول، پیام‌های Non و Annuler نمایش داده می‌شوند.

5.3.4. میدان ورودی

کلاس JOptionPane همچنین امکان وارد کردن داده‌ها را با استفاده از متد showInputDialog فراهم می‌کند. در اینجا نیز چندین متد اِبربارگذاری‌شده وجود دارد. ما یکی از آن‌ها را ارائه می‌دهیم:

ثابت رشته
showInputDialog(Component parentComponent, Object message, String title, int messageType)

آرگومان‌ها همان‌هایی هستند که قبلاً چندین بار با آن‌ها مواجه شده‌ایم. این متد رشته‌ای را که کاربر تایپ کرده است بازمی‌گرداند. در اینجا یک مثال آمده است:

import javax.swing.*;

public class input1 {
  public static void main(String[] args) {
    // ورودی
    System.out.println("Chaîne saisie ["+
      JOptionPane.showInputDialog(null,"Quel est votre nom","Saisie du nom",JOptionPane.QUESTION_MESSAGE )
      + "]");
  }//دست
}//کلاس

نمایش کادر ورودی:

Image

نمایش کنسول:

Chaîne saisie [dupont]

5.4. جعبه‌های انتخاب

اکنون به تعدادی از کادرهای انتخاب از پیش تعریف‌شده در جاوا 2 می‌پردازیم:

JFileChooser
یک کادر انتخاب برای انتخاب یک فایل از درخت فایل‌ها
JColorChooser
یک کادر انتخاب برای انتخاب رنگ

5.4.1. JFileChooser جعبه‌ی انتخاب

ما قصد داریم اپلیکیشن زیر را بسازیم:

Image

کنترل‌ها به شرح زیر هستند:

خیر.
نوع
name
نقش
0
JScrollPane
jScrollPane1
ظرف قابل پیمایش برای کادر متن ۱
1
خود JTextArea درون JScrollPane
txtTexte
متن تایپ‌شده توسط کاربر یا بارگذاری‌شده از یک فایل
2
JButton
btnSauvegarder
امکان ذخیره متن از ۱ در یک فایل متنی را فراهم می‌کند
3
JButton
btnCharger
امکان بارگذاری محتویات یک فایل متنی را به 1 می‌دهد
۴
JButton
btnEffacer
محتویات 1 را پاک می‌کند

یک کنترل غیرگرافیکی استفاده می‌شود: jFileChooser1. این از پالت محفظه‌های Swing JBuilder گرفته شده است:

Image

ما کامپوننت را در پنجره طراحی اما خارج از فرم قرار می‌دهیم. این در لیست کامپوننت‌ها ظاهر می‌شود:

Image

اکنون برای ارائه یک نمای کلی، کد برنامه مربوطه را ارائه می‌دهیم:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;

public class dialogues extends JFrame {
   //اجزای فریم
  JPanel contentPane;
  JButton btnSauvegarder = new JButton();
  JButton btnCharger = new JButton();
  JButton btnEffacer = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea txtTexte = new JTextArea();
  JFileChooser jFileChooser1 = new JFileChooser();

  //فیلترهای فایل
  javax.swing.filechooser.FileFilter filtreTxt = null;

   //ساخت فریم
  public dialogues() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
       // سایر راهاندازیها
      moreInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

   // moreInit
  private void moreInit(){
     // ابتکاریات هنگام ساخت پنجره
     // فیلتر *.txt
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        //آیا 'f' پذیرفته میشود؟
        return f.getName().toLowerCase().endsWith(".txt");
      }//قبول
      public String getDescription(){
        // توضیحات فیلتر
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // ما فیلتر را اضافه میکنیم
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // ما همچنین یک فیلتر برای همه فایلها میخواهیم
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // مخزن منبع برای پوشه FileChooser را روی دایرکتوری جاری تنظیم کنید
    jFileChooser1.setCurrentDirectory(new File("."));
  }

   //کامپوننت را راهاندازی کنید
  private void jbInit() throws Exception  {
.......................
  }
   //جایگزین شد، بنابراین میتوانیم هنگام بستهشدن پنجره خروج کنیم
  protected void processWindowEvent(WindowEvent e) {
......................
    }
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    //انتخاب یک فایل با استفاده از یک شیء JFileChooser

     // فیلتر اولیه را تنظیم کنید
    jFileChooser1.setFileFilter(filtreTxt);
     // نمایش جعبهی انتخاب
    int returnVal = jFileChooser1.showOpenDialog(this);
    // آیا کاربر چیزی را انتخاب کرده است؟
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // قرار دادن فایل در فیلد متن
       lireFichier(jFileChooser1.getSelectedFile());
    }//اگر
  }//btnCharger_actionPerformed

  // lireFichier
  private void lireFichier(File fichier){
     //محتویات فایل متنی 'fichier' را در فیلد متن نمایش میدهد

     // میدان متن را پاک میکند
    txtTexte.setText("");

     // دادههای برخی
    BufferedReader IN=null;
    String ligne=null;
    try{
      // فایل را در حالت فقط خواندنی باز میکند
      IN=new BufferedReader(new FileReader(fichier));
      // فایل را خط به خط میخواند
      while((ligne=IN.readLine())!=null){
        txtTexte.append(ligne+"\n");
      }//در حالی که
       // بستن فایل
      IN.close();
    }catch(Exception ex){
       // یک خطا رخ داده است
      txtTexte.setText(""+ex);
    }//catch
  }

  //پاک کردن
  void btnEffacer_actionPerformed(ActionEvent e) {
    // پاک کردن کادر متن
    txtTexte.setText("");
  }

   // ذخیره
  void btnSauvegarder_actionPerformed(ActionEvent e) {
     // محتویات کادر متن را در یک فایل ذخیره میکند

     // تنظیم فیلتر اولیه
    jFileChooser1.setFileFilter(filtreTxt);
     // نمایش پنجرهٔ انتخاب ذخیره
    int returnVal = jFileChooser1.showSaveDialog(this);
    // آیا کاربر چیزی را انتخاب کرده است؟
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // نوشتن محتویات کادر متن در یک فایل
       écrireFichier(jFileChooser1.getSelectedFile());
    }//اگر
  }

   // lireFichier
  private void écrireFichier(File fichier){
     // محتویات کادر متن را به یک فایل مینویسد

     // دادههایی
    PrintWriter PRN=null;
    try{
       // فایل را برای نوشتن باز میکند
      PRN=new PrintWriter(new FileWriter(fichier));
      //محتویات کادر متن را مینویسد
      PRN.print(txtTexte.getText());
       // فایل را میبندد
      PRN.close();
    }catch(Exception ex){
       //یک خطا رخ داده است
      txtTexte.setText(""+ex);
    }//catch
  }

ما در مورد کد متدهای btnEffacer_Click، lireFichier و écrireFichier توضیحی ارائه نمی‌دهیم، زیرا آن‌ها چیزی را معرفی نمی‌کنند که قبلاً پوشش داده نشده باشد. ما بر کلاس JFileChooser و نحوه استفاده از آن تمرکز خواهیم کرد. این کلاس پیچیده و نسبتاً درهم‌تنیده است. در اینجا، ما فقط از متدهای زیر استفاده می‌کنیم:

addChoosableFilter(FileFilter)
انواع فایل‌های در دسترس برای انتخاب را تعیین می‌کند
setAcceptAllFileFilterUsed(boolean)
مشخص می‌کند که آیا گزینه «تمام فایل‌ها» باید برای انتخاب ارائه شود یا خیر
File getSelectedFile()
فایل (File) انتخاب‌شده توسط کاربر
int showSaveDialog()
متدی که کادر محاوره‌ای ذخیره را نمایش می‌دهد. مقداری از نوع int را برمی‌گرداند. مقدار jFileChooser.APPROVE_OPTION نشان می‌دهد که کاربر یک انتخاب معتبر انجام داده است. در غیر این صورت، یا انتخاب را لغو کرده یا خطایی رخ داده است.
setCurrentDirectory
برای تنظیم دایرکتوری اولیه که کاربر از آن شروع به کاوش در سیستم فایل می‌کند
setFileFilter(FileFilter)
برای تنظیم فیلتر فعال

متد showSaveDialog یک کادر انتخاب مشابه شکل زیر را نمایش می‌دهد:

Image

1
لیست کشویی ایجادشده با استفاده از متد addChoosableFilter. این لیست شامل فیلترهای انتخابی است که توسط کلاس FileFilter نمایش داده می‌شوند. بر عهده توسعه‌دهنده است که این فیلترها را تعریف کرده و به لیست 1 اضافه کند.
۲
پوشهٔ جاری، که توسط متد setCurrentDirectory در صورت استفاده از این متد تنظیم می‌شود؛ در غیر این صورت، پوشهٔ جاری، پوشهٔ «My Documents» در ویندوز یا پوشهٔ خانگی در یونیکس خواهد بود.
۳
نام فایلی که توسط کاربر انتخاب یا مستقیماً وارد شده است. از طریق متد getSelectedFile() در دسترس خواهد بود.
4
دکمه‌های ذخیره/لغو. اگر دکمه Enregistrer استفاده شود، متد showSaveDialog نتیجه را به jFileChooser.APPROVE_OPTION بازمی‌گرداند

فیلترهای فایل برای لیست کشویی 1 چگونه ساخته می‌شوند؟ فیلترها با استفاده از متد زیر به لیست 1 اضافه می‌شوند:

addChoosableFilter(FileFilter)
انواع فایل‌های در دسترس برای انتخاب را تعیین می‌کند

از کلاس JFileChooser. ما همچنان باید کلاس FileFilter را درک کنیم. این در واقع کلاس javax.swing.filechooser.FileFilter است، که یک کلاس انتزاعی است، c.a.d – کلاسی که نمی‌توان آن را نمونه‌سازی کرد، بلکه فقط می‌توان از آن ارث برد. این به شرح زیر تعریف شده است:

FileFilter()
سازنده
boolean accept(File)
نشان می‌دهد که آیا فایل f به فیلتر تعلق دارد یا خیر
String getDescription()
رشتهٔ توصیف فیلتر

بیایید یک مثال بزنیم. ما می‌خواهیم لیست کشویی 1 فیلتری برای انتخاب فایل‌های *.txt با توضیح «فایل‌های متنی (*.txt)» ارائه دهد.

  • ما باید یک کلاس مشتق‌شده از کلاس FileFilter ایجاد کنیم
  • از متد بولین `accept(File f)` استفاده کنید تا در صورتی که نام فایل `f` با .txt پایان یابد، مقدار true را بازگردانید.
  • از متد String با نام getDescription() برای بازگرداندن توضیح «فایل‌های متنی (*.txt)» استفاده کنید

این فیلتر می‌تواند در برنامه ما به صورت زیر تعریف شود:

  javax.swing.filechooser.FileFilter filtreTxt = new javax.swing.filechooser.FileFilter(){
    public boolean accept(File f){
      //آیا باید f پذیرفته شود؟
      return f.getName().toLowerCase().endsWith(".txt");
    }//قبول
    public String getDescription(){
      // توضیحات فیلتر
      return "Fichiers Texte (*.txt)";
    }//getDescription
  };

این فیلتر با استفاده از عبارت زیر به لیست فیلترهای شیء jFileChooser1 اضافه می‌شود:

     // فیلتر *.txt اضافه می‌شود
    jFileChooser1.addChoosableFileFilter(filtretxt);

تمام این موارد، به همراه چند مقداردهی اولیه دیگر، در متد moreInit انجام می‌شود که هنگام ایجاد پنجره اجرا می‌گردد (به برنامه کامل بالا مراجعه کنید). کد دکمه Sauvegarder به شرح زیر است:

  void btnSauvegarder_actionPerformed(ActionEvent e) {
    // محتویات کادر متن را در یک فایل ذخیره می‌کند

     // تنظیم فیلتر اولیه
    jFileChooser1.setFileFilter(filtreTxt);
     // نمایش پنجرهٔ تأیید ذخیره
    int returnVal = jFileChooser1.showSaveDialog(this);
    //آیا کاربر چیزی را انتخاب کرده است؟
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      //محتویات کادر متن را در یک فایل می‌نویسد
       écrireFichier(jFileChooser1.getSelectedFile());
    }//اگر
  }

ترتیب عملیات به شرح زیر است:

  • فیلتر فعال روی *.txt تنظیم شده است تا کاربر بتواند عمدتاً این نوع فایل را جستجو کند. فیلتر «تمام فایل‌ها» نیز موجود است. این فیلتر در رویه moreInit اضافه شده است. بنابراین دو فیلتر وجود دارد.
  • کادر محاوره‌ای ذخیره نمایش داده می‌شود. در این نقطه، کنترل به کاربر واگذار می‌شود تا با استفاده از کادر محاوره‌ای، فایلی را از سیستم فایل انتخاب کند.
  • هنگامی که کاربر از کادر انتخاب خارج می‌شود، مقدار بازگشتی بررسی می‌شود تا مشخص شود که آیا متن باید ذخیره شود یا خیر. در صورت مثبت بودن پاسخ، باید در فایلی که از طریق متد getSelectedFile به دست آمده، ذخیره شود.

کد مربوط به دکمه «بارگذاری» بسیار شبیه کد دکمه «ذخیره» است.

  void btnCharger_actionPerformed(ActionEvent e) {
    // یک فایل را با استفاده از یک شیء JFileChooser انتخاب کنید

     // فیلتر اولیه را تنظیم کنید
    jFileChooser1.setFileFilter(filtreTxt);
     // جعبه‌ی انتخاب را نمایش دهید
    int returnVal = jFileChooser1.showOpenDialog(this);
    //آیا کاربر چیزی را انتخاب کرده است؟
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // قرار دادن فایل در فیلد متن
       lireFichier(jFileChooser1.getSelectedFile());
    }//اگر
  }//btnCharger_actionPerformed

دو تفاوت وجود دارد:

  • برای نمایش کادر محاوره‌ای انتخاب فایل، روش showOpenDialog به جای روش showSaveDialog استفاده می‌شود. کادر محاوره‌ای انتخاب نمایش‌داده‌شده مشابه کادری است که توسط روش showSaveDialog نمایش داده می‌شود.
  • اگر کاربر با موفقیت یک فایل را انتخاب کند، متد lireFichier فراخوانی می‌شود، نه متد écrireFichier.

5.4.1.1. جعبه‌های انتخاب JColorChooser و JFontChooser

ما با مثال قبلی ادامه می‌دهیم و دو دکمه جدید اضافه می‌کنیم:

Image

خیر.
نوع
name
نقش
۶
JButton
btnCouleur
برای تنظیم رنگ متن برای TextBox
7
JButton
btnPolice
برای تنظیم قلم برای TextBox

کامپوننت JColorChooser که یک انتخابگر رنگ را نمایش می‌دهد، را می‌توان در لیست کامپوننت‌های Swing برای JBuilder یافت:

Image

ما این کامپوننت را در پنجره طراحی، اما خارج از فرم قرار می‌دهیم. این کامپوننت در فرم قابل مشاهده نیست اما با این حال در لیست کامپوننت‌های پنجره موجود است:

Image

کلاس JColorChooser بسیار ساده است. ما با استفاده از متد int showDialog: انتخابگر رنگ را نمایش می‌دهیم:

ثابت Color
showDialog(Component component, String title, Color initialColor)
Component component
کامپوننت والد انتخابگر رنگ، معمولاً یک پنجره JFrame
رشته title
عنوان نمایش‌داده‌شده در نوار عنوان کادر انتخاب
رنگ intialColor
رنگ انتخاب‌شده در ابتدا در انتخابگر

اگر کاربر رنگی را انتخاب کند، متد یک رنگ را برمی‌گرداند؛ در غیر این صورت، مقدار null را برمی‌گرداند. کد مربوط به دکمه Couleur به شرح زیر است:

  void btnCouleur_actionPerformed(ActionEvent e) {
     // با استفاده از مؤلفه QZXW2HTMLCSkNvbG9yQ2hhcmdlcl9hY3Rpb25QZXJmb3JtZWQX رنگ متن را انتخاب کنید
    Color couleur;
    if((couleur=jColorChooser1.showDialog(this,"Choix d'une couleur",Color.BLACK))!=null){
       //تنظیم رنگ متن در کادر متن
      txtTexte.setForeground(couleur);
    }//if
  }

کلاس Color در java.awt.Color تعریف شده است. ثابت‌های مختلفی در آنجا تعریف شده‌اند، از جمله Color.BLACK برای رنگ سیاه. جعبه‌ی انتخاب نمایش‌داده‌شده به شرح زیر است

Image

جالب اینجاست که کتابخانهٔ Swing کلاسی برای انتخاب قلم ارائه نمی‌دهد. خوشبختانه منابع جاوا به‌صورت آنلاین در دسترس هستند. با جستجوی عبارت «JFontChooser» – که به نظر می‌رسد نام احتمالی چنین کلاسی باشد – چندین نتیجه قابل یافتن است. مثال زیر نشان می‌دهد چگونه JBuilder را برای استفاده از بسته‌هایی که در پیکربندی اولیه آن گنجانده نشده‌اند، پیکربندی کنیم.

پکیج بازیابی‌شده swingextras.jar نام دارد و در پوشه <jdk>\jre\lib\perso قرار گرفته است، که در آن <jdk> به مسیر نصب JDK مورد استفاده توسط JBuilder اشاره دارد. می‌توانست در هر جای دیگری قرار داده شود.

بیایید محتویات بسته SwingExtras.jar را بررسی کنیم:

Image

این شامل کد منبع جاوا برای کامپوننت‌های موجود در بسته است. همچنین خود کلاس‌ها را نیز در بر می‌گیرد:

Image

از این آرشیو، شایان ذکر است که کلاس JFontChooser در واقع با نام com.lamatek.swingextras.JFontChooser نامگذاری شده است. اگر مایل نیستید نام کامل را بنویسید، باید در ابتدای برنامه موارد زیر را بنویسید:

import com.lamatek.swingextras.*;

کامپایلر و ماشین مجازی جاوا این بسته جدید را چگونه پیدا خواهند کرد؟ در مورد استفاده مستقیم از JDK، این موضوع قبلاً توضیح داده شده است و خواننده می‌تواند جزئیات را در بخش مربوط به بسته‌های جاوا بیابد. در اینجا، روش استفاده با JBuilder را به تفصیل توضیح می‌دهیم. پکیج‌ها در منوی Options/Configure JDK پیکربندی می‌شوند:

Image

1
دکمه Modifier (۱) به شما امکان می‌دهد به JBuilder مشخص کنید که کدام JDK را استفاده کند. در این مثال، JBuilder نسخه ۱.۳.۱ از JDK را همراه خود آورده بود. وقتی JDK نسخه 1.4 منتشر شد، به‌طور جداگانه‌ای از JBuilder نصب شد و از دکمه Modifier برای دستور دادن به JBuilder استفاده شداکنون با مشخص کردن پوشه نصب JDK 1.4 از آن استفاده کنید
۲
پوشهٔ پایهٔ JDK که در حال حاضر توسط JBuilder استفاده می‌شود
۳
فهرست آرشیوهای جاوا (.jar) مورد استفاده توسط JBuilder. آرشیوهای بیشتری را می‌توان با استفاده از دکمه Ajouter (۴) اضافه کرد.
۴
دکمه Ajouter (۴) به شما امکان می‌دهد پکیج‌های جدیدی را اضافه کنید که JBuilder برای کامپایل و اجرای برنامه‌ها از آن‌ها استفاده خواهد کرد. در اینجا برای افزودن پکیج SwingExtras.jar (۵) استفاده شده است.

JBuilder اکنون به درستی برای استفاده از کلاس JFontChooser پیکربندی شده است. با این حال، برای استفاده صحیح از آن، به دسترسی به تعریف این کلاس نیاز داریم. آرشیو swingextras.jar حاوی فایل‌های HTML است که می‌توانیم برای این منظور استخراج کنیم. این کار غیرضروری است. مستندات جاوا که در فایل‌های .jar گنجانده شده است، مستقیماً از JBuilder قابل دسترسی است. برای این کار، باید زبانه Documentation (۶) را در بالا پیکربندی کنید. پنجره جدید زیر ظاهر می‌شود:

Image

دکمه Ajouter به شما امکان می‌دهد مشخص کنید که فایل SwingExtras.jar باید برای مستندات اسکن شود. پس از تأیید این موضوع، خواهید دید که واقعاً به مستندات SwingExtras.jar دسترسی دارید. این امر مزایای متعددی را ارائه می‌دهد:

  • اگر شروع به تایپ عبارت import کنیم
import com.lamatek.swingextras.*;

مشاهده خواهیم کرد که JBuilder راهنمایی ارائه می‌دهد:

Image

پکیج com.lamatek یافت شد.

  • اکنون، اگر به برنامه زیر نگاه کنیم:
import com.lamatek.swingextras.*;

public class test{
  JFontChooser jFontChooser1=null;
}  

اگر F1 را با کلیدواژه JFontChooser اجرا کنید، راهنمای این کلاس را دریافت می‌کنید:

Image

ما می‌توانیم در نوار وضعیت ۱ ببینیم که در واقع یک فایل HTML از بسته swingextras.jar در حال استفاده است. مثال نشان داده شده در بالا به اندازه کافی واضح است تا بتوانیم کد دکمه Police را در برنامه خود بنویسیم:

  void btnPolice_actionPerformed(ActionEvent e) {
    // انتخاب فونت متن با استفاده از کامپوننت JFontChooser
    jFontChooser1 = new JFontChooser(new Font("Arial", Font.BOLD, 12));
    if (jFontChooser1.showDialog(this, "Choix d'une police") == JFontChooser.ACCEPT_OPTION) {
      //تغییر فونت کادر متن
      txtTexte.setFont(jFontChooser1.getSelectedFont());
    }//if
  }

جعبه انتخاب نمایش‌داده‌شده توسط روش showDialog فوق به شرح زیر است:

Image

5.5. برنامه گرافیکی IMPOTS

ما به برنامه IMPOTS بازمی‌گردیم که قبلاً دو بار بررسی شده است. اکنون یک رابط گرافیکی به آن اضافه می‌کنیم:

Image

کنترل‌ها به شرح زیر هستند

خیر.
نوع
نام
نقش
1
JRadioButton
rdOui
در صورت متأهل بودن تیک خورده
2
JRadioButton
rdNon
تیک خورده در صورت متأهل نبودن
3
JSpinner
spinEnfants
تعداد فرزندان مؤدی
حداقل=0، حداکثر=20، گام=1
۴
JTextField
txtSalaire
حقوق سالانه مالیات‌دهنده به F
۵
JLabel
lblImpots
مبلغ مالیات پرداختنی
۶
JTextField
txtStatus
میدان پیام وضعیت – قابل ویرایش نیست

منو به شرح زیر است:

گزینهٔ اصلی
گزینهٔ ثانویه
نام
نقش
مالیات‌ها
   
 
ابتدایی‌سازی
mnuInitialiser
بارگذاری داده‌های مورد نیاز برای محاسبه از یک فایل متنی
 
محاسبه
mnuCalculer
پس از موجود و صحیح بودن تمام داده‌های لازم، مالیات قابل پرداخت را محاسبه می‌کند
 
پاک کردن
mnuEffacer
فرم را به وضعیت اولیهٔ خود بازمی‌گرداند
 
خروج
mnuQuitter
برنامه را می‌بندد

قوانین عملیاتی

  • منوی Calculer تا زمانی که فیلد حقوق پر نشود، مخفی می‌ماند
  • اگر هنگام اجرای محاسبه، مشخص شود که حقوق نادرست است، خطایی گزارش می‌شود:

Image

برنامه در زیر نشان داده شده است. این برنامه از کلاس impots که در فصل مربوط به کلاس‌ها ایجاد شده است، استفاده می‌کند. برخی از کدهای تولید شده به‌طور خودکار توسط JBuilder در اینجا بازتولید نشده‌اند.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
import java.util.*;
import javax.swing.event.*;

public class frmImpots extends JFrame {
  // اجزای پنجره
  JPanel contentPane;
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem mnuInitialiser = new JMenuItem();
  JMenuItem mnuCalculer = new JMenuItem();
  JMenuItem mnuEffacer = new JMenuItem();
  JMenuItem mnuQuitter = new JMenuItem();
  JLabel jLabel1 = new JLabel();
  JFileChooser jFileChooser1 = new JFileChooser();
  JTextField txtStatus = new JTextField();
  JRadioButton rdOui = new JRadioButton();
  JRadioButton rdNon = new JRadioButton();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSalaire = new JTextField();
  JLabel jLabel4 = new JLabel();
  JLabel jLabel5 = new JLabel();
  JLabel lblImpots = new JLabel();
  JLabel jLabel7 = new JLabel();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JSpinner spinEnfants=null;
  FileFilter filtreTxt=null;

   // ویژگی‌های کلاس
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;

   //چارچوب را بسازید
  public frmImpots() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     //سایر راه‌اندازی‌ها
    moreInit();
  }

   // ابتکاری فرم
  private void moreInit(){
     // منوی «حساب کردن» غیرفعال است
    mnuCalculer.setEnabled(false);
    // میدان‌های ورودی غیرفعال
    txtSalaire.setEditable(false);
    txtSalaire.setBackground(Color.WHITE);
    // میدان وضعیت
    txtStatus.setBackground(Color.WHITE);
    //چرخ‌وفلک فرزندان  بین ۰ و ۲۰ فرزند
    spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);
     // فیلتر *.txt برای لیست کشویی
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        //آیا 'f' پذیرفته می‌شود؟
        return f.getName().toLowerCase().endsWith(".txt");
      }//قبول
      public String getDescription(){
        // توضیحات فیلتر
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // ما فیلتر *.txt را اضافه می‌کنیم
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // ما همچنین یک فیلتر برای همه فایل‌ها می‌خواهیم
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // مخزن منبع را برای پوشه FileChooser تنظیم کنید
    jFileChooser1.setCurrentDirectory(new File("."));
  }//moreInit

   //کامپوننت را راه‌اندازی کنید
  private void jbInit() throws Exception  {

................

  }

   //جایگزین شد، بنابراین می‌توانیم هنگام بسته‌شدن پنجره خروج کنیم
  protected void processWindowEvent(WindowEvent e) {
.....................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    //خروج از برنامه
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // بارگذاری فایل داده
     // که با استفاده از کادر انتخاب JFileChooser1 انتخاب شده است
    jFileChooser1.setFileFilter(filtreTxt);
    if (jFileChooser1.showOpenDialog(this)!=JFileChooser.APPROVE_OPTION)
      return;
     // فایل انتخابی پردازش می‌شود
    try{
       // خواندن داده‌ها
      lireFichier(jFileChooser1.getSelectedFile());
       // ایجاد شیء 'impots'
      objImpots=new impots(limites,coeffr,coeffn);
       //تأیید
      txtStatus.setText("Données chargées");
       // حقوق قابل اصلاح است
      txtSalaire.setEditable(true);
       // دیگر امکان تغییر وجود ندارد
      mnuInitialiser.setEnabled(false);
    }catch(Exception ex){
       // مشکل
      txtStatus.setText("Erreur : " + ex.getMessage());
      //پایان
      return;
    }//catch
  }

  private void lireFichier(File fichier) throws Exception {
     // جدول‌های داده
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // باز کردن فایل برای خواندن
    BufferedReader IN=new BufferedReader(new FileReader(fichier));
    // فایل خط به خط خوانده می‌شود
     //آن‌ها به شکل limit coeffr coeffn هستند
    String ligne=null;
    int numLigne=0;           // شماره خط جاری
    while((ligne=IN.readLine())!=null){
      //یک خط دیگر
      numLigne++;
       // خط به فیلدها تقسیم می‌شود
      champs=ligne.split("\\s+");
       // ۳ فیلد؟
      if(champs.length!=3)
        throw new Exception("ligne " + numLigne + "erronée dans fichier des données");
       //سه فیلد را بازیابی کنید
       aLimites.add(champs[0]);
       aCoeffR.add(champs[1]);
       aCoeffN.add(champs[2]);
    }//در حالی که
     // بستن فایل
    IN.close();
     //داده‌ها را به آرایه‌های محدود منتقل می‌کند
    int n=aLimites.size();
    limites=new double[n];
    coeffr=new double[n];
    coeffn=new double[n];
    for(int i=0;i<n;i++){
      limites[i]=Double.parseDouble((String)aLimites.get(i));
      coeffr[i]=Double.parseDouble((String)aCoeffR.get(i));
      coeffn[i]=Double.parseDouble((String)aCoeffN.get(i));
    }//برای
  }

  void mnuCalculer_actionPerformed(ActionEvent e) {
    //محاسبه مالیات
     //بررسی حقوق
    int salaire=0;
    try{
      salaire=Integer.parseInt(txtSalaire.getText().trim());
      if(salaire<0) throw new Exception();
    }catch (Exception ex){
       // پیام خطا
      txtStatus.setText("Salaire incorrect. Recommencez");
       //تمرکز روی فیلد اشتباه
      txtSalaire.requestFocus();
       //بازگشت به رابط کاربری
      return;
    }
     // تعداد فرزندان
    Integer InbEnfants=(Integer)spinEnfants.getValue();
     // محاسبه مالیات
    lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),InbEnfants.intValue(),salaire));
     // پاک کردن پیام وضعیت
    txtStatus.setText("");
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
     // حقوق تغییر کرده است  منوی «حساب کردن» را به‌روزرسانی کنید
    mnuCalculer.setEnabled(! txtSalaire.getText().trim().equals(""));
  }

  void mnuEffacer_actionPerformed(ActionEvent e) {
    // پاک کردن فرم
    rdNon.setSelected(true);
    spinEnfants.getModel().setValue(new Integer(0));
    txtSalaire.setText("");
    mnuCalculer.setEnabled(false);
    lblImpots.setText("");
  }
}

در اینجا از کامپوننتی استفاده کرده‌ایم که تنها از نسخه ۱.۴ به بعد در JDK موجود است، یعنی JSpinner. این یک افزاینده است که در این مورد به کاربر اجازه می‌دهد تعداد فرزندان را تنظیم کند. این کامپوننت Swing در نوار کامپوننت‌های Swing نسخه JBuilder 6 که برای آزمایش استفاده شد، موجود نبود. این امر مانع از استفاده از آن نمی‌شود، هرچند کار کمی پیچیده‌تر از کامپوننت‌های موجود در نوار کامپوننت‌ها است. در واقع، کامپوننت JSpinner را نمی‌توان در زمان طراحی روی فرم قرار داد. این کار باید در زمان اجرا انجام شود. بیایید نگاهی به کدی بیندازیم که این کار را انجام می‌دهد:

     // چرخ‌فلک تعداد فرزندان – بین ۰ تا ۲۰ فرزند وارد کنید
    spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);

خط اول کامپوننت JSpinner را ایجاد می‌کند. این کامپوننت می‌تواند برای اهداف مختلف استفاده شود، نه فقط به‌عنوان یک شمارشگر عدد صحیح همان‌طور که در اینجا نشان داده شده است. آرگومان سازنده JSpinner یک قالب افزایش‌دهنده عدد است که چهار پارامتر (value، min، max، increment) را می‌پذیرد. این کامپوننت به شکل زیر است:

Image

valeur
مقدار اولیه نمایش داده شده در کامپوننت
min
حداقل مقداری که می‌تواند در کامپوننت نمایش داده شود
max
حداکثر مقداری که می‌تواند در مؤلفه نمایش داده شود
incrément
مقدار افزایشی برای مقدار نمایش‌داده‌شده هنگام استفاده از فلش‌های بالا/پایین کامپوننت

مقدار کامپوننت از طریق متد آن getValue به دست می‌آید که نوع Object را برمی‌گرداند. بنابراین، برای به دست آوردن عدد صحیح مورد نیاز، به چند تبدیل نوع نیاز است:

     //تعداد فرزندان
    Integer InbEnfants=(Integer)spinEnfants.getValue();
     //محاسبه مالیات
    lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),
      InbEnfants.intValue(),salaire));

پس از تعریف کامپوننت JSpinner، در پنجره قرار داده می‌شود:

    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);

ابتدا، کاربر باید از گزینه منوی Initialiser استفاده کند که با استفاده از سازنده، یک شیء impots ایجاد می‌کند

    public impots(double[] LIMITES, double[] COEFFR, double[] COEFFN) throws Exception

از کلاس impots. توجه داشته باشید که این کلاس به‌عنوان یک مثال در فصل مربوط به کلاس‌ها تعریف شده است. در صورت نیاز به آن فصل مراجعه کنید. سه آرایه مورد نیاز سازنده با استفاده از محتویات یک فایل متنی با فرمت زیر پر می‌شوند:

12620.0
0
0
13190
0.05
۶۳۱
۱۵٬۶۴۰
0.1
۱٬۲۹۰٫۵
۲۴٬۷۴۰
0.15
۲٬۰۷۲٫۵
۳۱٬۸۱۰
0.2
۳٬۳۰۹٫۵
۳۹٬۹۷۰
0.25
۴٬۹۰۰
۴۸٬۳۶۰
0.3
۶۸۹۸.۵
۵۵٬۷۹۰
0.35
۹٬۳۱۶٫۵
۹۲٬۹۷۰
0.4
۱۲٬۱۰۶
۱۲۷٬۸۶۰
0.45
۱۶٬۷۵۴٫۵
۱۵۱٬۲۵۰
0.50
۲۳٬۱۴۷٫۵
۱۷۲٬۰۴۰
0.55
۳۰٬۷۱۰
۱۹۵٬۰۰۰
0.60
۳۹٬۳۱۲
0
0.65
۴۹٬۰۶۲

هر خط شامل سه عدد است که با حداقل یک فاصله از هم جدا شده‌اند. این فایل متنی توسط کاربر با استفاده از کامپوننت JFileChooser انتخاب می‌شود. پس از ایجاد شیء impots، تنها کاری که باقی می‌ماند این است که به کاربر اجازه دهید سه اطلاعات مورد نیاز را وارد کند: وضعیت تأهل، تعداد فرزندان و حقوق سالانه، و سپس متد calculer از کلاس impots را فراخوانی کند. این عملیات را می‌توان چندین بار تکرار کرد. با این حال، شیء از نوع impots تنها یک بار، زمانی که گزینه Initialiser استفاده می‌شود، ایجاد می‌گردد.

5.6. نوشتن اپلت‌ها

5.6.1. مقدمه

پس از اینکه یک برنامه با رابط کاربری گرافیکی نوشتید، تبدیل آن به applet نسبتاً ساده است. این برنامه که روی ماشین A ذخیره شده، می‌تواند از طریق یک مرورگر وب از ماشین B از طریق اینترنت دانلود شود. بدین ترتیب، برنامهٔ اصلی در میان کاربران زیادی به اشتراک گذاشته می‌شود و این مزیت اصلی تبدیل یک برنامه به یک اپلت است. با این حال، هر برنامه‌ای را نمی‌توان به این روش تبدیل کرد: برای اطمینان از اینکه کاربرانی که اپلت را در مرورگر خود اجرا می‌کنند با مشکل مواجه نشوند، محیط اپلت محدود شده است:

  • یک اپلت نمی‌تواند از هارد دیسک کاربر بخواند یا روی آن بنویسد
  • این اپلت تنها می‌تواند با ماشینی که از طریق مرورگر از آن دانلود شده است، ارتباط برقرار کند.

این‌ها محدودیت‌های قابل توجهی هستند. این بدان معناست که برای مثال، یک برنامه‌ای که نیاز به خواندن اطلاعات از یک فایل یا پایگاه داده دارد، باید آن را از طریق یک برنامه واسط که روی سروری که از آن دانلود شده قرار دارد، درخواست کند.

ساختار کلی یک برنامه وب ساده به شرح زیر است:

Image

  • کلاینت یک سند HTML را معمولاً از طریق یک مرورگر از وب‌سرور درخواست می‌کند. این سند ممکن است حاوی یک اپلت باشد که به‌عنوان یک برنامه گرافیکی مستقل در داخل سند HTML نمایش‌داده‌شده توسط مرورگر کلاینت عمل خواهد کرد.
  • این اپلت قادر به دسترسی به داده‌ها خواهد بود، اما فقط به داده‌هایی که در سرور وب قرار دارند. این اپلت به منابع روی ماشین کلاینتی که آن را اجرا می‌کند، و همچنین به منابع روی سایر ماشین‌های شبکه به غیر از ماشینی که از آن دانلود شده است، دسترسی نخواهد داشت.

5.6.2. کلاس JApplet

5.6.2.1. Définition

یک برنامه کاربردی می‌تواند توسط یک مرورگر وب دانلود شود اگر یک نمونه از کلاس java.applet.Applet یا کلاس javax.swing.JApplet باشد. دومی از اولی مشتق شده است، که خود از کلاس Panel مشتق شده است، که خود از کلاس Container مشتق شده است. از آنجایی که یک نمونه از Applet یا JApplet از نوع container است، بنابراین ممکن است حاوی کامپوننت‌ها (Component) مانند دکمه‌ها، چک‌باکس‌ها، لیست‌ها و غیره باشد. در اینجا چند راهنما در مورد نقش روش‌های مختلف آورده شده است:

متد
نقش
public void destroy();
نابود کردن نمونهٔ آلت‌افزار
public AppletContext getAppletContext();
زمینهٔ اجرای اپلت را بازیابی می‌کند (سند HTML که اپلت در آن قرار دارد، اپلت‌های دیگر در همان سند و غیره)
public String getAppletInfo();
یک رشته حاوی اطلاعات دربارهٔ اپلت را بازمی‌گرداند
public AudioClip getAudioClip(URL url);
فایل صوتی مشخص‌شده توسط URL را بارگذاری می‌کند
public AudioClip getAudioClip(URL url, String name);
فایل صوتی مشخص‌شده توسط URL/name را بارگذاری می‌کند
public URL getCodeBase();
بازگرداندن URL آلت‌افزار
عمومی URL getDocumentBase();
بازگرداندن URL از سند HTML حاوی اپلت
public Image getImage(URL url);
تصویر مشخص‌شده توسط URL را بازیابی می‌کند
public Image getImage(URL url, String name);
تصویر مشخص‌شده توسط URL/name را بازیابی می‌کند
public String getParameter(String name);
مقدار پارامتر name را که در تگ <applet> سند HTML حاوی اپلت قرار دارد، بازیابی می‌کند.
public void init();
این متد توسط مرورگر زمانی فراخوانی می‌شود که اپلت برای اولین بار اجرا می‌شود
public boolean isActive();
وضعیت اپلت
public void play(URL url);
فایل صوتی مشخص‌شده توسط URL را پخش می‌کند
public void play(URL url, String name);
پخش فایل صوتی مشخص‌شده توسط UR/name
public void resize(Dimension d);
اندازه قاب اپلت را تعیین می‌کند
public void resize(int width, int height);
همانند بالا
public final void setStub(AppletStub stub);
 
public void showStatus(String msg);
یک پیام را در نوار وضعیت اپلت نمایش می‌دهد
public void start();
این متد هر بار که سند حاوی اپلت نمایش داده می‌شود، توسط مرورگر فراخوانی می‌شود
public void stop();
این متد توسط مرورگر هر زمان که سند حاوی اپلت به نفع سند دیگری رها شود، فراخوانی می‌شود (کاربر از URL خارج می‌شود)

کلاس JApplet تعدادی بهبود را نسبت به کلاس Applet ارائه کرده است، به‌ویژه قابلیت شامل شدن کامپوننت‌های JMenuBar و c.a.d. موارد منو، که با کلاس Applet امکان‌پذیر نبود.

5.6.2.2. اجرای یک اپلت: متدهای init، start و stop

وقتی یک مرورگر یک اپلت را بارگذاری می‌کند، سه متد آن را فراخوانی می‌کند:

init
این متد زمانی فراخوانی می‌شود که اپلت برای اولین بار بارگذاری می‌شود. بنابراین باید شامل inizializاسیون‌های لازم برای برنامه باشد.
start
این متد هرگاه سند حاوی اپلت به سند جاری مرورگر تبدیل شود، فراخوانی می‌شود. بنابراین، وقتی کاربر یک اپلت را بارگذاری می‌کند، متدهای init و start به ترتیب اجرا خواهند شد. وقتی کاربر سند را ترک می‌کند تا سند دیگری را مشاهده کند، متد stop اجرا می‌شود. وقتی بعداً به آن بازمی‌گردد، متد start اجرا خواهد شد.
stop
این متد هر زمان که کاربر سند حاوی اپلت را ترک می‌کند، فراخوانی می‌شود.

برای بسیاری از اپلت‌ها، تنها متد init لازم است. متدهای start و stop تنها در صورتی ضروری هستند که برنامه وظایفی (تراکنش‌ها) را راه‌اندازی کند که به طور موازی و مداوم اجرا می‌شوند، اغلب بدون اطلاع کاربر. وقتی کاربر سند را ترک می‌کند، بخش قابل مشاهده برنامه ناپدید می‌شود، اما این وظایف پس‌زمینه به اجرای خود ادامه می‌دهند. این اغلب غیرضروری است. بنابراین برای متوقف کردن آنها از فراخوانی متد **stop** توسط مرورگر استفاده می‌کنیم. اگر کاربر به سند بازگردد، برای راه‌اندازی مجدد آنها از فراخوانی متد **start** توسط مرورگر استفاده می‌کنیم.

برای مثال، یک اپلت را در نظر بگیرید که در رابط کاربری گرافیکی خود یک ساعت دارد. این ساعت توسط یک وظیفه پس‌زمینه (ترد) نگهداری می‌شود. هنگامی که کاربر صفحه اپلت را در مرورگر ترک می‌کند، ادامه دادن به نمایش ساعت که اکنون نامرئی شده است، بی‌فایده است: در متد **stop** اپلت، ما تردی را که ساعت را مدیریت می‌کند، متوقف می‌کنیم. در متد **start**، آن را مجدداً راه‌اندازی می‌کنیم تا وقتی کاربر به صفحه اپلت بازمی‌گردد، ساعتی را ببیند که به‌روز است.

5.6.3. تبدیل یک برنامه گرافیکی به یک اپلت

ما در اینجا فرض می‌کنیم که این تبدیل امکان‌پذیر است، یعنی با محدودیت‌های اجرای اپلِت مطابقت دارد. یک برنامه با متد main یکی از کلاس‌های آن راه‌اندازی می‌شود:


public class application{
    
    public static main void(String arg[]){
        
    }
    
}// پایان پرانتز

چنین برنامه‌ای به صورت زیر به یک اپلت تبدیل می‌شود:

import java.applet.JApplet;

public class application extends JApplet{
    
    public void init(){
        
    }
    
}// پایان کلاس

لطفاً به نکات زیر توجه کنید:

  1. کلاس application اکنون از کلاس JApplet ارث می‌برد
  2. متد main با متد init جایگزین شده است.

به‌عنوان مثال، بیایید نگاهی دوباره به برنامه‌ای که قبلاً بررسی کرده‌ایم بیندازیم: مدیریت فهرست.

Image

اجزای این پنجره به شرح زیر است:

خیر.
نوع
نام
نقش
1
JTextField
txtSaisie
میدان ورودی
2
JList
jList1
لیست قرار گرفته در داخل یک کانتینر jScrollPane1
3
JList
jList2
فهرست موجود در یک کانتینر jScrollPane2
4
JButton
cmd1To2
موارد انتخاب‌شده را از لیست ۱ به لیست ۲ منتقل می‌کند
5
JButton
cmd2To1
معکوس آن را انجام می‌دهد
۶
JButton
cmdRaz1
فهرست 1 را پاک کنید
7
JButton
cmdRaz2
پاک کردن فهرست ۲

ساختار برنامه به شرح زیر بود:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**چارچوب را بسازید*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**ابتدایی‌سازی مؤلفه*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         //Jlist1 در کانتینر jScrollPane1 قرار می‌گیرد
    jScrollPane1.getViewport().add(jList1, null);
        //Jlist2 در کانتینر jScrollPane2 قرار داده شده است
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**جایگزین شد، تا بتوانیم هنگام بستن پنجره خارج شویم*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
.............
}//کلاس
  void cmd1To2_actionPerformed(ActionEvent e) {
..........
  }//انتقال
  void cmdRaz1_actionPerformed(ActionEvent e) {
    // فهرست 1 را پاک کنید
    v1.removeAllElements();
  }//cmd Reset1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // فهرست ۲ را پاک کنید
    v2.removeAllElements();
  }///cmd Clear2

برای تبدیل کلاس appli به applet، مراحل زیر را انجام دهید:

  • کلاس قبلی interfaceAppli را طوری اصلاح کنید که دیگر از JFrame ارث‌بری نکند، بلکه از JApplet ارث‌بری کند:
public class interfaceAppli extends JApplet {
  • دستور تعیین عنوان پنجره JFrame را حذف کنید. یک اپلِت JApplet نوار عنوان ندارد.
    // QZXW2HTMLCdGhpcy.zZXRUaXRsZQZQX("JList");
  • سازنده را به یک متد (init) تبدیل کنید و در داخل این متد، رسیدگی به رویدادهای پنجره (WindowListener, ...) را حذف کنید. یک اپلکت یک کانتینر است که نمی‌توان آن را تغییر اندازه داد یا بست.
   /**ساخت فریم*/
  public init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli
  • روش processWindowEvent باید حذف یا غیرفعال شود
   /**جایگزین شده، تا بتوانیم هنگام بستن پنجره خارج شویم*/
  //protected void processWindowEvent(WindowEvent e) {
  //  super.processWindowEvent(e);
  //  if (e.getID() == WindowEvent.WINDOW_CLOSING) {
  //    System.exit(0);
  //  }
  // }

به‌عنوان مثال، در اینجا کد کامل اپلت آورده شده است، به استثنای بخشی که به‌طور خودکار توسط JBuilder تولید می‌شود.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceAppli extends JApplet {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**چارچوب را بسازید*/
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**ابتدایی‌سازی مؤلفه*/
  private void jbInit() throws Exception  {
    //setIconImage(Toolkit.getDefaultToolkit().createImage(interfaceAppli.class.getResource("[Votre icône]")));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(400, 308));
    // this.setTitle("JList");
    jScrollPane1.setBounds(new Rectangle(37, 133, 124, 101));
    jScrollPane2.setBounds(new Rectangle(232, 132, 124, 101));
.............
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
     // متن وارد شده اعتبارسنجی شده است
     // متن وارد شده با حذف فاصله‌های ابتدایی و انتهایی بازیابی می‌شود
    String texte=txtSaisie.getText().trim();
     // اگر خالی باشد، آن را نمی‌خواهیم
    if(texte.equals("")){
      // پیام خطا
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      //پایان
      return;
    }//اگر
    // اگر خالی نباشد، آن را به مقادیر لیست 1 اضافه کنید
    v1.addElement(texte);
     // و فیلد ورودی را پاک کنید
    txtSaisie.setText("");
  }

  void cmd1To2_actionPerformed(ActionEvent e) {
    //انتقال موارد انتخاب‌شده از لیست ۱ به لیست ۲
    transfert(jList1,jList2);
  }//cmd1To2

  private void transfert(JList L1, JList L2){
      //انتقال موارد انتخاب‌شده از فهرست 1 به فهرست 2
       //بازیابی آرایهٔ شاخص‌ها برای موارد انتخاب‌شده در L1
      int[] indices=L1.getSelectedIndices();
      // آیا کاری با آن دارد؟
      if (indices.length==0) return;
      // مقادیر را از L1 بازیابی می‌کند
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      //و آن‌هایی از L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // ما مقادیر انتخاب‌شده از L1 را به L2 اضافه می‌کنیم
        v2.addElement(v1.elementAt(indices[i]));
        // عناصر از L1 که به L2 کپی شده‌اند باید از L1 حذف شوند
        v1.removeElementAt(indices[i]);
      }//برای
  }//انتقال

  private void affiche(String message){
    //پیامی را نمایش می‌دهد
      JOptionPane.showMessageDialog(this,message,
        "Suivi",JOptionPane.INFORMATION_MESSAGE);
  }//نمایش می‌دهد

  void cmd2To1_actionPerformed(ActionEvent e) {
    //آیتم‌های انتخاب‌شده را از jList2 به jList1 منتقل می‌کند
      transfert(jList2,jList1);
  }//cmd2TO1

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // پاک کردن لیست ۱
    v1.removeAllElements();
  }//فرمان Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // فهرست خالی ۲
    v2.removeAllElements();
  }//cmd Clear2

}//کلاس

کد منبع این اپلِت قابل کامپایل است. ما این کار را در اینجا با استفاده از JDK انجام می‌دهیم، بدون JBuilder.

E:\data\serge\Jbuilder\interfaces\JApplets\1>javac.bat interfaceAppli.java

E:\data\serge\Jbuilder\interfaces\JApplets\1>dir
12/06/2002  16:40                6 148 interfaceAppli.java
12/06/2002  16:41                  527 interfaceAppli$1.class
12/06/2002  16:41                  525 interfaceAppli$2.class
12/06/2002  16:41                  525 interfaceAppli$3.class
12/06/2002  16:41                  525 interfaceAppli$4.class
12/06/2002  16:41                  525 interfaceAppli$5.class
12/06/2002  16:41                4 759 interfaceAppli.class

این برنامه را می‌توان با استفاده از برنامه AppletViewer از JDK آزمایش کرد، که امکان اجرای اپلکت‌ها یا یک مرورگر را فراهم می‌کند. برای این کار، باید سند HTML appli.htm را ایجاد کنید که شامل اپلت خواهد بود:

<html>
    <head>
        <title>listes swing</title>
    </head>
    <body>
        <applet 
        code="interfaceAppli.class"
      width="400"
      height="300">
        </applet>
    </body>
</html>

این یک سند استاندارد HTML است، اگر نه به خاطر وجود تگ applet. این تگ با سه پارامتر استفاده شده است:

code="interfaceAppli.class"
نام کلاس کامپایل‌شده JAVA که برای اجرای اپلِت بارگذاری می‌شود
width="400"
عرض قاب اپلت در داخل سند
height="300"
ارتفاع قاب اپلِت در داخل سند

پس از نوشتن فایل appli.htm، می‌توان آن را با استفاده از برنامه appletviewer از JDK یا از طریق یک مرورگر وب بارگذاری کرد. در یک پنجره DOS، دستور زیر را در پوشه‌ای که حاوی فایل appli.htm است تایپ کنید:

appletviewer appli.htm

ما در اینجا فرض می‌کنیم که دایرکتوری حاوی فایل اجرایی appletviewer.exe در دایرکتوری PATH نشان داده شده در پنجره DOS قرار دارد؛ در غیر این صورت، باید مسیر کامل فایل اجرایی appletviewer.exe را مشخص کنید. پنجره زیر ظاهر می‌شود:

Image

اجرای اپلِت را با استفاده از گزینه Applet/Quitter متوقف کنید. اکنون بیایید اپلت را با استفاده از یک مرورگر وب آزمایش کنیم. مرورگر باید از یک ماشین مجازی جاوا 2 استفاده کند تا بتواند کامپوننت‌های Swing را نمایش دهد. تا همین اواخر (۲۰۰۱)، این الزام یک مشکل بود زیرا شرکت Sun نسخه‌های JDK را تولید می‌کرد که فروشندگان مرورگر در پذیرش آن‌ها بسیار کند عمل می‌کردند. سرانجام شرکت Sun با ارائه برنامه‌ای به نام «پلاگین جاوا» به کاربران، این مشکل را حل کرد. این برنامه به Internet Explorer و Netscape Navigator امکان می‌دهد تا از جدیدترین نسخه‌های JRE تولید شده توسط Sun (JRE = محیط اجرایی جاوا) استفاده کنند. آزمایش‌های زیر با استفاده از IE نسخهٔ ۵.۵ همراه با افزونهٔ جاوا ۱.۴ انجام شدند.

یک روش برای آزمایش اپلت interfaceAppli.class این است که فایل HTML appli.htm را با دوبار کلیک کردن مستقیماً در مرورگر بارگذاری کنید. مرورگر سپس صفحه HTML و اپلِت آن را بدون نیاز به وب‌سرور نمایش خواهد داد:

Image

از URL (1) می‌توان دید که فایل مستقیماً در مرورگر بارگذاری شده است. در مثال زیر، فایل appli.htm از یک سرور وب آپاچی که روی پورت 81 در ماشین محلی در حال اجرا است، درخواست شده است:

Image

5.6.4. گزینه قالب‌بندی <applet> در یک سند HTML

ما دیده‌ایم که در یک سند HTML، اپلت توسط دستور قالب‌بندی (برچسب) <applet> ارجاع می‌شود. این دستور می‌تواند پارامترهای مختلفی داشته باشد:

<applet
    code=
    width=
    height=
    codebase=
    align=
    hspace=
    vspace=
alt=
>
    <param name1=nom1 value=val1>
    <param name2=nom2 value=val2>
    texte
>
</applet>

پارامترها معانی زیر را دارند:

پارامتر
معنی
code
الزامی – نام فایل .class که باید اجرا شود
width
الزامی – عرض اپلت در داخل سند
height
الزامی – ارتفاع …
codebase
اختیاری – URL مسیر دایرکتوری حاوی اپلت قابل اجرا. اگر 'codebase' مشخص نشود، اپلت در دایرکتوری سند HTML که به آن ارجاع داده شده است جستجو خواهد شد
align
اختیاری – موقعیت‌یابی (LEFT, RiGHT, CENTER) آلت در داخل سند
hspace
اختیاری – حاشیه افقی اطراف اپلت، بیان‌شده به پیکسل
vspace
اختیاری – حاشیه عمودی اطراف اپلت، بیان‌شده به پیکسل
alt
اختیاری – متنی که در صورت عدم بارگذاری اپلت توسط مرورگر، به جای آن نمایش داده شود
param
اختیاری – پارامتر ارسال‌شده به اپلت که نام (name) و مقدار (value) آن را مشخص می‌کند. اپلت می‌تواند مقدار پارامتر 'name1' را با استفاده از 'val1=getParameter("name1")' بازیابی کند.
می‌توانید هر تعداد پارامتر که می‌خواهید استفاده کنید
texte
اختیاری – توسط هر مرورگری که قادر به اجرای یک اپلِت نیست، نمایش داده می‌شود، برای مثال به این دلیل که ماشین مجازی جاوا ندارد.

بیایید برای روشن شدن نحوه ارسال پارامترها به یک اپلت، یک مثال بزنیم:

<html>
    <head>
        <title>paramètres applet</title>
    </head>
    <body>
        <applet code="interfaceParams.class" width="400" height="300">
      <param name="param1" value="val1">
      <param name="param2" value="val2">      
        </applet>
    </body>
</html>

کد جاوا برای اپلت interfaceParams همان‌طور که در بالا توضیح داده شد تولید شد. ما یک برنامه JBuilder ساختیم و سپس چند تغییر ذکرشده در بالا را اعمال کردیم:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceParams extends JApplet {
  JPanel contentPane;
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel1 = new JLabel();
  DefaultListModel params=new DefaultListModel();
  JList lstParams = new JList(params);

  //ساخت قاب
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // ابتکارات دیگر
    moreInit();
  }

   // ابتدایی‌سازی‌ها
  public void moreInit(){
     //مقادیر پارامترهای اپلت را نمایش می‌دهد
    params.addElement("nom=param1 valeur="+getParameter("param1"));
    params.addElement("nom=param2 valeur="+getParameter("param2"));
  }//initهای بیشتر

   //کامپوننت را инициалиزه کنید
  private void jbInit() throws Exception  {
............
    this.setSize(new Dimension(205, 156));
    //this.setTitle("پارامترهای آپلِت");
    jScrollPane1.setBounds(new Rectangle(19, 53, 160, 73));
............
 }
}

خروجی برای AppletViewer:

Image

5.6.5. دسترسی به منابع راه دور از یک اپلت

بسیاری از برنامه‌ها نیاز دارند از اطلاعات موجود در فایل‌ها یا پایگاه‌های داده استفاده کنند. ما اشاره کرده‌ایم که یک اپلت به منابع ماشینی که روی آن اجرا می‌شود دسترسی ندارد. این یک اقدام منطقی است. در غیر این صورت، می‌توان یک اپلت نوشت که بر هارد دیسک کسانی که آن را بارگذاری می‌کنند «جاسوسی» کند. با این حال، اپلت به منابعی که از سرور دانلود شده است، مانند فایل‌ها، دسترسی دارد. این چیزی است که اکنون به آن خواهیم پرداخت.

5.6.5.1. کلاس URL

هر برنامه جاوا می‌تواند با استفاده از کلاس java.net.URL (URL = مکان‌یاب یکنواخت منبع) یک فایل را که روی یک ماشین در شبکه قرار دارد، بخواند. یک URL یک منبع شبکه، ماشینی که روی آن قرار دارد، و پروتکل ارتباطی و پورت مورد استفاده برای بازیابی آن را به شکل زیر مشخص می‌کند:

پروتکل:پورت//ماشین/فایل

بنابراین، URL http://www.ibm.com/index.html به فایل index.html روی ماشین www.ibm.com اشاره می‌کند. این فایل از طریق پروتکل http قابل دسترسی است. پورت مشخص نشده است: مرورگر از پورت ۸۰ استفاده خواهد کرد که پورت پیش‌فرض سرویس HTTP است.

بیایید به برخی از عناصر کلاس URL نگاهی بیندازیم:

public URL(String spec)
یک نمونه از URL را از یک رشته به شکل «پروتکل:پورت//ماشین/فایل» ایجاد می‌کند – در صورتی که نحو رشته با URL مطابقت نداشته باشد، یک استثنا پرتاب می‌کند
  
public String getFile()
میدان 'file' را از رشته «protocol:port//machine/file» برای URL بازیابی می‌کند
  
public String getHost()
میدان 'machine' را از رشته «protocol:port//machine/file» در URL بازیابی می‌کند
  
public String getPort()
میدان پورت را از رشته "protocol:port//machine/file" در URL بازیابی می‌کند
  
public String getProtocol()
میدان پروتکل را از رشته "protocol:port//machine/file" در URL بازیابی می‌کند
  
public URLConnection openConnection()
یک اتصال به ماشین راه دور getHost() را روی پورت آن getPort() با استفاده از پروتکل getProtocol() برای خواندن فایل getFile() باز می‌کند. در صورتی که اتصال برقرار نشود، یک استثنا پرتاب می‌کند
  
public final InputStream openStream()
کوته‌راهی برای openConnection().getInputStream(). یک جریان ورودی را به‌دست می‌آورد که از آن می‌توان محتوای فایل getFile() را خواند. اگر نتوان جریان را به‌دست آورد، یک استثنا پرتاب می‌کند
  
public String toString()
هویت نمونه URL را نمایش می‌دهد

در اینجا دو متد مورد توجه وجود دارد:

  • public URL(String spec) برای مشخص کردن فایلی که باید پردازش شود
  • public final InputStream openStream() برای پردازش آن

5.6.5.2. یک مثال کنسولی

ما قصد داریم یک برنامهٔ جاوا بدون رابط کاربری گرافیکی بنویسیم که برای نمایش محتویات یک فایل URL که به‌عنوان پارامتر به آن ارسال می‌شود، روی صفحه طراحی شده است. یک مثال از فراخوانی ممکن است به شکل زیر باشد:

    DOS> java urlcontenu http://istia.univ-angers.fr/index.html

برنامه نسبتاً ساده است:


import java.net.*;             //برای کلاس URL
import java.io.*;                //برای استریم‌ها

public class urlcontenu{

// محتوای URL را که به‌عنوان آرگومان ارسال شده است نمایش می‌دهد
//این محتوا باید متن باشد تا قابل خواندن باشد

  public static void main (String arg[]){
    //بررسی آرگومان‌ها
    if(arg.length==0){
      System.err.println("Syntaxe pg url");
      System.exit(0);
    }
    
    try{
      // ایجاد URL      
      URL url=new URL(arg[0]);
      // خواندن محتوا
      try{
        // ایجاد جریان ورودی
        BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
        try{
          //خواندن خطوط متن از جریان ورودی
          String ligne;
          while((ligne=is.readLine())!=null)
            System.out.println(ligne);
        } catch (Exception e){
            System.err.println("Erreur lecture : " +e);
        }
        finally{
          try { is.close(); } catch (Exception e) {}
        }
      } catch (Exception e){
          System.err.println("Erreur openStream : " +e);
      }
    } catch (Exception e){
      System.err.println("Erreur création URL : " +e);
    }
  }//پایان کلاس اصلی
}//پایان کلاس

پس از بررسی وجود یک آرگومان، ما تلاش می‌کنیم با استفاده از آن یک URL ایجاد کنیم:


// ایجاد URL      
      URL url=new URL(arg[0]);

این ایجاد ممکن است در صورتی که آرگومان با نحو URL protocole:port//machine/fichier مطابقت نداشته باشد، ناموفق باشد. اگر یک URL از نظر نحوی صحیح داشته باشیم، سعی می‌کنیم یک استریم ورودی ایجاد کنیم که بتوانیم از آن خطوط متن را بخوانیم. جریان ورودی ارائه‌شده توسط تابع URL URL.openStream() یک جریان از نوع InputStream را بازمی‌گرداند که یک جریان مبتنی بر کاراکتر است: خواندن به صورت کاراکتر به کاراکتر انجام می‌شود و شما باید خطوط را خودتان تشکیل دهید. برای خواندن خطوط متن، باید از متد readLine کلاس‌های BufferedReader یا DataInputStream.On استفاده کنید؛ در اینجا، BufferedReader انتخاب شده است. تنها کاری که باقی مانده تبدیل جریان InputStream از URL به یک جریان BufferedReader است. این کار با ایجاد یک جریان واسط، InputStreamReader انجام می‌شود:


BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));

ایجاد این جریان ممکن است با شکست مواجه شود. ما با خطای متناظر آن مقابله می‌کنیم. پس از به‌دست آمدن جریان، تنها کاری که باقی می‌ماند خواندن خطوط متن از آن و نمایش آن‌ها بر روی صفحه است.


            String ligne;
         while((ligne=is.readLine())!=null)
                System.out.println(ligne);

در اینجا نیز، خواندن استریم ممکن است یک استثنا را فعال کند که باید مدیریت شود. در اینجا مثالی از اجرای برنامه آورده شده است که به یک URL محلی نیاز دارد:

E:\data\serge\Jbuilder\interfaces\JApplets\3>java urlcontenu http://localhost
<html>

<head>


<title>Bienvenue dans le Serveur Web personnel</title>
</head>

<body bgcolor="#FFFFFF" link="#0080FF" vlink="#0080FF"
topmargin="0" leftmargin="0">

<table border="0" cellpadding="0" cellspacing="0" width="100%"
bgcolor="#000000">
............
                </table>
                </center></div></td>
            </tr>
        </table>
        </td>
    </tr>
</table>
</body>
</html>

5.6.5.3. یک مثال گرافیکی

رابط کاربری گرافیکی به شرح زیر خواهد بود:

Image

شماره
نام
نوع
نقش
۱
txtURL
JTextField
URL – لطفاً بخوانید
2
btnCharger
JButton
دکمه برای شروع پخش URL
3
JScrollPane
JScrollPane
پنل پیمایش
4
lstURL
JList
فهرست نمایش‌دهنده محتویات URL درخواستی

هنگام اجرا، خروجی مشابه خروجی برنامه کنسول است:

Image

کد مربوطه از برنامه به شرح زیر است:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.net.*;
import java.io.*;

public class interfaceURL extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtURL = new JTextField();
  JButton btnCharger = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel lignes=new DefaultListModel();
  JList lstURL = new JList(lignes);

  //چارچوب را بسازید
  public interfaceURL() {
..............
  }

   //کامپوننت را راه‌اندازی کنید
  private void jbInit() throws Exception  {
..............
  }

   //جایگزین شد، بنابراین می‌توانیم هنگام بستن پنجره خارج شویم
  protected void processWindowEvent(WindowEvent e) {
...................
  }

  void txtURL_caretUpdate(CaretEvent e) {
    //وضعیت دکمهٔ Load را تنظیم می‌کند
    btnCharger.setEnabled(! txtURL.getText().trim().equals(""));
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    //محتویات URL را در لیست نمایش می‌دهد
    try{
      afficherURL(txtURL.getText().trim());
    }catch(Exception ex){
       //خطا را نمایش می‌دهد
      JOptionPane.showMessageDialog(this,"Erreur : " + ex.getMessage(),"Erreur",JOptionPane.ERROR_MESSAGE);
    }//try-catch
  }

  private void afficherURL(String strURL) throws Exception {
    //محتویات URL و strURL را در لیست نمایش می‌دهد
     // هیچ استثنایی به‌طور خاص مدیریت نمی‌شود. آن‌ها صرفاً منتقل می‌شوند

     // ایجاد URL
    URL url=new URL(strURL);
     // ایجاد جریان ورودی
    BufferedReader IN=new BufferedReader(new InputStreamReader(url.openStream()));
    //خواندن خطوط متنی از جریان ورودی
    String ligne;
    while((ligne=IN.readLine())!=null)
      lignes.addElement(ligne);
     //بستن جریان خواندن
    IN.close();
  }
}

5.6.5.4. یک اپلت

برنامهٔ گرافیکی قبلی به یک اپلت تبدیل شده است، همان‌طور که در چندین مورد نشان داده شده است. اپلت در مستندی به شناسهٔ HTML appliURL.htm جاسازی شده است:

<html>
  <head>
    <title>Applet lisant une URL</title>
  </head>
  <body>
    <h1>Applet lisant une URL</h1>
    <applet
      code="appletURL.class"
      width="400"
      height="300"
    >
    </applet>
  </body>
</html>

Image

در مثال بالا، مرورگر http://localhost:81/Japplets/2/appliURL.htm را از یک وب‌سرور apache که روی پورت 81 در حال اجرا بود، درخواست کرد. سپس اپلت در مرورگر نمایش داده شد. در داخل اپلت، مجدداً URL http://localhost:81/Japplets/2/appliURL.htm را درخواست کردیم تا تأیید کنیم که واقعاً فایلی را که ایجاد کرده بودیم دریافت می‌کنیم. اکنون بیایید سعی کنیم یک URL را بارگذاری کنیم که به ماشین صادرکننده اپلت تعلق ندارد (در این مورد، localhost):

Image

تلاش برای بارگذاری URL رد شد. این موضوع محدودیت مربوط به اپلکت‌ها را برجسته می‌کند: آنها فقط می‌توانند به منابع شبکه روی دستگاهی که از آن دانلود شده‌اند دسترسی داشته باشند. راهی برای دور زدن این محدودیت برای اپلت وجود دارد که آن واگذاری درخواست‌های شبکه به یک برنامه سرور مستقر در دستگاهی است که اپلت از آن دانلود شده است. این برنامه درخواست‌های شبکه را از طرف اپلت انجام داده و نتایج را به آن بازمی‌گرداند. این برنامه به عنوان یک برنامه واسطه (relay programme) شناخته می‌شود.

5.7. اپلت IMPOTS

اکنون قصد داریم برنامه گرافیکی IMPOTS را به یک اپلِت تبدیل کنیم. این موضوع از اهمیت ویژه‌ای برخوردار است: این برنامه برای هر کاربر اینترنتی که مرورگر و افزونه جاوا 1.4 داشته باشد، در دسترس قرار خواهد گرفت (به دلیل کامپوننت JSpinner). بنابراین برنامه ما در سطح جهانی در دسترس قرار خواهد گرفت... این تغییر به چیزی بیش از تبدیل استاندارد یک برنامه گرافیکی به یک اپلِت نیاز دارد. این برنامه از یک گزینه منو به نام Initialiser استفاده می‌کند که برای خواندن محتویات یک فایل محلی طراحی شده است. با این حال، اگر یک برنامه وب را در نظر بگیریم، می‌بینیم که این رویکرد دیگر کار نمی‌کند:

Image

واضح است که داده‌های تعریف‌کننده مقیاس‌های مالیاتی روی سرور وب قرار خواهند داشت و نه روی هر رایانه مشتری به طور جداگانه. فایلی که باید از سرور وب خوانده شود، در همان پوشه اپلت قرار داده خواهد شد و گزینه Initialiser باید آن را از آنجا بازیابی کند. مثال‌های قبلی نشان داده‌اند که چگونه این کار را انجام دهیم. علاوه بر این، برای انتخاب محلی فایل داده، از کامپوننت JFileChooser استفاده کرده بودیم که در اینجا دیگر مورد نیاز نیست.

سند HTML حاوی اپلت به شرح زیر خواهد بود:

<html>
  <head>
    <title>Applet de calcul d'impôts</title>
  </head>
  <body>
    <h2>Calcul d'impôts</h2>
    <applet
      code="appletImpots.class"
      width="320"
      height="270"
    >

<param name="data" value="impots.txt">


    </applet>
  </body>
</html>

به پارامتر data توجه کنید که مقدار آن نام فایلی است که حاوی داده‌های جدول مالیاتی می‌باشد. سند HTML، کلاس appletImpots، کلاس impots و فایل impots.txt همگی در یک پوشه روی سرور وب قرار دارند:

E:\data\serge\web\JApplets\impots>dir
12/06/2002  13:24                  247 impots.txt
13/06/2002  10:17                  654 appletImpots$2.class
13/06/2002  10:17                  653 appletImpots$3.class
13/06/2002  10:17                  653 appletImpots$4.class
13/06/2002  10:17                  651 appletImpots$5.class
13/06/2002  10:06                  651 appletImpots$6.class
13/06/2002  10:17                8 655 appletImpots.class
13/06/2002  10:17                  657 appletImpots$1.class
13/06/2002  10:24                  286 appletImpots.htm
13/06/2002  10:17                1 305 impots.class

کد این اپلت به شرح زیر است (ما تنها تغییرات را نسبت به برنامهٔ گرافیکی برجسته کرده‌ایم):

...........
import java.net.*;
import java.applet.Applet;

public class appletImpots extends JApplet {
  // اجزای پنجره
  JPanel contentPane;
............................

   //ویژگی‌های کلاس
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;
  String urlDATA=null;

  //ساخت فریم
  public void init() {
    //enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // ابتکارات دیگر
    moreInit();
  }

   // ابتدای‌سازی فرم
  private void moreInit(){
     // غیرفعال بودن منوی «محاسبه»
    mnuCalculer.setEnabled(false);
................
     // بازیابی نام فایل جدول مالیاتی
    String nomFichier=getParameter("data");
    // خطا؟
    if(nomFichier==null){
       // پیام خطا
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       // غیرفعال کردن گزینه «ابتدایی‌سازی»
      mnuInitialiser.setEnabled(false);
      //پایان
      return;
    }//اگر
     // تنظیم URL برای داده‌ها
    urlDATA=getCodeBase()+"/"+nomFichier;
  }//moreInit

   //کامپوننت را راه‌اندازی کنید
  private void jbInit() throws Exception  {
...................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    //خروج از برنامه
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // بارگذاری فایل داده
    try{
       // خواندن داده‌ها
      lireDATA();
       // ایجاد شیء 'impots'
      objImpots=new impots(limites,coeffr,coeffn);
................
  }

  private void lireDATA() throws Exception {
     // جدول‌های داده
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // باز کردن فایل در حالت فقط خواندنی
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
    // خواندن خط به خط فایل
....................
  }

  void mnuCalculer_actionPerformed(ActionEvent e) {
    //محاسبه مالیات
......................
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
..........
  }

  void mnuEffacer_actionPerformed(ActionEvent e) {
...............
  }
}

ما در اینجا تنها در مورد تغییراتی که از این واقعیت ناشی می‌شود که فایل داده‌ای که باید خوانده شود اکنون روی یک ماشین از راه دور به جای یک ماشین محلی قرار دارد، توضیح می‌دهیم:

نام فایل داده URL که باید خوانده شود، با استفاده از کد زیر به دست می‌آید:

     //بازیابی نام فایل جدول مالیات
    String nomFichier=getParameter("data");
    // خطا؟
    if(nomFichier==null){
       // پیام خطا
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       //غیرفعال کردن گزینه «Initialise»
      mnuInitialiser.setEnabled(false);
      //پایان
      return;
    }//اگر
     // تنظیم URL برای داده‌ها
    urlDATA=getCodeBase()+"/"+nomFichier;

بیایید به یاد داشته باشیم که نام فایل «impots.txt» به پارامتر data اپلِت ارسال شده است:

    <param name="data" value="impots.txt">

بنابراین کد بالا با بازیابی مقدار پارامتر data آغاز می‌شود، در حالی که هرگونه خطایی را که ممکن است رخ دهد، مدیریت می‌کند. اگر URL سند HTML حاوی اپلت http://localhost:81/JApplets/impots/appletImpots.htm باشد، URL برای فایل impots.txt برابر خواهد بود با http://localhost:81/JApplets/impots/impots.txt. ما باید نام این URL را بسازیم. متد getCodeBase() اپلت، URL پوشه‌ای را بازمی‌گرداند که سند HTML حاوی اپلت از آن بازیابی شده است، بنابراین در مثال ما http://localhost:81/JApplets/impots. دستورالعمل زیر به ما امکان می‌دهد تا URL را برای فایل داده بسازیم:

    urlDATA=getCodeBase()+"/"+nomFichier;

روش lireFichier() که محتویات URL و urlData را می‌خواند، شامل ایجاد جریان ورودی است که امکان خواندن داده‌ها را فراهم می‌کند:

     // باز کردن فایل برای خواندن
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));

از این نقطه به بعد، دیگر نمی‌توان تشخیص داد که داده‌ها از یک فایل محلی هستند یا از یک فایل راه دور. در اینجا مثالی از اجرای این اپلت آورده شده است:

Image

5.8. نتیجه‌گیری

این فصل ارائه کرده است

  • مقدمه‌ای بر ساخت رابط‌های کاربری گرافیکی با JBuilder
  • رایج‌ترین کامپوننت‌های Swing
  • ایجاد اپلکت‌ها

شایان ذکر است که

  • کدی که توسط JBuilder تولید می‌شود را می‌توان به‌صورت دستی نوشت. پس از به‌دست‌آوردن این کد به هر نحو ممکن، یک JDK ساده برای اجرای آن کافی است و JBuilder دیگر ضروری نخواهد بود.
  • استفاده از ابزاری مانند JBuilder می‌تواند به افزایش چشمگیر بهره‌وری منجر شود:
    • اگرچه نوشتن دستی کدی که توسط JBuilder تولید شده است امکان‌پذیر است، اما این کار می‌تواند بسیار وقت‌گیر باشد و فایده چندانی نداشته باشد، زیرا منطق برنامه معمولاً در جای دیگری قرار دارد.
    • کد تولیدشده می‌تواند آموزنده باشد. مطالعه و بررسی آن راه خوبی برای کشف برخی روش‌ها و ویژگی‌های کامپوننت‌هایی است که برای اولین بار از آن‌ها استفاده می‌کنید.
    • JBuilder چند سکویی است. بنابراین هنگام جابجایی بین پلتفرم‌ها دانش خود را حفظ می‌کنید. توانایی نوشتن برنامه‌هایی که هم روی ویندوز و هم روی لینوکس اجرا می‌شوند، البته عاملی بسیار مهم در بهره‌وری است. با این حال، این به خودِ جاوا مربوط است و نه به JBuilder.

5.9. JBuilder روی لینوکس

تمام مثال‌های قبلی روی ویندوز ۹۸ آزمایش شده‌اند. ممکن است این سؤال پیش بیاید که آیا برنامه‌های نوشته شده به همین شکل برای لینوکس قابل حمل هستند یا خیر. به شرطی که ماشین لینوکس مورد نظر، کلاس‌های مورد استفاده توسط برنامه‌های مختلف را داشته باشد، پاسخ مثبت است. برای مثال، اگر JBuilder را روی لینوکس نصب کرده باشید، کلاس‌های لازم از قبل روی سیستم شما موجود هستند. در اینجا، به‌عنوان مثال، خروجی اجرای یکی از برنامه‌های ما روی کامپوننت JList با JBuilder 4 در لینوکس را مشاهده می‌کنید:

در زیر، نصب JBuilder 4 Foundation روی یک سیستم لینوکس را تشریح می‌کنیم. نصب آن روی سیستم Win9x هیچ مشکلی ندارد و مشابه روندی است که در ادامه توضیح داده شده است. نصب نسخه‌های بعدی ممکن است متفاوت باشد، اما این سند ممکن است همچنان اطلاعات مفیدی ارائه دهد.

JBuilder در وب‌سایت Inprise به آدرس http://www.inprise.com/jbuilder در دسترس است.

Image

این صفحه حاوی لینک‌هایی برای ویندوز و لینوکس و غیره است. اکنون نصب JBuilder را روی یک ماشین لینوکس که رابط گرافیکی KDE را اجرا می‌کند، شرح خواهیم داد.

وقتی روی لینک «JBuilder 4 for Linux» کلیک می‌کنید، یک فرم ظاهر می‌شود. آن را پر کنید تا دو فایل دریافت کنید:

jb4docs_fr.tar.gz: مستندات و مثال‌های JBuilder 4

jb4fndlinux_fr.tar.gz: JBuilder 4 Foundation. این نسخه محدودی از JBuilder 4 تجاری است، اما برای اهداف آموزشی کافی است.

یک کلید فعال‌سازی برای نرم‌افزار از طریق ایمیل برای شما ارسال خواهد شد. این کلید به شما امکان استفاده از JBuilder 4 را می‌دهد و در اولین بار استفاده از نرم‌افزار مورد نیاز خواهد بود. اگر این کلید را گم کنید، می‌توانید به آدرس اینترنتی بالا بازگردید و پیوند «دریافت کلید فعال‌سازی خود» را دنبال کنید. اکنون فرض می‌کنیم که شما root هستید و در دایرکتوری حاوی دو فایل tar.gz که در بالا ذکر شد، قرار دارید. دو فایل را از حالت فشرده خارج کنید:

[tar xvzf jb4fndlinux_fr.tar.gz]
[tar xvzf jb4docs_fr.tar.gz]
[ls -l]
drwxr-xr-x    3 nobody   nobody       4096 oct 10  2000 docs
drwxr-xr-x    3 nobody   nobody       4096 déc  5 13:00 foundation
[ls -l foundation]
-rw-r--r--    1 nobody   nobody       1128 déc  5 13:00 deploy.txt
-rwxr-xr-x    1 nobody   nobody   69035365 déc  5 13:00 fnd_linux_install.bin
drwxr-xr-x    2 nobody   nobody       4096 déc  5 13:00 images
-rw-r--r--    1 nobody   nobody      15114 déc  5 13:00 index.html
-rw-r--r--    1 nobody   nobody      23779 déc  5 13:00 license.txt
-rw-r--r--    1 nobody   nobody      75739 déc  5 13:00 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 déc  5 13:00 whatsnew.html
[ls -l docs]
-rw-r--r--    1 nobody   nobody       1128 oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 oct 10  2000 whatsnew.html

در هر دو پوشهٔ ایجادشده، فایل .bin فایل نصب است. علاوه بر این، در هر پوشه با استفاده از یک مرورگر وب، فایل index.html را باز کنید. این فایل‌ها دستورالعمل‌هایی برای نصب هر دو محصول ارائه می‌دهند. بیایید با نصب JBuilder Foundation شروع کنیم:

[cd foundation]
[./fnd_linux_install.bin]

اولین صفحه نصب ظاهر می‌شود. صفحات بسیار بیشتری به دنبال آن خواهند آمد:

Image

تأیید کنید. یک صفحهٔ توضیحی بعدی نمایش داده خواهد شد:

Image

[suivant] را وارد کنید.

Image

قرارداد مجوز را بپذیرید و [suivant] را وارد کنید.

Image

مکان پیشنهادی نصب JBuilder را بپذیرید (آن را یادداشت کنید، زیرا بعداً به آن نیاز خواهید داشت) و [suivant] را وارد کنید. نصب سریع است.

Image

ما برای یک تست اولیه آماده‌ایم. در KDE، مدیر فایل را اجرا کنید تا به دایرکتوری اجرایی‌های JBuilder بروید: /opt/jbuilder4/bin (اگر JBuilder را در /opt/jbuilder4 نصب کرده‌اید):

Image

روی آیکون jbuilder در بالا کلیک کنید. از آنجا که این اولین باری است که از JBuilder استفاده می‌کنید، باید کلید فعال‌سازی خود را وارد کنید:

Image

میدان‌های Nom و Société را پر کنید. برای وارد کردن کلید فعال‌سازی خود روی [Ajouter] کلیک کنید. لطفاً توجه داشته باشید که این کلید باید از طریق ایمیل برای شما ارسال شده باشد و اگر آن را گم کرده‌اید، می‌توانید آن را از URL محل دانلود JBuilder 4 بازیابی کنید (به ابتدای فرایند نصب مراجعه کنید). پس از پذیرش کلید فعال‌سازی شما، شرایط مجوز برایتان یادآوری خواهد شد:

Image

با وارد کردن OK، به پنجره ورود اطلاعات که قبلاً دیده‌اید بازخواهید گشت:

Image

برای تکمیل این مرحله، OK را وارد کنید؛ این مرحله تنها در اولین بار اجرای برنامه انجام می‌شود. سپس محیط توسعه JBuilder ظاهر خواهد شد:

Image

از JBuilder خارج شوید تا مستندات را اکنون نصب کنید. این کار تعدادی فایل را نصب می‌کند که در راهنمای JBuilder استفاده خواهند شد، که در حال حاضر ناقص است. به دایرکتوری‌ای که فایل‌های JBuilder را در آن استخراج کرده‌اید بازگردید tar.gz. برنامه نصب در دایرکتوری docs قرار دارد. به آن بروید:

[cd docs]
[ls -l]
-rw-r--r--    1 nobody   nobody       1128 oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 oct 10  2000 whatsnew.html

فایل نصب doc_install.bin است، اما نمی‌توانید آن را بلافاصله اجرا کنید. اگر این کار را انجام دهید، نصب بدون هیچ دلیل واضحی ناموفق خواهد بود. برای مشاهده توضیحات دقیق مراحل نصب، فایل index.html را در یک مرورگر وب باز کنید. این نصاب به یک ماشین مجازی جاوا (JVM) نیاز دارد؛ به طور خاص، برنامه‌ای به نام java که باید در دایرکتوری PATH روی سیستم شما قرار داشته باشد. لطفاً توجه داشته باشید که PATH یک متغیر یونیکس است که مقدار آن، در قالب rep1:rep2:...:repn، دایرکتوری‌های repi را که باید برای یک فایل اجرایی جستجو شوند، مشخص می‌کند. در اینجا، نصاب درخواست می‌کند که برنامه‌ای به نام java اجرا شود. ممکن است نسخه‌های مختلفی از این برنامه داشته باشید، بسته به تعداد ماشین‌های مجازی جاوایی که اینجا و آنجا نصب کرده‌اید. به طور منطقی، ما از نسخه‌ای که توسط JBuilder 4 ارائه شده است استفاده خواهیم کرد که در /opt/jbuilder4/jdk1.3/bin قرار دارد. برای تنظیم این دایرکتوری در متغیر PATH:

[echo $PATH]
/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
[export PATH=/opt/jbuilder4/jdk1.3/bin/:$PATH]
[echo $PATH]
/opt/jbuilder4/jdk1.3/bin/:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin

اکنون می‌توانیم نصب مستندات را آغاز کنیم:

[./doc_install.bin]
Preparing to install...

این یک نصب گرافیکی است که اکنون انجام خواهد شد:

Image

این بسیار شبیه نصب JBuilder Foundation است. بنابراین در اینجا وارد جزئیات نمی‌شویم. یک صفحه وجود دارد که نباید آن را از دست بدهید:

Image

نصب‌کننده معمولاً به‌طور خودکار تشخیص می‌دهد که JBuilder Foundation را کجا نصب کرده‌اید. بنابراین، تنظیمات پیش‌فرض را تغییر ندهید، مگر اینکه البته نادرست باشند.

پس از نصب مستندات، آمادهٔ آزمایش مجدد JBuilder هستیم. برنامه را همان‌طور که در بالا نشان داده شده اجرا کنید. پس از باز شدن JBuilder، منوی Help/Help Topic را انتخاب کنید. در پنل سمت چپ، روی پیوند Tutoriels کلیک کنید:

Image

JBuilder همراه با مجموعه‌ای از آموزش‌ها ارائه می‌شود تا به شما در شروع برنامه‌نویسی جاوا کمک کند. در زیر، ما آموزش «ساخت یک برنامه» را که در بالا توضیح داده شد، دنبال کرده‌ایم.

Image

در JBuilder، File/New Project را انتخاب کنید. یک جادوگر شما را در سه صفحه راهنمایی خواهد کرد:

Image

ما قصد داریم یک پنجره ساده با عنوان «سلام به همه» ایجاد کنیم. این پروژه را coucou نام‌گذاری خواهیم کرد. این مثال توسط root اجرا شد. سپس JBuilder پیشنهاد می‌کند که همه پروژه‌ها را در یک پوشه به نام jbproject در داخل پوشه اتصال root گروه‌بندی کنید. پروژه coucou در دایرکتوری coucou (میدان نام دایرکتوری پروژه) از jbproject قرار داده خواهد شد. [suivant] را ایجاد کنید.

Image

این صفحهٔ دوم مسیرهای مختلف پروژهٔ شما را خلاصه می‌کند. چیزی برای تغییر وجود ندارد. [suivant] را اجرا کنید.

Image

صفحه سوم از شما می‌خواهد پروژه خود را سفارشی‌سازی کنید. جزئیات را پر کنید و [Terminer] را اجرا کنید.

اکنون Fichier/Nouveau را اجرا کنید:

Image

Application را انتخاب کرده و روی OK کلیک کنید. یک جادوگر جدید دو صفحه نمایش خواهد داد:

Image

میدان paquet حاوی نام پروژه است. میدان «Class» به مقدار nom نیاز دارد که به کلاس اصلی پروژه اختصاص داده می‌شود. نام بالا را بردارید و مقدار [suivant] را وارد کنید:

Image

اپلیکیشن ما شامل یک کلاس جاوا دوم برای پنجرهٔ برنامه است. برای این کلاس یک نام انتخاب کنید. فیلد Titre عنوانی است که می‌خواهید به این پنجره بدهید. بخش options گزینه‌هایی را برای پنجرهٔ شما ارائه می‌دهد. همگی را انتخاب کرده و [Terminer] را وارد کنید. سپس به محیط JBuilder بازمی‌گردید که اکنون با اطلاعاتی که برای پروژه‌تان ارائه کرده‌اید، به‌روزرسانی شده است:

Image

در پنجره سمت چپ بالا (۱)، فهرستی از فایل‌های تشکیل‌دهنده پروژه خود را مشاهده خواهید کرد. این‌ها شامل دو کلاس .java است که ما همین‌الان نام‌گذاری کرده‌ایم. در پنجره سمت راست (۲)، کد جاوا برای کلاس coucouCadre را مشاهده خواهید کرد. در پنجرهٔ پایین سمت چپ می‌توانید ساختار (کلاس‌ها، متدها، ویژگی‌ها) پروژهٔ خود را مشاهده کنید. پروژه آمادهٔ اجرا است. روی دکمهٔ ۴ در بالا کلیک کنید، یا Run/Run Project را انتخاب کنید، یا F9 را انتخاب کنید. باید پنجرهٔ زیر را مشاهده کنید:

Image

با کلیک بر روی گزینه Aide، اطلاعاتی را که به جادوگران ایجاد ارائه کرده‌اید، باید ببینید. ما بیشتر پیش نمی‌رویم. اکنون زمان آن است که به سراغ آموزش‌ها برویم.

قبل از پایان، بیایید فقط نشان دهیم که شما می‌توانید نه از JBuilder و رابط کاربری گرافیکی آن، بلکه از JDK که با خود آورده و در /opt/jbuilder4/jdk1.3 قرار داده است، استفاده کنید. فایل زیر را کامپایل کنید:

import java.io.*;

public class essai1{
    public static void main(String args[]){
        System.out.println("coucou");
        System.exit(0);
    }
}

بیایید آن را با استفاده از JDK JBuilder کامپایل و اجرا کنیم:

[ls -l *.java]
-rw-r--r--    1 root     root          135 mai  9 21:57 essai1.java
[/opt/jbuilder4/jdk1.3/bin/javac essai1.java]
[/opt/jbuilder4/jdk1.3/bin/java essai1]
coucou