PDA

View Full Version : اجرا نشدن JOptionPane برای نمایش خروجی برنامه



Sina.iRoid
چهارشنبه 28 آبان 1393, 10:39 صبح
سلام.
دوستان، برنامه ای که در زیر نوشتم خیلی سادست. اما دوست دارم به صورت شی گرا برنامه رو بنویسم برای همین به مشکل خورم.

برنامه به این صورت هست که وقتی که روی فیلد ها دکمه اینتر و فشار می دیم، یک کادر گفتگو ایی باز میشه و یه پیغامی و نمایش میده. اما برنامه موقعی که دکمه اینتر و فشار میدیم کرش می کنه. نمی دونم مشکل از کجاست؟
درضمن در مورد شی گرا بدون برنامه هم اگر میشه نظرتون و بیان کنید. اینکه برنامه چقدر ایراد داره تا کاملا به صورت درست شی گرا نوشته بشه. ممنون. کد های برنامه رو در زیر می بینید:

کد کلاس FrameFields:


import javax.swing.JPasswordField;
import javax.swing.JTextField;


public final class FrameFields{

private JTextField textField1; //text field with set size
private JTextField textField2; //text field construct with text
private JTextField textField3; //text field with text and size
private JPasswordField passwordField; //password field with text

//getter and setter
public JTextField getTextField1(){
return textField1;
}
public void setTextField1(JTextField textField1){
this.textField1 = textField1;
}
public JTextField getTextField2(){
return textField2;
}
public void setTextField2(JTextField textField2){
this.textField2 = textField2;
}
public JTextField getTextField3(){
return textField3;
}
public void setTextField3(JTextField textField3){
this.textField3 = textField3;
}
public JPasswordField getPasswordField(){
return passwordField;
}
public void setPasswordField(JPasswordField passwordField){
this.passwordField = passwordField;
}
}


کد کلاس MainFrame:


import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import javax.swing.JTextField;




public class MainFrame extends JFrame{

//object from FrameFields
FrameFields ob = new FrameFields();

//Constructor
public MainFrame() {
super("JTextField And JPasswordField");
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//text field1
ob.setTextField1(new JTextField(10));
add(ob.getTextField1());

//text field2
ob.setTextField2(new JTextField("Sina"));
add(ob.getTextField2());

//text field3
ob.setTextField3(new JTextField("Uneditable text field", 15));
ob.getTextField3().setEditable(false);
add(ob.getTextField3());

//password field
ob.setPasswordField(new JPasswordField("sdiRoid1372", 10));
add(ob.getPasswordField());

//register event handler
TextFieldHandler handler = new TextFieldHandler();

ob.getTextField1().addActionListener(handler);
ob.getTextField2().addActionListener(handler);
ob.getTextField3().addActionListener(handler);
ob.getPasswordField().addActionListener(handler);
}
}


کد کلاس TextFieldHandler:


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;


public class TextFieldHandler implements ActionListener{

//default constructor
public TextFieldHandler() {}

private FrameFields ob;

//Constructor
public TextFieldHandler(FrameFields ob) {
this.ob = ob;
}

@Override
public void actionPerformed(ActionEvent e) {

String result;
if (e.getSource() == ob.getTextField1()) {
result = String.format("TextField1: %s", e.getActionCommand());
}
else if (e.getSource() == ob.getTextField2()) {
result = String.format("TextField2: %s", e.getActionCommand());
}
else if (e.getSource() == ob.getTextField3()) {
result = String.format("TextField3: %s", e.getActionCommand());
}else{
result = String.format("PasswordField: %s", e.getActionCommand());
}

//display result
JOptionPane.showMessageDialog(null, result, "Result", JOptionPane.PLAIN_MESSAGE);
}
}


و کد کلاس اصلی:


public class DriverClass {

public static void main(String[] args) {

MainFrame ob = new MainFrame();

ob.setSize(300, 400);
ob.setVisible(true);
}
}


ممنون اگر راهنماییم کنید.

ahmad.mo74
چهارشنبه 28 آبان 1393, 10:58 صبح
سلام، خط 38 کلاس MainFrame :)

Sina.iRoid
چهارشنبه 28 آبان 1393, 11:40 صبح
سلام.
خب مشکلش چیه!؟

Sina.iRoid
چهارشنبه 28 آبان 1393, 11:52 صبح
سلام.
من کلاسم و به اینصورت تغییر دادم و درست شد. اما نمی دونم چرا درست شد؟ میشه توضیح بدین. ممنون.

MainFrame:


import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import javax.swing.JTextField;




