View Full Version : سوال: چند سوال در مورد Mouse event ها در جاوا .
larten-k
سه شنبه 08 تیر 1395, 12:12 عصر
سلام ،چندتا سوال در مورد mouse listener داشتم ممنون میشم اگر کسی پاسخ بده.
1)چرا و چطور جاوا بین یک MouseListener, MouseMotionLisetner و یک MouseWheelListener تمایز قائل میشه؟
2)اینترفیس MouseInputListener خالی است پس اصلن چرا وجود داره؟چه فایده ای داره؟
3) دو کلاس MouseAdapter وMouseMotionAdapter چه اهمیت ویژه ای دارن؟
vahid-p
چهارشنبه 09 تیر 1395, 06:38 صبح
1)چرا و چطور جاوا بین یک MouseListener, MouseMotionLisetner و یک MouseWheelListener تمایز قائل میشه؟
اگر عملکرد Event ها و نقش Listenerها رو بدونید، فکر میکنم چرا و چطورش براتون مشخص بشه.
هر رخداد (Event) یک سری ویژگی همراه خودش داره. مثلا از طریق چه کامپوننتی رخ داده و نوع Event چی بوده و یکسری جزئیات دیگه. این Eventها در یک صف قرار میگیرند که AWT خودش مدیریت این صف رو بر عهده میگیره (تمام رخدادها در یک Thread اجرا میشن). خب پس اونها رو به نوبت میگیره و به کامپوننت مورد نظر تحویل میده. ممکنه کامپوننت مورد نظر باز خودش صفی برای مدیریت داشته باشه یا نه (که پیاده سازیش رو بررسی نکردم). به هر حال وقتی Event رو داریم پس میدونیم به کدوم کامپوننت مرتبطه پس از صف رخدادهای AWT برداشته میشه و به همون کامپوننت تحویل داده میشه، اگر خود کامپوننت Listener ای براش در نظر نگرفته باشه به کلاس پدرش داده میشه و همینطور ادامه پیدا میکنه. در نهایت این کامپوننت ممکنه با انجام عملی مصرف بشه یا بدون انجام عملی مصرف بشه (Consume).
به این تصویر دقت کنید: (میگه AWT رخداد رو میده به شی هدف (Target Object) اگر هندلش نکرد میده به پدرش و الی آخر)
http://www.webbasedprogramming.com/Java-Developers-Reference/f21-2.gif
پس مشخصه که رخدادهایی که داخل صف هستند به کامپوننت مورد نظر میرن و اونجا اگر Listener ای براش بود، متد مربوطه اون Listener رو صدا میزنه.
این یک دیدگاه کلی بود. برای جزئیات بیشتر، ادامه رو بخونید با دقت.
ادامه توضیحات با یه مثال: فرض کنید یک Button داریم و براش یک MouseListener تعریف کردیم (در حالت پیشفرض mouseListener=null است). اگر بر روی کامپوننت کلیک کنیم، AWT رخدادی به شکل نمادین زیر میسازه:
آبجکت Event(کامپوننت: آبجکت 8362، رخداد: کلیک کردن)
خب این آبجکت یا شی رو در صف قرار میده و وقتی نوبتش رسید، این Event رو مخابره می کنه (Dispatch). بعد اون Event طی مراحلی به کامپوننت مربوطه پاس میشه. به متد processEvent کامپوننت مربوطه پاس میشه. متد processEvent در کلاس Component ( کلاس Component پدر تمام کلاس کامپوننت ها مثل button و textfield و...) به صورت زیر است: (به راحتی میتونید سورس کد لایبرری های جاوا رو بخونید مثلا در نت بینز با گرفتن Ctrl و کلیک بر روی متد یا نام کلاس سورسش باز میشه)
protected void processEvent(AWTEvent e) { if (e instanceof FocusEvent) {
processFocusEvent((FocusEvent)e);
} else if (e instanceof MouseEvent) {
switch(e.getID()) {
case MouseEvent.MOUSE_PRESSED:
case MouseEvent.MOUSE_RELEASED:
case MouseEvent.MOUSE_CLICKED:
case MouseEvent.MOUSE_ENTERED:
case MouseEvent.MOUSE_EXITED:
processMouseEvent((MouseEvent)e);
break;
case MouseEvent.MOUSE_MOVED:
case MouseEvent.MOUSE_DRAGGED:
processMouseMotionEvent((MouseEvent)e);
break;
case MouseEvent.MOUSE_WHEEL:
processMouseWheelEvent((MouseWheelEvent)e);
break;
}
} else if (e instanceof KeyEvent) {
processKeyEvent((KeyEvent)e);
} else if (e instanceof ComponentEvent) {
processComponentEvent((ComponentEvent)e);
} else if (e instanceof InputMethodEvent) {
processInputMethodEvent((InputMethodEvent)e);
} else if (e instanceof HierarchyEvent) {
switch (e.getID()) {
case HierarchyEvent.HIERARCHY_CHANGED:
processHierarchyEvent((HierarchyEvent)e);
break;
case HierarchyEvent.ANCESTOR_MOVED:
case HierarchyEvent.ANCESTOR_RESIZED:
processHierarchyBoundsEvent((HierarchyEvent)e);
break;
}
}
}
میبینید چیزی نیست جز چند شرط که چک میکنه Event ای که بهش پاس داده شده از چه نوع است. در مثال ما (else if (e instanceof MouseEvent درسته و در نتیجه بدنه شرط اجرا میشه (instanceof کلاس یک شی رو بررسی میکنه). بدنه شرط هم یک switch ... case است که با e.getID نوعش رو مشخص میکنه. خب در مثال ما کلیک کردن هست پس از نوع MouseEvent است نه MouseWheelEvent و... . در نتیجه processMouseEvent((MouseEvent) e) صدا زده میشه و متد processMouseEvent کدش اینه:
MouseListener listener = mouseListener; if (listener != null) {
int id = e.getID();
switch(id) {
case MouseEvent.MOUSE_PRESSED:
listener.mousePressed(e);
break;
case MouseEvent.MOUSE_RELEASED:
listener.mouseReleased(e);
break;
case MouseEvent.MOUSE_CLICKED:
listener.mouseClicked(e);
break;
case MouseEvent.MOUSE_EXITED:
listener.mouseExited(e);
break;
case MouseEvent.MOUSE_ENTERED:
listener.mouseEntered(e);
break;
}
}
که به راحتی چک میکنه اگر Listener ای بود (یعنی mouseListener مقدار null نداشته باشه) یعنی یک گوش شنوایی باشه که event رو به گوش شنوا میده (Listener)، اما قبلش چک میکنه کلیک کردن بوده یا فشردن کلید، یا رها کردن کلید، یا خروج از کامپوننت یا ورود به کامپوننت، و در مثال ما کلیک کردن بوده پس listener.mouseClicked(e); صدا زده میشه.
خب تا اینجای کار همه کارها رو اتوماتیک انجام میشه. اما کار ما چیه این وسط؟
ما باید شیء ای از نوع اون Listener (گوش شنوا) بسازیم و بگیم برای هر رخدادی که شنیدی کاری که ما میخوایم انجام بده. در اصل MouseListener یا بقیه، تنها یک Interface هستن (Interface یک رابط هست که پیاده سازی نشده و پیاده سازیش بر عهده ماست، هر چند ممکنه مثل اینترفیس Serializable هیچ متدی نداشته باشه). در این مورد (هر چند Interfaceها کاربردهای مختلفی دارن) دلیل استفاده از Interface اینه که ما بدونیم هر تایپ Event چه کارهایی رو انجام میده که ما مجاز هستیم برای اونها یک پیاده سازی انجام بدیم. اینترفیس ها برخلاف گفته شما خالی نیستن بلکه متدهای بدون بدنه دارن. اگر اینترفیس نبود ممکنه شما برای رخداد کلیک کردن یک متد بنویسید به اسم rooshClickShode(MouseEvent e) در صورتی که در مسیری که طی کردیم فقط یک نام و اون هم mouseClicked قابل قبوله.
اینم سورس کد اینترفیس MouseListener : (بالاتر گفتم چطور سورس کد ها رو پیدا کنیم)
public interface MouseListener extends EventListener {
/**
* Invoked when the mouse button has been clicked (pressed
* and released) on a component.
*/
public void mouseClicked(MouseEvent e);
/**
* Invoked when a mouse button has been pressed on a component.
*/
public void mousePressed(MouseEvent e);
/**
* Invoked when a mouse button has been released on a component.
*/
public void mouseReleased(MouseEvent e);
/**
* Invoked when the mouse enters a component.
*/
public void mouseEntered(MouseEvent e);
/**
* Invoked when the mouse exits a component.
*/
public void mouseExited(MouseEvent e);
}
خب میبینید شبیه یک کلاسه که متدهاش بدنه ندارن. یعنی کاری انجام نمیدن، فقط اسمشون، ورودی و خروجی رو مشخص میکنن. مثل یک جعبه سیاه (Black Box) که درونش رو ما میگیم چیکار انجام بده. خب حالا هر کلاسی ما تعریف کنیم که این لیسنر رو پیاده سازی کنه (implements) حتما این پنج متد رو خواهد داشت.
مثلا کلاس MouseHandler تعریف میکنیم که اینترفیس MouseListener رو پیاده سازی میکنه:
public class MouseHandler implements MouseListener{
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
حالا میتونیم داخل هر کدوم از این متدها کاری که میخوایم رو انجام بدیم (دقت کنید برای Interface از implements بعد از اسم کلاس استفاده شده اما برای کلاس از extends استفاده میشه). خب الان هر آبجکتی از نوع MouseHandler در هر جایی که تایپ MouseListener رو قبول میکنه میتونیم قرار بدیم، چرا که مطمئنیم ویژگی ها (پنج متد مذکور) اون اینترفیس رو داره.
خب حالا میتونیم ازش استفاده کنیم:
JButton btn=new JButton();MouseHandler mouseHandler=new MouseHandler();
btn.addMouseListener(mouseHandler);
الان تو اون کد متد processMouseEvent که بالاتر توضیح داده شد، وقتی listener.mouseClicked صدا زده بشه، اینی که ما نوشتیم انجام میشه. خیلی وقتها به صورت in-line یک اینترفیس رو پیاده سازی (implement) میکنیم:
JButton btn=new JButton();btn.addMouseListener(new MouseListener() {
...
});
این معادل همون کد قبلیه.
پایان
vahid-p
چهارشنبه 09 تیر 1395, 07:02 صبح
2)اینترفیس MouseInputListener خالی است پس اصلن چرا وجود داره؟چه فایده ای داره؟
در پست قبل پاسخ داده شد (خالی نیست).
3) دو کلاس MouseAdapter وMouseMotionAdapter چه اهمیت ویژه ای دارن؟
اهمیت ویژه ای ندارن (بعضی Adapter ها کارهایی انجام میدن ولی اینا نه). یه خورده کد رو خلوت تر میکنن، چون MouseAdapter به عنوان مثال، یک کلاس هست و نه یک اینترفیس و نیازی نیست تمام متدهاش رو پیاده سازی کنید چون ممکنه خیلیاشو نیازی نداشته باشید. در واقع MouseAdapter یک abstract class که متدهاش یک پیاده سازی اولیه شدن و شما ملزم به پیاده سازی هستید ولی هر چندتاشو که دوست داشتید (هیچی، یکی، دو سه یا همه) میتونید پیاده سازی کنید و MouseAdapter خودش کلاسیه که هر سه نوع Listener مربوط به موس رو پیاده سازی کرده (مثلا!)
اگر سورسش رو ببینید متوجه میشید:
public abstract class MouseAdapter implements MouseListener, MouseWheelListener, MouseMotionListener { /**
* {@inheritDoc}
*/
public void mouseClicked(MouseEvent e) {}
/**
* {@inheritDoc}
*/
public void mousePressed(MouseEvent e) {}
...
{
در حالت عادی بدنه mouseClicked خالیه و به این معنی است که کاری انجام نمیده. ولی شما میتونید override کنید. مثلا:
btn.addMouseListener(new MouseAdapter() { @Override
public void mouseClicked(MouseEvent e) {
System.out.println("Hello!");
}
});
همانطور که دیدید نیازی به پیاده سازی تمام متدها نیست.
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.