零食网站色调搭配怎麽做,平台公司经营范围,zeronet网站开发,微信小程序设计软件场景
在开发Windows和macOS的界面软件时#xff0c;Windows用的是WTL/Win32技术#xff0c;而macOS用的是Cocoa技术。而两种技术的本地语言一个主打是C,另一个却是Object-c。界面软件的源码随着项目功能增多而增多#xff0c;这就会给同步Windows和macOS的功能造成很大负担…场景
在开发Windows和macOS的界面软件时Windows用的是WTL/Win32技术而macOS用的是Cocoa技术。而两种技术的本地语言一个主打是C,另一个却是Object-c。界面软件的源码随着项目功能增多而增多这就会给同步Windows和macOS的功能造成很大负担。 有大部分的调用底层逻辑界面数据搜索等代码逻辑会重复写两遍用C和Object-C写。初步估计这部分代码至少占界面代码的50%。这无疑会影响产品发布速度影响软件质量可能有些逻辑两个平台不能完全一样增大了开发的工作量这部分时间无疑是浪费了的。有什么办法可以把这部分代码进行重用
说明 界面代码往往就是获取数据显示数据之后点击按钮处理数据。这就需要获取数据处理数据需要和平台相关的界面代码剥离显示数据部分依赖平台的框架进行数据绘制。 按照这种逻辑最好的办法就是数据获取和处理使用C语言处理处理这些和界面无关的逻辑代码。 当然如果有特殊情况也可以用.mm文件(这种是Object-C和C混编的文件后缀来调用Object-C平台接口处理。比如presenter_mac.mm和presenter_win.cpp。 界面架构MVP架构可以满足这个要求。当然这和Object-c和C可以混编有些关系如果是Swift语言不能直接调用C类需要通过桥接调用Object-C,再通过Object-C调用C来处理。 使用C处理跨平台逻辑最好使用C11以上标准因为这个标准多了很多有用的库和特性节省MVP架构的很多代码如lambda,thread,functional等。 看看MVP架构的分层主要是以下三层。很好理解Presenter作为View和Model的通讯层起到了连接视图和底层模型逻辑处理的作用也起到了跨平台时处理不同平台界面框架获取数据的本地实现的桥梁。
View - Presenter - Model这里说的Presenter可根据界面语言的实现进行基于本地的实现比如macOS下Presenter层需要处理NSString作为字符串存储的数据而在Windows下需要处理std::wstring作为字符串处理的数据。这些数据如果传递给Model,那么需要转换为std::string的UTF8编码进行处理。 在这个三层模型里依赖关系需要注意设计, 切不可以互相依赖。 View依赖Presenter接口View里有Presenter的成员变量Presenter的实例需要通过方法注入。这样如果View更换不同的Presenter也可以通过注入的方法。 View通过成员变量presenter_调用它的方法。异步处理通过传入std::function绑定的方法给Presenter当Presenter处理完之后再调用绑定的方法类似回调函数的处理。
private:shared_ptrPresenter presenter_ nullptr;...
void CView::setPresenter(shared_ptrPresenter presenter)
{presenter_ presenter;
}Presenter依赖Model接口注意说的接口是根据实际项目的复杂度来定义虚拟类接口如果实现只有一个定义一个普通类就行。Presenter通过成员变量model_调用它的方法。异步处理通过传入std::function绑定的方法给Model当Model处理完之后再调用绑定的方法类似回调函数的处理。 protected:shared_ptrModel model_;...
void Presenter::setModel(shared_ptrModel model)
{model_ model;
}
例子
以下的虚拟listview是MVP架构的实现。
View.h
// View.h : interface of the CView class
//
/#pragma once#include utility
#include string
#include vector
#include memory
#include atlmisc.h
#include atlctrls.h
#include atlctrlx.h
#include GdiPlus.husing namespace std;class Presenter;enum
{kMyButtonId WM_USER1,kMyButtonId2,kMyButtonId3,kMyListViewId
};class CView : public CWindowImplCView
{
public:DECLARE_WND_CLASS(NULL)BOOL PreTranslateMessage(MSG* pMsg);BEGIN_MSG_MAP_EX(CView)MSG_WM_CREATE(OnCreate)MESSAGE_HANDLER(WM_PAINT, OnPaint)NOTIFY_HANDLER(kMyListViewId,NM_CLICK,OnNMClickListResult)NOTIFY_HANDLER(kMyListViewId,LVN_GETDISPINFO,OnGetListViewData)NOTIFY_HANDLER(kMyListViewId,LVN_ODCACHEHINT,OnPrepareListViewData)NOTIFY_HANDLER(kMyListViewId,LVN_ODFINDITEM,OnFindListViewData)COMMAND_RANGE_HANDLER_EX(kMyButtonId,kMyButtonId3,OnCommandIDHandlerEX)REFLECT_NOTIFICATIONS()END_MSG_MAP()void setPresenter(shared_ptrPresenter presenter);protected:
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL /*bHandled*/)int OnCreate(LPCREATESTRUCT lpCreateStruct);LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL /*bHandled*/);void UpdateLayout();LRESULT OnNMClickListResult(int idCtrl,LPNMHDR pnmh,BOOL bHandled);LRESULT OnGetListViewData(int idCtrl,LPNMHDR pnmh,BOOL bHandled);LRESULT OnPrepareListViewData(int idCtrl,LPNMHDR pnmh,BOOL bHandled);LRESULT OnFindListViewData(int idCtrl,LPNMHDR pnmh,BOOL bHandled);void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl);void ReloadMockData();void ReloadListView();private:std::wstring GetControlText(HWND hwnd,wchar_t* buf NULL);CListViewCtrl listview_;CFont font_normal_;CFont font_bold_;CBrushHandle brush_white_;CBrushHandle brush_hollow_;CBrush brush_red_;CButton buttonReloadMockData_;CButton buttonReloadListView_;CButton buttonDeleteListViewOneRow_;private:shared_ptrPresenter presenter_ nullptr;
};
View.cpp
// View.cpp : implementation of the CView class
//
/#include stdafx.h
#include resource.h
#include utility
#include sstream
#include stdint.h
#include assert.h
#include Strsafe.h#include View.h
#include CommCtrl.h
#include string
#include regex
#include Presenter.h
#include Photo.husing namespace std;BOOL CView::PreTranslateMessage(MSG* pMsg)
{return FALSE;
}LRESULT CView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL /*bHandled*/)
{CPaintDC dc(m_hWnd);CMemoryDC mdc(dc,dc.m_ps.rcPaint);CRect rect_client;GetClientRect(rect_client);mdc.FillSolidRect(rect_client,RGB(255,255,255));//TODO: Add your drawing code herereturn 0;
}static HFONT GetFont(int pixel,bool bold,const wchar_t* font_name)
{LOGFONT lf; memset(lf, 0, sizeof(LOGFONT)); // zero out structure lf.lfHeight pixel; // request a 8-pixel-height fontif(bold){lf.lfWeight FW_BOLD; }lstrcpy(lf.lfFaceName, font_name); // request a face name ArialHFONT font ::CreateFontIndirect(lf);return font;
}std::wstring CView::GetControlText(HWND hwnd,wchar_t* buf)
{auto length ::GetWindowTextLength(hwnd);bool bufNull false;if(!buf){buf new wchar_t[length1]();bufNull true;}::GetWindowText(hwnd,buf,length1);std::wstring str(buf);if(bufNull)delete []buf;return str;
}static std::wstring GetProductBinDir()
{static wchar_t szbuf[MAX_PATH]; GetModuleFileName(NULL,szbuf,MAX_PATH); PathRemoveFileSpec(szbuf);int length lstrlen(szbuf);szbuf[length] L\\;szbuf[length1] 0;return std::wstring(szbuf);
}LRESULT CView::OnGetListViewData(int idCtrl,LPNMHDR pnmh,BOOL bHandled)
{NMLVDISPINFO* plvdi (NMLVDISPINFO*) pnmh;auto iItem plvdi-item.iItem;if (-1 iItem)return 0;auto count presenter_-getPhotoCount();if(count iItem)return 0;auto photo presenter_-getPhoto(iItem);if(plvdi-item.mask LVIF_TEXT){switch(plvdi-item.iSubItem){case 0:StringCchCopy(plvdi-item.pszText, plvdi-item.cchTextMax, to_wstring((int64_t)iItem1).c_str());break;case 1:StringCchCopy(plvdi-item.pszText, plvdi-item.cchTextMax, photo-name.c_str());break;case 2:StringCchCopy(plvdi-item.pszText, plvdi-item.cchTextMax, photo-format.c_str());break;case 3:StringCchCopy(plvdi-item.pszText, plvdi-item.cchTextMax, photo-createDate.c_str());break;}}return 0;
}LRESULT CView::OnPrepareListViewData(int idCtrl,LPNMHDR pnmh,BOOL bHandled)
{return 0;
}LRESULT CView::OnFindListViewData(int idCtrl,LPNMHDR pnmh,BOOL bHandled)
{ return 0;
}LRESULT CView::OnNMClickListResult(int idCtrl,LPNMHDR pnmh,BOOL bHandled)
{return 0;
}void CView::OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
{switch(nID){case kMyButtonId:{ReloadMockData();MessageBox(L刷新模拟数据完成);break;}case kMyButtonId2:{ReloadListView();MessageBox(L重新加载表格数据完成);break;}case kMyButtonId3:{int iItem -1;while((iItem listview_.GetNextItem(iItem,LVNI_SELECTED)) ! -1){presenter_-removePhoto(iItem);listview_.DeleteItem(iItem);iItem--;}MessageBox(L已删除);break;}}
}void CView::ReloadListView()
{listview_.SetItemCount(0);presenter_-clearPhotos();
}void CView::ReloadMockData()
{presenter_-loadPhotos([this]() {listview_.SetItemCount(presenter_-getPhotoCount());});}int CView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{font_normal_ ::GetFont(16,false,LArial);font_bold_ ::GetFont(16,true,LArial);brush_hollow_ AtlGetStockBrush(HOLLOW_BRUSH);brush_white_ AtlGetStockBrush(WHITE_BRUSH);brush_red_.CreateSolidBrush(RGB(255,0,0));// 1.创建CListViewCtrllistview_.Create(m_hWnd,0,NULL,WS_CHILD | WS_TABSTOP |WS_VISIBLE|LVS_ALIGNLEFT|LVS_REPORT|LVS_SHOWSELALWAYS|WS_BORDER|LVS_OWNERDATA,0,kMyListViewId);listview_.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_DOUBLEBUFFER);listview_.SetFont(font_normal_);auto header listview_.GetHeader();header.SetFont(font_bold_);listview_.SetBkColor(RGB(255,255,255));listview_.InsertColumn(0,LNo.,LVCFMT_LEFT,40);listview_.InsertColumn(1,LName,LVCFMT_LEFT,100);listview_.InsertColumn(2,LFormat,LVCFMT_LEFT,100);listview_.InsertColumn(3,LCreate Date,LVCFMT_LEFT,100);// 2.创建按钮buttonReloadMockData_.Create(m_hWnd,0,L加载新数据,WS_CHILD|WS_VISIBLE,0,kMyButtonId);buttonReloadMockData_.SetFont(font_normal_);buttonReloadListView_.Create(m_hWnd,0,L刷新表格,WS_CHILD|WS_VISIBLE,0,kMyButtonId2);buttonReloadListView_.SetFont(font_normal_);buttonDeleteListViewOneRow_.Create(m_hWnd,0,L删除选中行,WS_CHILD|WS_VISIBLE,0,kMyButtonId3);buttonDeleteListViewOneRow_.SetFont(font_normal_);UpdateLayout();return 0;
}void CView::UpdateLayout()
{CRect rect;GetClientRect(rect);CClientDC dc(m_hWnd);dc.SelectFont(font_normal_);CSize size_control(500,300);CRect rect_control CRect(CPoint(20,20),size_control);listview_.MoveWindow(rect_control);CSize size_button;buttonReloadMockData_.GetIdealSize(size_button);rect_control CRect(CPoint(rect_control.left,rect_control.bottom10),size_button);buttonReloadMockData_.MoveWindow(rect_control);CSize sizeButton2;buttonReloadListView_.GetIdealSize(sizeButton2);rect_control CRect(CPoint(rect_control.right10,rect_control.top),sizeButton2);buttonReloadListView_.MoveWindow(rect_control);CSize sizeButton3;buttonDeleteListViewOneRow_.GetIdealSize(sizeButton3);rect_control CRect(CPoint(rect_control.right10,rect_control.top),sizeButton3);buttonDeleteListViewOneRow_.MoveWindow(rect_control);
}void CView::setPresenter(shared_ptrPresenter presenter)
{presenter_ presenter;
}Presenter.h #ifndef PRESENTER_H
#define PRESENTER_H#include vector
#include memory
#include functionalusing namespace std;class Photo;
class Model;typedef functionvoid() FuncSimple;class Presenter
{public:shared_ptrPhoto getPhoto(int i);void clearPhotos();size_t getPhotoCount();void removePhoto(int nItem);void loadPhotos(FuncSimple func);void setModel(shared_ptrModel model);protected:vectorshared_ptrPhoto photos_;protected:shared_ptrModel model_;FuncSimple funcLoadFinish_;
};#endif // !PRESENTER_H
Presenter.cpp
#include stdafx.h
#include Presenter.h
#include Photo.h
#include Model.h
#include dispatch_queue.hshared_ptrPhoto Presenter::getPhoto(int i)
{return (i photos_.size()) ? photos_[i] : nullptr;
}void Presenter::clearPhotos()
{photos_.clear();
}size_t Presenter::getPhotoCount()
{return photos_.size();
}void Presenter::removePhoto(int nItem)
{if (nItem getPhotoCount()) {auto ite photos_.begin() nItem;photos_.erase(ite);}
}void Presenter::loadPhotos(FuncSimple func)
{funcLoadFinish_ func;model_-loadPhoto([this](vectorshared_ptrPhoto* photos) {// 需要把数据发送到主线程更新,这样才不会出现多线程访问共享数据冲突。DispatchQueue::DispatchAsync(DispatchQueue::DispatchGetMainQueue(), new FuncSimple([this, photos]() {photos_.insert(photos_.end(), photos-begin(), photos-end());if (funcLoadFinish_)funcLoadFinish_();delete photos;}));});
}void Presenter::setModel(shared_ptrModel model)
{model_ model;
}
Model.h #ifndef MODEL_H
#define MODEL_H#include functional
#include memory
#include vector
#include Photo.husing namespace std;typedef functionvoid(vectorshared_ptrPhoto*) FuncLoadPhoto;class Model
{
public:void loadPhoto(FuncLoadPhoto func);protected:FuncLoadPhoto funcLoadPhoto_;
};#endif
Model.cpp
#include stdafx.h
#include Model.h
#include thread
#include Photo.husing namespace std;void Model::loadPhoto(FuncLoadPhoto func)
{funcLoadPhoto_ func;// 模拟异步加载数据thread t1([this]() {wchar_t buf[MAX_PATH] { 0 };int index 0;auto photos new vectorshared_ptrPhoto();for (int i 0; i 10000; i, index) {auto photo new Photo();wsprintf(buf, LName-%d, index);photo-name buf;wsprintf(buf, LFormat-%d, index);photo-format buf;wsprintf(buf, LcreateDate-%d, index);photo-createDate buf;photos-push_back(move(shared_ptrPhoto(photo)));}if (funcLoadPhoto_)funcLoadPhoto_(photos);});t1.detach();
}dispatch_queue.h
#ifndef __DISPATCH_QUEUE_H
#define __DISPATCH_QUEUE_H#include Windows.h
#include WinUser.h
#include functionalenum
{WMC_DISPATCH_MAIN_QUEUE WM_USER1000
};typedef struct DispatchQueueObject1
{DWORD threadId;HWND m_hwnd;UINT msg;
}DispatchQueueObject;class DispatchQueue
{
public:static DWORD GetMainThreadId();static bool IsCurrentMainThread();static void DispatchQueueInit(HWND hwnd);static DispatchQueueObject* DispatchGetMainQueue();static void FreeDispatchMainQueue(DispatchQueueObject* dqo);static void DispatchAsync(DispatchQueueObject* queue,std::functionvoid()* callback);
};#endifdispatch_queue.cpp
#include stdafx.h#include dispatch_queue.hstatic HWND gMainHwnd NULL;
static DWORD gMainThreadId 0;bool DispatchQueue::IsCurrentMainThread()
{return GetMainThreadId() GetCurrentThreadId();
}DWORD DispatchQueue::GetMainThreadId()
{return gMainThreadId;
}void DispatchQueue::DispatchQueueInit(HWND hwnd)
{gMainHwnd hwnd;gMainThreadId GetCurrentThreadId();
}void DispatchQueue::DispatchAsync(DispatchQueueObject* queue,std::functionvoid()* callback)
{if(queue-threadId){::PostThreadMessage(queue-threadId,queue-msg,(WPARAM)callback,0);}else{::PostMessage(queue-m_hwnd,queue-msg,(WPARAM)callback,0);}FreeDispatchMainQueue(queue);
}DispatchQueueObject* DispatchQueue::DispatchGetMainQueue()
{DispatchQueueObject* object (DispatchQueueObject*)malloc(sizeof(DispatchQueueObject));memset(object,0,sizeof(DispatchQueueObject));object-m_hwnd gMainHwnd;object-msg WMC_DISPATCH_MAIN_QUEUE;return object;
}void DispatchQueue::FreeDispatchMainQueue(DispatchQueueObject* dqo)
{free(dqo);
}MainFrm.h
// MainFrm.h : interface of the CMainFrame class
//
/#pragma once#include View.h
#include Presenter.h
#include Model.h
#include dispatch_queue.hclass CMainFrame : public CFrameWindowImplCMainFrame, public CUpdateUICMainFrame,public CMessageFilter, public CIdleHandler
{
public:DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)CView m_view;virtual BOOL PreTranslateMessage(MSG* pMsg);virtual BOOL OnIdle();BEGIN_UPDATE_UI_MAP(CMainFrame)END_UPDATE_UI_MAP()BEGIN_MSG_MAP(CMainFrame)MESSAGE_HANDLER(WM_CREATE, OnCreate)MESSAGE_HANDLER(WM_DESTROY, OnDestroy)COMMAND_ID_HANDLER(ID_APP_EXIT, OnFileExit)COMMAND_ID_HANDLER(ID_FILE_NEW, OnFileNew)COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)MESSAGE_HANDLER(WMC_DISPATCH_MAIN_QUEUE, OnDispatchMainQueueEvent)CHAIN_MSG_MAP(CUpdateUICMainFrame)CHAIN_MSG_MAP(CFrameWindowImplCMainFrame)END_MSG_MAP()// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL /*bHandled*/)LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL /*bHandled*/);LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL bHandled);LRESULT OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL /*bHandled*/);LRESULT OnFileNew(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL /*bHandled*/);LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL /*bHandled*/);LRESULT OnDispatchMainQueueEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL bHandled){std::functionvoid()* func (std::functionvoid()*)wParam;(*func)();delete func;bHandled TRUE;return 0;}
};
MainFrm.cpp
// MainFrm.cpp : implmentation of the CMainFrame class
//
/#include stdafx.h
#include resource.h#include aboutdlg.h
#include MainFrm.hBOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{if(CFrameWindowImplCMainFrame::PreTranslateMessage(pMsg))return TRUE;return m_view.PreTranslateMessage(pMsg);
}BOOL CMainFrame::OnIdle()
{return FALSE;
}LRESULT CMainFrame::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL /*bHandled*/)
{// 注册线程接收异步主线程消息的窗口DispatchQueue::DispatchQueueInit(m_hWnd);auto presenter make_sharedPresenter();auto model make_sharedModel();presenter-setModel(model);m_view.setPresenter(presenter);m_hWndClient m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);// register object for message filtering and idle updatesCMessageLoop* pLoop _Module.GetMessageLoop();ATLASSERT(pLoop ! NULL);pLoop-AddMessageFilter(this);pLoop-AddIdleHandler(this);return 0;
}LRESULT CMainFrame::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL bHandled)
{// unregister message filtering and idle updatesCMessageLoop* pLoop _Module.GetMessageLoop();ATLASSERT(pLoop ! NULL);pLoop-RemoveMessageFilter(this);pLoop-RemoveIdleHandler(this);bHandled FALSE;return 1;
}LRESULT CMainFrame::OnFileExit(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL /*bHandled*/)
{PostMessage(WM_CLOSE);return 0;
}LRESULT CMainFrame::OnFileNew(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL /*bHandled*/)
{// TODO: add code to initialize documentreturn 0;
}LRESULT CMainFrame::OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL /*bHandled*/)
{CAboutDlg dlg;dlg.DoModal();return 0;
}
项目下载
https://download.csdn.net/download/infoworld/89445554 注意: 关于WTL的开发学习可以订阅我的课程: 使用WTL进行Windows桌面应用开发-第一部_在线视频教程-CSDN程序员研修院
参考 观察者模式在项目中实际使用例子 观察者模式在项目中实际使用例子2 QQ NT全新重构探寻24岁QQ大重构背后的思考_跨端开发