码迷,mamicode.com
首页 > 其他好文 > 详细

2015年8月13日——关于设计模式

时间:2015-08-13 20:00:08      阅读:116      评论:0      收藏:0      [点我收藏+]

标签:

3周之前老板让做一个天气预报模块,目标样式:

技术分享

经过一番自以为是的编程,最终完成了任务。

今天突然让我做另一个项目,里面需要用到天气预报、时钟(拆开)。同时同事手里也有一个项目,也需要用到两个模块拆开的情况。

目标样式:

技术分享

突然发现之前写的模块存在很多不足,耦合度较高。常用接口未开放出来。经过一天的修改,将模块拆了开来。给同事”审批“也通过了。

目标样式:

技术分享技术分享

因为最终考虑到客户的修改,所以部分参数的修改是在XML中进行的。(这部分参数是初始化时设定的数值)

经过这件事,才明白设计模式的重要性,虽然说重剑无锋,大巧不工,但是一些神妙的招式还是必须要学的。公司有实体书,是在是爽歪歪了。。。

代码以及使用范例献上:

天气预报头文件:

技术分享
#ifndef GET_WEATHER_INFO
#define GET_WEATHER_INFO

#include "ofxTextUtilsUL2.h"
#include "ofxTrueTypeFontUL2.h"
#include "ofxJSON.h"
#include "TextReader.h"

/*
* 获取天气信息,两种方式,一种是json,一种是xml
* XML调整城市信息的方式与JSON不一样
*/


#define IMG_INFO_FILE    "weather/WeatherStateSwap.json"

typedef struct WeatherStruct
{
    // 基础信息
    wstring cityName;        // 中文城市名
    string cityName_En;        // 英文城市名

    wstring time;            // 当前时间

    // 天气
    int stateIndex;            // 天气状态序号
    string state1;            // 天气状况详情
    string state2;            // 天气状况
    wstring stateDetail;    // 详细天气信息

    // 温度
    wstring maxTemp,        // 最高气温
        minTemp,            // 最低气温
        curTemp;            // 当前气温

    //
    wstring windState;        // 风况
    wstring windDir;        // 风向
    wstring windPower;        // 风力

    // 图片
    ofImage img[2];

}WeatherStruct, *pWeatherStruct;



// 函数指针,默认方式是json
bool GetWeatherInfoXML(string url, WeatherStruct& ws);
bool GetWeatherInfoJSon(string url, WeatherStruct& ws);

class GetWeatherInfo
{
public:
    GetWeatherInfo();
    ~GetWeatherInfo();

    void setup(string filePath);
    void update();
    void draw();

    // 查看是否有天气信息
    bool GetWeatherInfoState(){ return mHasInfo; }

    // 设置天气图标颜色
    void SetWeatherImgColor(ofColor cl){ mColorWeatherImg = cl; }
    // 设置天气信息的颜色
    void SetWeatherInfoColor(ofColor cl){ mColorWeatherInfo = cl; }
    // 设置温度信息的颜色
    void SetTempColor(ofColor cl){ mColorTemp = cl; }

    // 设置整个绘制区域
    void SetErea(ofRectangle rt){ rtWholeErea = rt; }
    // 设置获取天气的间隔
    void SetParseGap(int gap){ mParseGap = gap; curTime = gap + 1; }
    // 查看偶去天气的间隔
    int GetParGap(){ return mParseGap; }

    // 获取天气信息数据,对外开放,可以随意使用
    WeatherStruct& GetWeatherData(){ return mWeatherData; }

private:
    // 获取天气信息
    bool(*GetInfo)(string url, WeatherStruct& ws);
    
    // 获取设置信息
    bool GetSettingInfo(string filePath);

private:
    // 数据
    WeatherStruct mWeatherData;    // 天气信息
    ofColor mColorWeatherImg, mColorWeatherInfo, mColorTemp;

    // 接口地址
    string mUrl;

    // 区域
    ofRectangle rtWholeErea, rtWeatherImg;
    ofPoint posWeatherInfo, posTemp;

    // 字体
    ofxTrueTypeFontUL2 fontWeatherInfo, fontTemp;


    // 城市名称
    string mCityName;

    bool mHasInfo;                // 有效信息的标志位,如果没有或者信息错误,该值为 false
    int mParseGap;                // 解析间隔
    int curTime;
};


#endif
View Code

天气预报Cpp文件:

技术分享
#include "GetWeatherInfo.h"

