基于MVC架构的GUI设计

<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 classGamePanel extends 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 components
		add(panel,BorderLayout.NORTH);	   
/*		add(button,BorderLayout.SOUTH);
		add(text,BorderLayout.CENTER);*/
		
		//Create components actions
		panel.addMouseListener(new MouseHandler());
		panel.setFocusable(true);//very important
		panel.addKeyListener(new KeyAction());
		
		//set Frame appearance
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		setTitle("Hello,world");
		pack();
		setVisible(true);
		new Thread(this).start();
	}
	private class KeyAction extends KeyAdapter{

		@Override
		public void keyPressed(KeyEvent e) {
			// TODO Auto-generated method stub
			
			int keyCode = e.getKeyCode();
			System.out.println(keyCode);
		}
		
	}
	
	private class MouseHandler extends MouseAdapter{

		@Override
		public 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();				
			}			
		});
		

	}

	@Override
	public void run() {
		while(true){
			repaint();
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.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>后续的工作
进一步优化
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值