public class MainFrame extends JFrame{

//object from FrameFields
FrameFields ob = new FrameFields();

//Constructor
public MainFrame() {
super("JTextField And JPasswordField");
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//text field1
ob.setTextField1(new JTextField(10));
add(ob.getTextField1());

//text field2
ob.setTextField2(new JTextField("Sina"));
add(ob.getTextField2());

//text field3
ob.setTextField3(new JTextField("Uneditable text field", 15));
ob.getTextField3().setEditable(false);
add(ob.getTextField3());

//password field
ob.setPasswordField(new JPasswordField("sdiRoid1372", 10));
add(ob.getPasswordField());

//register event handler
TextFieldHandler handler = new TextFieldHandler(ob, this);

ob.getTextField1().addActionListener(handler);
ob.getTextField2().addActionListener(handler);
ob.getTextField3().addActionListener(handler);
ob.getPasswordField().addActionListener(handler);
}
}


TextFieldHandler


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;


public class TextFieldHandler implements ActionListener{

private final FrameFields ob;

//Constructor
public TextFieldHandler(FrameFields ob, MainFrame ob1) {
this.ob = ob;
}

@Override
public void actionPerformed(ActionEvent e) {

String result;
if (e.getSource() == ob.getTextField1()) {
result = String.format("TextField1: %s", e.getActionCommand());
}
else if (e.getSource() == ob.getTextField2()) {
result = String.format("TextField2: %s", e.getActionCommand());
}
else if (e.getSource() == ob.getTextField3()) {
result = String.format("TextField3: %s", e.getActionCommand());
}else{
result = String.format("PasswordField: %s", e.getActionCommand());
}

//display result
JOptionPane.showMessageDialog(null, result, "Result", JOptionPane.PLAIN_MESSAGE);
}
}

vahid-p
چهارشنبه 28 آبان 1393, 14:54 عصر
اگر در کد پست اولتون در MainFrame به جای خط 38 بنویسید :

TextFieldHandler handler = new TextFieldHandler(ob);

درست میشه.
البته این اشتباه به خاطر اشتباه در مرتب نویسی است. حتی در کد دومتون هم اصول مرتب نویسی و شی گرایی رو در نظر نگرفتید. مثلا در کلاس TextFieldHandler در پست اولتون، دو کانستراکتور دارید :
public TextFieldHandler() {}

private FrameFields ob;



//Constructor

public TextFieldHandler(FrameFields ob) {

this.ob = ob;

}




یکی بدون آرگومان یکی با آرگومان. با آرگومان صحیح است چون باید فیلد FrameFields رو مقدار دهی کنید چون در actionPerformed از فیلد ob استفاده کردید. پس شما در کد اول چون در خط 38 کد MainFrame آبجکت ندادید ob مقدار null خواهد داشت.
اما توصیه هایی برای بهتر نوشتن :
1- تمام فیلد های کلاس بالا بنویسید و از نوع private تعریف کنید و برای هر کدام بر حسب نیاز getter , setter بنویسید.
2- کانستراکتورها رو در صورتی بیشتر از یکی بنویسید که مورد نیاز باشد. مثلا در کد اول شما دو کانستراکتور دارید که کانستراکتور اولی هیچ کاری هم انجام نمیدهد. در کد پست آخرتون هم در کانستراکتور دو آرگومان گرفتید و فقط از یکی استفاده کردید! آرگومان اضافه ننویسید یا از آن استفاده کنید.
3- وظیفه هر کلاس را ابتدا مشخص کنید. فلسفه وجود و کارها ( متد ها ) و وِیژگی ها ( فیلد ها ) رو از قبل به صورت واضح بدونید.
4- از اسامی با مسما استفاده کنید. در تمام برنامه شما آبجکت های مختلفی از کلاس های مختلف به اسم ob وجود دارد که نه خود ob مشخصه منظور چیست ( احتمالا مخفف Object در صورتی که در جاوا به جز Primary Types بقیه همه آبجکتن. نمیشه که همش بنویسید Object. تازه از مخفف نویسی استفاده نکنید. معمولا برنامه های جاوا رسمه که اسامی رو یکم طولانی و واضح مینویسن ) و همچین این یک اسم برای همه چیز استفاده شده. در اجرای برنامه اشکالی ایجاد نمیشه، ولی کد نویسی و خوندنش مخصوصا برای من که کد رو ننوشتم خیلی سخت میکنه. این همه اسامی مختلف وجود داره چرا ازش استفاده نکنید؟
5- نکته نه چندان مهم. DriverClass برای کلاس شروع کننده زیاد جالب نیست. چون همه کلاس ها خودش کلاس هستند دیگه ...Class نمیخواد. همچنین Driver معمولا برای چیزای دیگه ای استفاده میشه. میتونید از اسم برنامه یا Main یا Starter اینا استفاده کنید.