//--------------------------------------------------------
GetWeatherInfo::GetWeatherInfo()
{
    curTime = mParseGap + 1;
    mHasInfo = false;
    // 默认是xml方式加载
    GetInfo = GetWeatherInfoXML;
}


//--------------------------------------------------------
GetWeatherInfo::~GetWeatherInfo()
{
}

//--------------------------------------------------------
void GetWeatherInfo::setup(string filePath)
{
    // 获取设置信息
    GetSettingInfo(filePath);
    
}

//--------------------------------------------------------
void GetWeatherInfo::draw()
{
    ofSetColor(mColorWeatherImg);
    mWeatherData.img[0].setAnchorPercent(0.5, 0.5);
    mWeatherData.img[0].draw(rtWeatherImg.x + rtWholeErea.x,
 rtWeatherImg.y + rtWholeErea.y, rtWeatherImg.width, rtWeatherImg.height);

    ofSetColor( mColorWeatherInfo);
    fontWeatherInfo.drawString(mWeatherData.stateDetail,
        posWeatherInfo.x + rtWholeErea.x, posWeatherInfo.y +rtWholeErea.y);

    ofSetColor(mColorTemp);
    fontTemp.drawString(mWeatherData.curTemp + L"°C",
        posTemp.x + rtWholeErea.x, posTemp.y + rtWholeErea.y);

}

//--------------------------------------------------------
void GetWeatherInfo::update()
{
    if (curTime >= mParseGap)
        curTime = 0;
    else
    {
        curTime += ofGetLastFrameTime();
        return;
    }

    if (!GetInfo(mUrl, mWeatherData))
    {
        mHasInfo = false;
        return;
    }

    mHasInfo = true;
    float t = (float)mWeatherData.img[0].height / (float)mWeatherData.img[0].width;

    rtWeatherImg.height = rtWeatherImg.width * t;
}

//--------------------------------------------------------
bool GetWeatherInfo::GetSettingInfo(string filePath)
{
    // 从设置文件中加载设置信息
    ofXml xml;
    xml.load(filePath);
    xml.exists("mainErea");

    // 城市名字
    xml.setTo("mainErea[0]");
    rtWholeErea.x = ofToFloat(xml.getAttribute("x"));
    rtWholeErea.y = ofToFloat(xml.getAttribute("y"));
    rtWholeErea.width = ofToFloat(xml.getAttribute("width"));
    rtWholeErea.height = ofToFloat(xml.getAttribute("height"));



    // 天气图标
    xml.setTo("weatherImg");
    rtWeatherImg.x = ofToFloat(xml.getAttribute("x"))*rtWholeErea.width;
    rtWeatherImg.y = ofToFloat(xml.getAttribute("y"))*rtWholeErea.height;
    rtWeatherImg.width = ofToFloat(xml.getAttribute("width"))*rtWholeErea.width;



    // 天气信息字体
    xml.setToParent();
    xml.setTo("weatherInfo");
    posWeatherInfo.x = ofToFloat(xml.getAttribute("x"))*rtWholeErea.width;
    posWeatherInfo.y = ofToFloat(xml.getAttribute("y"))*rtWholeErea.height;

    fontWeatherInfo.loadFont( xml.getAttribute("fontStyle"),
        ofToInt( xml.getAttribute("fontSize") ) );

    // 温度字体
    xml.setToParent();
    xml.setTo("tempInfo");
    posTemp.x = ofToFloat(xml.getAttribute("x"))*rtWholeErea.width;
    posTemp.y = ofToFloat(xml.getAttribute("y"))*rtWholeErea.height;

    fontTemp.loadFont(xml.getAttribute("fontStyle"),
        ofToInt(xml.getAttribute("fontSize")));

    xml.setToParent();
    // 城市名字
    xml.setToParent();
    xml.exists("city");

    xml.setTo("city[0]");
    mCityName = xml.getAttribute("cityName");
    
    // 排除掉china字符串,防止解析出错
    if (mCityName == "china")
    {
        ofLogError("can`t determine which city") << endl;
        return false;
    }
    
    xml.setToParent();
    xml.exists("loadWay");
    
    // 加载方式
    xml.setTo("loadWay[0]");
    
    // 链接地址
    if (xml.getAttribute("wayName") == "xml")
    {
        mUrl = xml.getAttribute("urlInfo") + mCityName + ".xml";
    }
    else if (xml.getAttribute("wayName") == "json")
    {
        mUrl = xml.getAttribute("urlInfo") + mCityName + ".xml";
    }
    else
        return false;

    // 加载信息的时间间隔
    SetParseGap( ofToInt( xml.getAttribute("parseGap") ) );
    
    return true;
}

