基于MVC架构的GUI设计

来源:互联网 发布:淘宝商家怎么找客服 编辑:程序博客网 时间:2024/06/06 03:27
<1>问题背景
   复杂的GUI设计需要良好的框架结构,在阅读一些游戏源码时,看到有些ugly的设计,十分不爽,本文主要探讨gui项目的模型(model)视图(view)控制器(Controller)的分配与布置。
<2>问题的解决方法和思路

   (1) View:主类 继承 JFrame

   (2) Model:主类私有成员为,在主类的构造函数中初始化

   (3)Controller:定义为主类的内部私有类,这样便于访问主类的成员函数和成员变量model

   (4)不同组件之间的互动,通过model桥接,即信息状态改变都反映在model中,一旦希望View重画,调用主类repaint()进行通知,主类的相关组件自动从model中获取改变。

   (5) 其他技术细节:

    A) main中只负责new主类对象,调用主类的initialize()进行添加组件,注册监听器,组件都定义为intialize()的函数中的局部变量, GUI APP由单独的事件委派线程负责管理。

体现为如下main代码

  public staticvoid main(String[] args) {      

        EventQueue.invokeLater(new Runnable(){

            publicvoid run() {

                HelloAppapp=newHelloApp();

                app.initialize();             

            }          

        });

    }

 

    B)   void initialize(){   

         //default:BorderLayout       

        //Create components,(1)-(3)可以用子类代替,外观设置改在构造函数中

        JComponentpanel=newGamePanel();//(1)

        panel.setBackground(Color.BLACK);//(2)

        panel.setPreferredSize(new Dimension(320,240));//(3) /*      

        JButtonbutton=new JButton("hello");

        JTextFieldtext=new JTextField();*/

       

        //add components

        add(panel,BorderLayout.NORTH);  

/*      add(button,BorderLayout.SOUTH);

        add(text,BorderLayout.CENTER);*/

       

        //Create components actions

        panel.addMouseListener(new MouseHandler());

       

        //set Frame appearance

        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        setTitle("Helloworld");

        pack();

        setVisible(true);

    }

 

     C) 复杂的组件,需要设置外观,可以使用继承机制建立类,以利于initialize代码简洁。

如这里的Jpanel对象,需要覆盖paintComponent方法,必须新建子类。

    private classGamePanelextends JPanel{

        privateinti=0;

        protectedvoid paintComponent(Graphicsg) {                  

            super.paintComponent(g);

            g.setColor(Color.WHITE);

            g.drawString(model.getInfo(), 10, 10);

            System.out.println("paint:"+(++i));       

        }      

    }

 

     D)事件处理器定义为内部类,以方便访问主类私有信息,注意组件并不是作为主类的私有局部变量,事件处理器不能访问initialize内部的局部变量,二者传递信息的途径是model,通知途径是事件委派线程,简单的事件逻辑可以基于匿名内部类或者Lambda表达式完成(JDK1.8以上)

  private class MouseHandlerextends MouseAdapter{

        publicvoid mouseClicked(MouseEventevent) {

            int x=event.getX();

            int y=event.getY();

            model.setInfo("("+x+", "+y+")");

            repaint();//通知委派线程重绘

        }      

    }


<3>程序实现
package game;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Dimension;import java.awt.EventQueue;import java.awt.Graphics;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import java.util.Date;import java.util.Timer;import javax.swing.JButton;import javax.swing.JComponent;import javax.swing.JPanel;import javax.swing.JTextField;public class HelloApp extends javax.swing.JFrame implements Runnable{private Model model;public HelloApp(){model = new Model();}void initialize(){     //default: BorderLayout//Create components,(1)-(3)可以用子类代替,外观设置改在构造函数中JComponent panel=new GamePanel();//(1)panel.setBackground(Color.BLACK);//(2)panel.setPreferredSize(new Dimension(320,240));//(3) /*JButton button=new JButton("hello");JTextField text=new JTextField();*///add componentsadd(panel,BorderLayout.NORTH);   /*add(button,BorderLayout.SOUTH);add(text,BorderLayout.CENTER);*///Create components actionspanel.addMouseListener(new MouseHandler());panel.setFocusable(true);//very importantpanel.addKeyListener(new KeyAction());//set Frame appearancesetDefaultCloseOperation(DISPOSE_ON_CLOSE);setTitle("Hello,world");pack();setVisible(true);new Thread(this).start();}private class KeyAction extends KeyAdapter{@Overridepublic void keyPressed(KeyEvent e) {// TODO Auto-generated method stubint keyCode = e.getKeyCode();System.out.println(keyCode);}}private class MouseHandler extends MouseAdapter{@Overridepublic void mouseClicked(MouseEvent event) {int x=event.getX();int y=event.getY();model.setInfo("("+x+", "+y+")");repaint();//通知重绘}}private class GamePanel extends JPanel{private int i=0;protected void paintComponent(Graphics g) {super.paintComponent(g);g.setColor(Color.WHITE);//g.fillRect(30, 30, 50, 50);int x=(int)(Math.random()*320);int y=(int)(Math.random()*240);g.drawString(model.getInfo(), x, y);//System.out.println("paint:"+(++i));}}public static void main(String[] args) {EventQueue.invokeLater(new Runnable(){public void run() {HelloApp app=new HelloApp();    app.initialize();}});}@Overridepublic void run() {while(true){repaint();try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}class Model{private String info;Model(){info="Hello, world";}public void setInfo(String info){this.info=info;}public String getInfo(){return info;}}
<4>遇到的问题

<5>后续的工作
进一步优化
原创粉丝点击