مثلا کلاس TextFieldHandler رو براتون تغییر میدم. ( نحوه تعریف TextField هاتون هم زیاد درست نیست، بیشتر آدمو سر در گم میکنه )
اما کلاس TextFieldHandler اگر نخوای شماره TextField رو بدونی میشه اینجوری خلاصه نوشت :
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JOptionPane;

public class TextFieldHandler implements ActionListener{
//Methods
@Override
public void actionPerformed(ActionEvent e) {
String result;
result = "Text : " + e.getActionCommand();
//display result
JOptionPane.showMessageDialog(null, result, "Result", JOptionPane.PLAIN_MESSAGE);
}
}
اما اگر بخوای شمارش رو مشخص کنی اونطوری که نوشته درسته. ولی یه کار دیگه هم میشه کرد. بیای یک کلاس TextField برای خودت تعریف کنی مثلا :
import javax.swing.JTextField;

public class MyTextField extends JTextField{
private int id;

public void setId(int id) {
this.id = id;
}

public int getId() {
return id;
}
}


و از این تکست فیلد استفاده کنی. حالا تو Handler راحت مینویسی :
result = "TextField #"+((MyTextField)e.getSource()).getId()+" : " + e.getActionCommand();

اینجا هم یکی از کاربردهای Casting که در تاپیک دیگه ای سوال کرده بودید. اینجا e.getSource یک آبجکت از کلاس Object که parent بقیه کلاس هاست رو میده. حالا ما میگیم که ما خودمون خبر داریم این از نوع MyTextField هست و بعد بهت اجازه میده از متدهاش مثل getId استفاده کنی.

چقدر طولانی شد! خیلی از اینا نیاز نبود یه جا توضیح بدم و کم کم خودتون آشنا میشدید. ولی حیفم اومد نگم :)

Sina.iRoid
چهارشنبه 28 آبان 1393, 18:07 عصر
سلام.
ممنون از شما. یه چند تا سوال دارم.

من خیلی دوست دارم که تمام کلاس هام مرتب نوشته بشه. یعنی فیلد های کلاسم و اومدم توی کلاس جداگانه ای تعریف کردم که با بقیه کد ها قاطی نشه. اگه دقت داشته باشین کلاس FrameFields چیزه دیگه ای جز تعریف فیلد ها داخلش نیست. چون اگه می خواستم داخل کلاس MainFrame بنویسم خیلی کدها زیاد میشد. این کار درسته یا نه!؟ همانطور که خودتون گفتین من مثلا وظیفه کلاس FrameFields و فقط تعریف فیلد ها گذاشتم.

درضمن در مورد قسمت آخر من مثه شما نوشتم اما برنامه کرش می کنه و میگه که نمی تونه کست کنه.

و اینکه من از کتاب دایتل استفاده می کنم. برای یادگیری شی گرایی این کتاب خوب هست. چون دایتل کلا دوتا کلاس تو همه مثال هاش می نویسه و من خودم به این شکل تغییر میدم.
ممنون از شما.

vahid-p
چهارشنبه 28 آبان 1393, 22:05 عصر
اگر کدهاتون رو مستقیم در MainFrame مینوشتید زیاد تفاوتی نداشت از نظر حجم کد. مگر قرار دادن getter , setter ها. چون عملا اینجور که شما نوشتید حجمش تقریبا یکیه. حالا این بستگی به انتخاب خودتون داره. ولی در صورتی جالب میشد که FrameFields رو مثلا از نوع JPanel اکستند میکردید و اونجا پنلتون رو میساختید و در MainFrame استفاده میکردید با دو خط کد نه این همه set و ...



درضمن در مورد قسمت آخر من مثه شما نوشتم اما برنامه کرش می کنه و میگه که نمی تونه کست کنه.
احتمالا بقیه کدتون رو تغییر ندادید. چون اگر بقیه کدتون مثلا از JTextField استفاده کرده باشین، وقتی Cast کنه، اونوقت متدی مثل getId نداره JTextField که. اگه میخواهید از این استفاده کنید ( یا مثلا TextField ها بخش مهمی از برنامتون هستند، بهتره یک کلاس اکستند شده مثل MyTextField بسازی و بتونی ویژگی های اضافه براش درست کنی ) باید اون JTextField هایی که تعریف کردید رو به MyTextField تغییر بدید.
کتاب خب نمیتونه زیاد حجمش رو زیاد کنه و تعداد کلاس ها رو بیشتر کنه و طبیعیه.
کتاب معروفی هست حالا اینکه خوبه، احتمال زیاد آره.