string test;
//--------------------------------------------------------
bool GetWeatherInfoXML(string url, WeatherStruct& ws)
{
    // 解析XML数据
    ofHttpResponse response;
    response = ofLoadURL(url);

    ofXml mXML;
    // 从缓存中加载数据
    if (mXML.loadFromBuffer(response.data)){
        ofLogNotice("load xml succeed") << endl;
    }
    else{
        ofLogNotice("failed to load xml") << endl;
        return false;
    }

    // 取第一个城市的天气即可
    mXML.setTo("city[0]");
    // 分析数据
    ws.cityName = ofStringUTF8ToWide(mXML.getAttribute("cityname"));        // 城市名称
    ws.state1 = mXML.getAttribute("state1");                                // 天气状态1
    ws.state2 = mXML.getAttribute("state2");                                // 天气状态2
    ws.stateDetail = ofStringUTF8ToWide(mXML.getAttribute("stateDetailed"));// 天气详细信息
    ws.minTemp = ofStringUTF8ToWide(mXML.getAttribute("tem2"));                // 最低温度
    ws.maxTemp = ofStringUTF8ToWide(mXML.getAttribute("tem1"));                // 最高温度
    ws.curTemp = ofStringUTF8ToWide(mXML.getAttribute("temNow"));            // 当前温度
    ws.windState = ofStringUTF8ToWide(mXML.getAttribute("windState"));        // 风况
    ws.windDir = ofStringUTF8ToWide(mXML.getAttribute("windDir"));            // 风向
    ws.windPower = ofStringUTF8ToWide(mXML.getAttribute("windPower"));        // 风力
    
    // 加载图片---------------------------------------------------------------------
    // 从JSON文件中映射获得图片名称
    ofxJSONElement imgInfos;    // 图片名称集合
    imgInfos.open(IMG_INFO_FILE);


    ws.img[0].loadImage(imgInfos["WeatherStateSwap"]["imgDir"].asString() + "/"
        + imgInfos["WeatherStateSwap"][ws.state1].asString());
    ws.img[1].loadImage(imgInfos["WeatherStateSwap"]["imgDir"].asString() + "/"
        + imgInfos["WeatherStateSwap"][ws.state2].asString());

    // 加载图片---------------------------------------------------------------------

    return true;
}


//--------------------------------------------------------
bool GetWeatherInfoJSon(string url, WeatherStruct& ws)
{
    ofxJSONElement json;
    if (!json.open(url))
    {
        ofLogError("failed to open json url") << endl;
        return false;
    }
    
    ws.cityName = ofStringUTF8ToWide( json["weatherinfo"]["city"].asString() );
    ws.stateDetail = ofStringUTF8ToWide(json["weatherinfo"]["weather"].asString());

    return true;
}
View Code

时钟头文件:

技术分享
#ifndef OFX_MY_CLOCK
#define OFX_MY_CLOCK

#include "ofmain.h"
#include <cmath>

/*
    在指定位置画一只表
*/
#define HOUR_PCT    0.5
#define MINUTE_PCT    0.7
#define SECOND_PCT    0.85

class ofxMyClock
{
public:
    ofxMyClock();
    ~ofxMyClock();

    void setup();
    void update();
    void draw();


    void SetRadius(double r);
    void SetCenter(ofPoint p){ mCenter = p; }
    void SetColor(ofColor cl){ mColor = cl; }

private:
    // 生成表盘图片
    void GenerateFaceImg();

    // 根据时间计算各个指针尾点
    void ComputeHourAngle();
    void ComputeMinuteAngle();
    void ComputeSecondAngle();


private:
    ofPoint mCenter;            // 中心
    ofColor mColor;

    ofPoint ereaFace;            // 表盘绘制区域

    ofRectangle mRtHour, mRtMinute, mRtSecond;        // 表针的绘制区域
    double mHourAngle, mMinuteAngle, mSecondAngle;    // 三个指针的旋转角度

    ofImage mClockImg;                                // 表盘的图片
    ofImage mNeedleImg;                                // 指针的图片

    int alphaGap;                                    // 透明块的宽度
    int mW, mH, mNumPixels;
    int mSize;
    unsigned char* mOriClockFaceData,                // 表盘图片原始数据
        *mCurClockFaceData;
    

    int mHour;            // 小时
    int mMinute;        // 分钟
    int mSecond;        //


    double mCurTime;
};

#endif
View Code

时钟cpp文件:

技术分享
#include "ofxMyClock.h"

//--------------------------------------------------------
ofxMyClock::ofxMyClock()
{
    // 加载表盘图片
    mClockImg.loadImage("clock/face.png");
    mClockImg.setAnchorPercent(0.5, 0.5);

    mNumPixels = mClockImg.bpp / 8;
    mW = mClockImg.width;
    mH = mClockImg.height;
    // 图片像素数据,用于实时修改图片数据
    mCurClockFaceData = mClockImg.getPixels();        // 用于生成即时数据

    mSize = mW * mH * mNumPixels;
    mOriClockFaceData = new unsigned char[mSize];    // 保存了原始数据
    memcpy( mOriClockFaceData, mCurClockFaceData, mSize);

    // 透明覆盖条宽度
    alphaGap = 30;

    // 加载表针图片
    mNeedleImg.loadImage("clock/needle.png");
    mNeedleImg.setAnchorPercent(0.5, 1);

    mCenter.x = ofGetWidth() / 2;
    mCenter.y = ofGetHeight() / 2;

    // 随窗口缩放
    if ( ofGetWidth()<ofGetHeight() )
        ereaFace.x = ereaFace.y = ofGetWidth() / 4;
    else
        ereaFace.x = ereaFace.y = ofGetHeight() / 4;

    SetRadius(ereaFace.x/2);

    mHour = mMinute = mSecond = 0;
    mCurTime = 0;

    mColor = ofColor(255,255,255,255);
}

//--------------------------------------------------------
ofxMyClock::~ofxMyClock()
{
    delete[] mOriClockFaceData;
}

//--------------------------------------------------------
void ofxMyClock::setup()
{
    ComputeSecondAngle();
    ComputeMinuteAngle();
    ComputeHourAngle();
    GenerateFaceImg();
}

//--------------------------------------------------------
void ofxMyClock::draw()
{
    ofSetColor(mColor);
    // 表盘
    mClockImg.setAnchorPercent(0.5, 0.5);
    mClockImg.draw(mCenter.x, mCenter.y, ereaFace.x, ereaFace.y);

    ofPushMatrix();
    ofTranslate(mCenter.x, mCenter.y);

    // 时针
    ofPushMatrix();
    ofRotateZ(mHourAngle);
    mNeedleImg.draw(mRtHour);
    ofPopMatrix();

    // 分针
    ofPushMatrix();
    ofRotateZ(mMinuteAngle);
    mNeedleImg.draw(mRtMinute);
    ofPopMatrix();

    // 秒针
    ofPushMatrix();
    ofRotateZ(mSecondAngle);
    mNeedleImg.draw(mRtSecond);
    ofPopMatrix();
    
    ofPopMatrix();

    ofSetColor(255, 255, 255, 255);
}

//--------------------------------------------------------
void ofxMyClock::update()
{
    if (mCurTime > 1)
    {
        ComputeSecondAngle();
        
        if (mCurTime > 60)
        {
            ComputeMinuteAngle();
            ComputeHourAngle();
            
            mCurTime = 0;
        }
        GenerateFaceImg();
    }
    mCurTime += ofGetLastFrameTime();
}

//--------------------------------------------------------
void ofxMyClock::SetRadius(double r)
{
    ereaFace.x = ereaFace.y = r * 2;

    float t = r * mNeedleImg.getWidth() / mNeedleImg.height;

    // 表针的绘制范围(未随着窗口缩放前)
    // 时针是半径的 0.5
    mRtHour.x = mRtHour.y = 0;
    mRtHour.width = t * 1.5;
    mRtHour.height = r*HOUR_PCT;

    // 分针是半径的0.7
    mRtMinute.x = mRtMinute.y = 0;
    mRtMinute.width = t;
    mRtMinute.height = r*MINUTE_PCT;

    // 秒针是半径的 0.85
    mRtSecond.x = mRtSecond.y = 0;
    mRtSecond.width = t*0.5;
    mRtSecond.height = r*SECOND_PCT;
}

//--------------------------------------------------------
void ofxMyClock::ComputeHourAngle()
{
    mHour = ofGetHours();
    mHourAngle = (mHour % 12) * 30 + mMinute / 2.0;
}

//--------------------------------------------------------
void ofxMyClock::ComputeMinuteAngle()
{
    mMinute = ofGetMinutes();
    mMinuteAngle = mMinute * 6.0;
}

//--------------------------------------------------------
void ofxMyClock::ComputeSecondAngle()
{
    mSecond = ofGetSeconds();
    mSecondAngle = mSecond * 6.0;
}

//--------------------------------------------------------
void ofxMyClock::GenerateFaceImg()
{
    // 先把图片还原成原图片
    memcpy(mCurClockFaceData, mOriClockFaceData, mSize);

    // 思路:让两个“矩形条”随着时针分针旋转,他们所经过的地方都覆盖为透明,实现举行条的位置是0度角时的位置
    // 最快速的办法是利用自定义混合公式 + FBO,使用贴图实现,速度最快

    double angleHour = mHourAngle*DEG_TO_RAD;
    double angleMinute = mMinuteAngle*DEG_TO_RAD;
    double angleSecond = mSecondAngle*DEG_TO_RAD;
    double sin1, cos1, sin2, cos2, sin3, cos3;

    //
    int x1, x2, y1, y2, x3, y3;
    double hW = mW / 2, hH = mH /2;

    for (double y = 0; y < hH/4;y+=0.5)
    {
        for (double x = hW - alphaGap; x < hW+ alphaGap; x+=0.3)
        {
            double angle = atan( (x - hW) / (y - hH) );

            sin1 = sin(angleHour + angle - PI/2),
                cos1 = cos(angleHour + angle - PI / 2);
            
            sin2 = sin(angleMinute + angle - PI / 2),
                cos2 = cos(angleMinute + angle - PI / 2);

            sin3 = sin(angleSecond + angle - PI / 2),
                cos3 = cos(angleSecond + angle - PI / 2);

            // 计算旋转后的坐标
            double dist = ofDist( hW, hH, x, y);
            y1 = (dist*sin1 +hW);
            x1 = (dist*cos1 +hH);

            y2 = (dist*sin2 + hW);
            x2 = (dist*cos2 + hH);

            y3 = (dist*sin3 + hW);
            x3 = (dist*cos3 + hH);

            if (x1 > mW - 1 || x1 < 0 || y1<0 || y1> mH - 1)
                continue;
            if (x2 > mW - 1 || x2 < 0 || y2<0 || y2> mH - 1)
                continue;
            if (x3 > mW - 1 || x3 < 0 || y3<0 || y3> mH - 1)
                continue;

            mCurClockFaceData[y1 * mW *4 + x1 * 4 + 3] = 0;
            mCurClockFaceData[y2 * mW * 4 + x2 * 4 + 3] = 0;
            mCurClockFaceData[y3 * mW * 4 + x3 * 4 + 3] = 0;
        }
    }

    mClockImg.update();
}
View Code

使用范例:

头文件

技术分享
#pragma once

#include "ofMain.h"
#include "ofxMyClock.h"
#include "GetWeatherInfo.h"

class ofApp : public ofBaseApp{

public:

    void setup();
    void update();
    void draw();

    void keyPressed(int key);
    void keyReleased(int key);
    void mouseMoved(int x, int y);
    void mouseDragged(int x, int y, int button);
    void mousePressed(int x, int y, int button);
    void mouseReleased(int x, int y, int button);
    void mouseEntered(int x, int y);
    void mouseExited(int x, int y);
    void windowResized(int w, int h);
    void dragEvent(ofDragInfo dragInfo);
    void gotMessage(ofMessage msg);

    ofxMyClock clock;

    ofPoint clockCenter;

    GetWeatherInfo weatherCls;

};
View Code

Cpp文件:

技术分享
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofDisableAntiAliasing();
    ofSetFrameRate(60);
    ofSetWindowPosition(100, 100);

    weatherCls.setup("settings.xml");
    clock.setup();

    clock.SetColor(ofColor(255,255,255,255));
}
string ss;
//--------------------------------------------------------------
void ofApp::update(){

    ofSetWindowTitle( ofToString( ofGetFrameRate() ) );
    weatherCls.update();
    clock.update();
}

//--------------------------------------------------------------
void ofApp::draw(){

    ofBackgroundGradient(ofColor(200, 200, 200), ofColor(120, 120, 120),OF_GRADIENT_CIRCULAR);
    
    ofSetColor(255, 255, 255, 255);
    weatherCls.draw( );
    
    clock.draw();
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y){
    clockCenter.x = x, clockCenter.y = y;
    clock.SetCenter(clockCenter);

    clock.SetRadius( ofDist(x,y, ofGetWidth()/2, ofGetHeight()/2)/2 );
}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

    
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}


//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y){

}

//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){
}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
View Code

 

继续修炼。

2015年8月13日——关于设计模式

标签:

原文地址:http://www.cnblogs.com/SecretMan001/p/4727629.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!