From c2d22fc8efd988294ff4a34fd3e31a9743803964 Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期三, 08 一月 2025 11:02:16 +0800
Subject: [PATCH] 1.PLC View的加入,关闭,关联等;

---
 SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close0.ico |    0 
 SourceCode/Bond/BoounionPLC/BoounionPLC.rc                 |    0 
 SourceCode/Bond/BoounionPLC/CBaseView.cpp                  |  415 ++++++++++++++++++++++++
 SourceCode/Bond/BoounionPLC/Common.h                       |   10 
 SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close2.ico |    0 
 SourceCode/Bond/BoounionPLC/PlcView.cpp                    |  126 +++++++
 SourceCode/Bond/BoounionPLC/Resource.h                     |    0 
 SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close3.ico |    0 
 SourceCode/Bond/BoounionPLC/PagePlcList.h                  |    1 
 SourceCode/Bond/BoounionPLC/CBaseView.h                    |   73 ++++
 SourceCode/Bond/BoounionPLC/CMainContainer.cpp             |  110 ++++++
 SourceCode/Bond/BoounionPLC/CMainContainer.h               |   38 ++
 SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp             |  134 +++++++
 SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h               |   12 
 SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close1.ico |    0 
 SourceCode/Bond/BoounionPLC/PlcView.h                      |   43 ++
 SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters    |   18 +
 SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj            |    6 
 SourceCode/Bond/BoounionPLC/PagePlcList.cpp                |   14 
 19 files changed, 995 insertions(+), 5 deletions(-)

diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLC.rc b/SourceCode/Bond/BoounionPLC/BoounionPLC.rc
index d5245a2..e936298 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLC.rc
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLC.rc
Binary files differ
diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj b/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj
index 9f22244..74969b5 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj
@@ -195,12 +195,15 @@
     <ClInclude Include="BlButton.h" />
     <ClInclude Include="BoounionPLC.h" />
     <ClInclude Include="BoounionPLCDlg.h" />
+    <ClInclude Include="CBaseView.h" />
+    <ClInclude Include="CMainContainer.h" />
     <ClInclude Include="Common.h" />
     <ClInclude Include="Configuration.h" />
     <ClInclude Include="Log.h" />
     <ClInclude Include="Model.h" />
     <ClInclude Include="PagePlcList.h" />
     <ClInclude Include="PLC.h" />
+    <ClInclude Include="PlcView.h" />
     <ClInclude Include="Resource.h" />
     <ClInclude Include="stdafx.h" />
     <ClInclude Include="targetver.h" />
@@ -213,11 +216,14 @@
     <ClCompile Include="BlButton.cpp" />
     <ClCompile Include="BoounionPLC.cpp" />
     <ClCompile Include="BoounionPLCDlg.cpp" />
+    <ClCompile Include="CBaseView.cpp" />
+    <ClCompile Include="CMainContainer.cpp" />
     <ClCompile Include="Configuration.cpp" />
     <ClCompile Include="Log.cpp" />
     <ClCompile Include="Model.cpp" />
     <ClCompile Include="PagePlcList.cpp" />
     <ClCompile Include="PLC.cpp" />
+    <ClCompile Include="PlcView.cpp" />
     <ClCompile Include="stdafx.cpp">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters b/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters
index 0b107a9..5344377 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLC.vcxproj.filters
@@ -66,6 +66,15 @@
     <ClInclude Include="PLC.h">
       <Filter>澶存枃浠�</Filter>
     </ClInclude>
+    <ClInclude Include="CBaseView.h">
+      <Filter>澶存枃浠�</Filter>
+    </ClInclude>
+    <ClInclude Include="CMainContainer.h">
+      <Filter>澶存枃浠�</Filter>
+    </ClInclude>
+    <ClInclude Include="PlcView.h">
+      <Filter>澶存枃浠�</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="BoounionPLC.cpp">
@@ -107,6 +116,15 @@
     <ClCompile Include="PLC.cpp">
       <Filter>婧愭枃浠�</Filter>
     </ClCompile>
+    <ClCompile Include="CBaseView.cpp">
+      <Filter>婧愭枃浠�</Filter>
+    </ClCompile>
+    <ClCompile Include="CMainContainer.cpp">
+      <Filter>婧愭枃浠�</Filter>
+    </ClCompile>
+    <ClCompile Include="PlcView.cpp">
+      <Filter>婧愭枃浠�</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="BoounionPLC.rc">
diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp b/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp
index 4ff72a9..dbd2ea0 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.cpp
@@ -7,6 +7,7 @@
 #include "BoounionPLCDlg.h"
 #include "afxdialogex.h"
 #include "Common.h"
+#include "PlcView.h"
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
@@ -55,8 +56,10 @@
 {
 	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 	m_pTopToolbar = nullptr;
+	m_pObserver = nullptr;
 	m_crBkgnd = APP_MAIN_DLG_BACKGROUND;
 	m_hbrBkgnd = nullptr;
+	m_pActiveView = nullptr;
 }
 
 void CBoounionPLCDlg::DoDataExchange(CDataExchange* pDX)
@@ -78,10 +81,53 @@
 	ON_COMMAND(ID_MENU_HELP_ABOUT, &CBoounionPLCDlg::OnMenuHelpAbout)
 	ON_WM_INITMENUPOPUP()
 	ON_MESSAGE(ID_MSG_TOOLBAR_BTN_CLICKED, &CBoounionPLCDlg::OnToolbarBtnClicked)
+	ON_MESSAGE(ID_MSG_VIEW_ACTIVE, &CBoounionPLCDlg::OnViewActive)
+	ON_MESSAGE(ID_MSG_BTN_CLICKED, &CBoounionPLCDlg::OnViewBtnClicked)
+	ON_MESSAGE(ID_MSG_BTN_MENU_ITEM, &CBoounionPLCDlg::OnViewBtnMenuItem)
 END_MESSAGE_MAP()
 
 
 // CBoounionPLCDlg 消息处理程序
+
+
+void CBoounionPLCDlg::InitRxWindows()
+{
+	/* code */
+	// 订阅数据
+	IRxWindows* pRxWindows = RX_GetRxWindows();
+	pRxWindows->enableLog(5);
+	if (m_pObserver == NULL) {
+		m_pObserver = pRxWindows->allocObserver([&](IAny* pAny) -> void {
+			// onNext
+			pAny->addRef();
+			int code = pAny->getCode();
+			if (RX_CODE_SELECT_PLC == code) {
+				CPLC* pPlc;
+				if (pAny->getPtrValue("ptr", (void*&)pPlc)) {
+					ASSERT(m_pMainContainer != nullptr);
+					if (m_pActiveView == nullptr) {
+						m_pActiveView = (CPlcView*)CreatePlcView(pPlc);
+					}
+					ASSERT(m_pActiveView);
+					if (m_pActiveView->GetContext() != (void*)pPlc) {
+						m_pActiveView->SetWindowText(pPlc->getName().c_str());
+						m_pActiveView->SetContext(pPlc);
+					}
+				}
+			}
+
+			pAny->release();
+		}, [&]() -> void {
+			// onComplete
+		}, [&](IThrowable* pThrowable) -> void {
+			// onErrorm
+			pThrowable->printf();
+		});
+
+		theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())
+			->subscribe(m_pObserver);
+	}
+}
 
 BOOL CBoounionPLCDlg::OnInitDialog()
 {
@@ -129,12 +175,19 @@
 	m_pPagePlcList->ShowWindow(SW_SHOW);
 
 
+	// 主窗口页
+	m_pMainContainer = new CMainContainer();
+	m_pMainContainer->Create(IDD_MAIN_CONTAINER, this);
+	m_pMainContainer->ShowWindow(SW_SHOW);
+
+
 	// 菜单
 	CMenu menu;
 	menu.LoadMenu(IDR_MENU_APP);
 	SetMenu(&menu);
 
 
+	InitRxWindows();
 	ShowWindow(SW_MAXIMIZE);
 	Resize();
 
@@ -278,12 +331,28 @@
 		m_pPagePlcList = nullptr;
 	}
 	
+	if (m_pMainContainer != nullptr) {
+		m_pMainContainer->DestroyWindow();
+		delete m_pMainContainer;
+		m_pMainContainer = nullptr;
+	}
+
+	if (m_pActiveView != nullptr) {
+		m_pActiveView->DestroyWindow();
+		delete m_pActiveView;
+		m_pActiveView = nullptr;
+	}	
+
 	if (m_hbrBkgnd != nullptr) {
 		::DeleteObject(m_hbrBkgnd);
 		m_hbrBkgnd = nullptr;
 	}
-}
 
+	if (m_pObserver != nullptr) {
+		m_pObserver->unsubscribe();
+		m_pObserver = NULL;
+	}
+}
 
 void CBoounionPLCDlg::OnSize(UINT nType, int cx, int cy)
 {
@@ -300,13 +369,15 @@
 	CRect rcClient, rcItem;
 	GetClientRect(&rcClient);
 
+	int x = 0;
 	int y = 0;
 	m_pTopToolbar->MoveWindow(0, 0, rcClient.Width(), TOOLBAR_HEIGHT);
 	y += TOOLBAR_HEIGHT;
 
 	m_pPagePlcList->MoveWindow(0, y, PAGE_PLC_LIST_WIDTH, rcClient.Height() - y - 2);
+	x = PAGE_PLC_LIST_WIDTH;
+	m_pMainContainer->MoveWindow(x + 1, y, rcClient.Width() - x - 0, rcClient.bottom - y - 2);
 }
-
 
 HBRUSH CBoounionPLCDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
 {
@@ -424,3 +495,62 @@
 
 	return 0;
 }
+
+LRESULT CBoounionPLCDlg::OnViewActive(WPARAM wParam, LPARAM lParam)
+{
+	CBaseView* pView = (CBaseView*)wParam;
+	int code = (int)lParam;
+	if (code == MA_ACTIVATE || code == MA_ACTIVATEANDEAT) {
+
+	}
+
+
+	return 0;
+}
+
+LRESULT CBoounionPLCDlg::OnViewBtnClicked(WPARAM wParam, LPARAM lParam)
+{
+	int id = (int)lParam;
+	if (id == VIEW_TOOL_BTN_CLOSE) {
+		CloseView((CBaseView*)wParam);
+	}
+
+	return 0;
+}
+
+LRESULT CBoounionPLCDlg::OnViewBtnMenuItem(WPARAM wParam, LPARAM lParam)
+{
+	UINT id = (UINT)lParam;
+
+	return 0;
+}
+
+CBaseView* CBoounionPLCDlg::CreatePlcView(CPLC* pPlc)
+{
+	CPlcView* pDlg = new CPlcView(m_pMainContainer);
+	pDlg->SetContext(pPlc);
+	pDlg->Create(IDD_VIEW_PLC, m_pMainContainer);
+
+	CString strIcon0, strIcon1, strIcon2, strIcon3;
+	strIcon0.Format(_T("%s\\Res\\small_close0.ico"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+	strIcon1.Format(_T("%s\\Res\\small_close1.ico"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+	strIcon2.Format(_T("%s\\Res\\small_close2.ico"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+	strIcon3.Format(_T("%s\\Res\\small_close3.ico"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+	pDlg->AddToolBtn(VIEW_TOOL_BTN_CLOSE,
+		(LPTSTR)(LPCTSTR)strIcon0,
+		(LPTSTR)(LPCTSTR)strIcon1,
+		(LPTSTR)(LPCTSTR)strIcon2,
+		(LPTSTR)(LPCTSTR)strIcon3, "关闭");
+	pDlg->SetWindowText(pPlc->getName().c_str());
+	m_pMainContainer->Resize();
+
+	return pDlg;
+}
+
+void CBoounionPLCDlg::CloseView(CBaseView* pView)
+{
+	pView->DestroyWindow();
+	delete (CBaseView*)pView;
+	m_pActiveView = nullptr;
+	m_pMainContainer->Resize();
+}
diff --git a/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h b/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h
index e6665ec..3c2fb64 100644
--- a/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h
+++ b/SourceCode/Bond/BoounionPLC/BoounionPLCDlg.h
@@ -5,6 +5,9 @@
 #pragma once
 #include "TopToolbar.h"
 #include "PagePlcList.h"
+#include "CMainContainer.h"
+#include "CBaseView.h"
+
 
 // CBoounionPLCDlg 对话框
 class CBoounionPLCDlg : public CDialogEx
@@ -14,8 +17,10 @@
 	CBoounionPLCDlg(CWnd* pParent = NULL);	// 标准构造函数
 
 private:
+	void InitRxWindows();
 	void Resize();
-
+	CBaseView* CreatePlcView(CPLC* pPlc);
+	void CloseView(CBaseView* pView);
 
 private:
 	COLORREF m_crBkgnd;
@@ -23,6 +28,8 @@
 	IObserver* m_pObserver;
 	CTopToolbar* m_pTopToolbar;
 	CPagePlcList* m_pPagePlcList;
+	CMainContainer* m_pMainContainer;
+	CBaseView* m_pActiveView;
 
 
 // 对话框数据
@@ -55,4 +62,7 @@
 	afx_msg void OnUpdateMenuFileExit(CCmdUI* pCmdUI);
 	afx_msg void OnMenuHelpAbout();
 	afx_msg LRESULT OnToolbarBtnClicked(WPARAM wParam, LPARAM lParam);
+	LRESULT OnViewActive(WPARAM wParam, LPARAM lParam);
+	LRESULT OnViewBtnClicked(WPARAM wParam, LPARAM lParam);
+	LRESULT OnViewBtnMenuItem(WPARAM wParam, LPARAM lParam);
 };
diff --git a/SourceCode/Bond/BoounionPLC/CBaseView.cpp b/SourceCode/Bond/BoounionPLC/CBaseView.cpp
new file mode 100644
index 0000000..0484c89
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/CBaseView.cpp
@@ -0,0 +1,415 @@
+#include "stdafx.h"
+#include "CBaseView.h"
+#include "Common.h"
+
+
+#define CAPTION_HEIGHT		36
+#define CAPBTN				99
+
+
+IMPLEMENT_DYNAMIC(CBaseView, CDialogEx)
+
+CBaseView::CBaseView(UINT id, CWnd* pPage) : CDialogEx(id, pPage)
+{
+	m_crBkgnd = BASE_VIEW_BACKGROUND;
+	m_hbrBkgnd = nullptr;
+	m_pContext = nullptr;
+	m_nState = 0;
+	m_pHotBtn = nullptr;
+	m_pPressBtn = nullptr;
+}
+
+CBaseView::~CBaseView()
+{
+}
+
+BEGIN_MESSAGE_MAP(CBaseView, CDialogEx)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_ACTIVATE()
+	ON_WM_NCPAINT()
+	ON_WM_MOUSEACTIVATE()
+	ON_WM_SIZE()
+	ON_WM_NCCALCSIZE()
+	ON_WM_LBUTTONDOWN()
+	ON_WM_NCHITTEST()
+	ON_WM_NCMOUSEMOVE()
+	ON_WM_NCLBUTTONDOWN()
+	ON_WM_NCLBUTTONUP()
+END_MESSAGE_MAP()
+
+HBRUSH CBaseView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
+
+	if (nCtlColor == CTLCOLOR_STATIC) {
+		pDC->SetBkColor(m_crBkgnd);
+	}
+
+	if (m_hbrBkgnd == nullptr) {
+		m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
+	}
+
+	return m_hbrBkgnd;
+}
+
+
+void CBaseView::OnDestroy()
+{
+	CDialogEx::OnDestroy();
+}
+
+void CBaseView::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
+{
+	CDialogEx::OnActivate(nState, pWndOther, bMinimized);
+
+	if (WA_INACTIVE == nState) {
+		OnApply();
+	}
+}
+
+void CBaseView::OnNcPaint()
+{
+	// TODO: 在此处添加消息处理程序代码
+	// 不为绘图消息调用 CDialogEx::OnNcPaint()
+
+
+	RECT rect, rcClient;
+	::GetClientRect(m_hWnd, &rcClient);
+	::ClientToScreen(m_hWnd, (LPPOINT)&rcClient.left);
+	::ClientToScreen(m_hWnd, (LPPOINT)&rcClient.right);
+	::GetWindowRect(m_hWnd, &rect);
+	::OffsetRect(&rcClient, -rect.left, -rect.top);
+
+	rect.right -= rect.left;
+	rect.bottom -= rect.top;
+	rect.left = 0;
+	rect.top = 0;
+
+	HRGN hRgnWnd = CreateRectRgnIndirect(&rect);
+	HRGN hRgnClient = CreateRectRgnIndirect(&rcClient);
+
+	HBRUSH hBrushBK, hBrushFrame;
+	HDC hDC = ::GetWindowDC(m_hWnd);
+	::SelectClipRgn(hDC, hRgnWnd);
+	::ExtSelectClipRgn(hDC, hRgnClient, RGN_DIFF);
+
+
+	// 背景
+	hBrushBK = CreateSolidBrush(m_crBkgnd);
+	::FillRect(hDC, &rect, hBrushBK);
+	DeleteObject(hBrushBK);
+
+
+	// 标题栏,文字,横线
+	HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+	::SelectObject(hDC, hFont);
+
+	RECT rcCaption, rcText;
+	rcCaption = rect;
+	rcCaption.bottom = rcCaption.top + CAPTION_HEIGHT;
+	rcText = rcCaption;
+	rcText.left += 12;
+	char szCaption[64];
+	int nCaptionLen = GetWindowText(szCaption, 64);
+	::DrawText(hDC, szCaption, nCaptionLen, &rcText, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
+
+
+	HPEN hPen = CreatePen(PS_SOLID, 1, RGB(222, 222, 222));
+	HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);
+	::MoveToEx(hDC, 0, rcCaption.bottom, NULL);
+	::LineTo(hDC, rect.right, rcCaption.bottom);
+	::SelectObject(hDC, hOldPen);
+	::DeleteObject(hPen);
+
+
+	// 绘制按钮
+	int y = (rcCaption.bottom - rcCaption.top - 24) / 2;
+	int x = rcCaption.right - 12;
+	for (auto& item : m_toolbtns) {
+		if (item.hIcon != nullptr) {
+			if (!item.bEnable) {
+				DrawIconEx(hDC, x - 24, y,
+					item.hIcon[3], 24, 24, 0, 0, DI_NORMAL);
+			}
+			else if (m_pPressBtn == &item) {
+				DrawIconEx(hDC, x - 24, y,
+					item.hIcon[2], 24, 24, 0, 0, DI_NORMAL);
+			}
+			else if (m_pHotBtn == &item) {
+				DrawIconEx(hDC, x - 24, y,
+					item.hIcon[1], 24, 24, 0, 0, DI_NORMAL);
+			}
+			else {
+				DrawIconEx(hDC, x - 24, y,
+					item.hIcon[0], 24, 24, 0, 0, DI_NORMAL);
+			}
+			x -= 24;
+			x -= 3;
+		}
+	}
+
+
+
+	hBrushFrame = CreateSolidBrush(RGB(255, 0, 0));
+	// ::FrameRect(hDC, &rect, hBrushFrame);
+
+	::DeleteObject(hRgnWnd);
+	::DeleteObject(hRgnClient);
+	DeleteObject(hBrushFrame);
+	::ReleaseDC(m_hWnd, hDC);
+}
+
+int CBaseView::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+	int nRet = CDialogEx::OnMouseActivate(pDesktopWnd, nHitTest, message);
+	GetParent()->GetParent()->SendMessage(ID_MSG_VIEW_ACTIVE, (WPARAM)this, nRet);
+	return nRet;
+}
+
+void CBaseView::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
+{
+	lpncsp->rgrc[0].top += (CAPTION_HEIGHT);
+	CDialogEx::OnNcCalcSize(bCalcValidRects, lpncsp);
+}
+
+void CBaseView::SetContext(void* pContext)
+{
+	m_pContext = pContext;
+}
+
+void* CBaseView::GetContext()
+{
+	return m_pContext;
+}
+
+void CBaseView::OnApply()
+{
+
+}
+
+void CBaseView::Show(CWnd* pParent, LPRECT lprcBtn)
+{
+	RECT rcClient, rcBox;
+	pParent->GetClientRect(&rcClient);
+	pParent->ClientToScreen(&rcClient);
+	GetWindowRect(&rcBox);
+
+	int x = lprcBtn->left;
+	if (x + (rcBox.right - rcBox.left) > rcClient.right) {
+		x = rcClient.right - (rcBox.right - rcBox.left);
+	}
+	SetWindowPos(NULL, x, lprcBtn->bottom + 2, 0, 0, SWP_NOSIZE);
+	ShowWindow(SW_SHOW);
+}
+
+void CBaseView::OnViewActive()
+{
+	m_nState = 1;
+	SendMessage(WM_NCPAINT, 0, 0);
+}
+
+void CBaseView::OnViewInactive()
+{
+	m_nState = 0;
+	SendMessage(WM_NCPAINT, 0, 0);
+}
+
+void CBaseView::AddToolBtn(int id, const char* pszIcon0Path, const char* pszIcon1Path, const char* pszIcon2Path, const char* pszIcon3Path, const char* pszTooltip)
+{
+	TOOLBTN tb;
+	memset(&tb, 0, sizeof(TOOLBTN));
+	tb.id = id;
+	tb.hIcon[0] = (HICON)::LoadImage(GetModuleHandle(NULL), pszIcon0Path, IMAGE_ICON, 24, 24,
+		LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+	tb.hIcon[1] = (HICON)::LoadImage(GetModuleHandle(NULL), pszIcon1Path, IMAGE_ICON, 24, 24,
+		LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+	tb.hIcon[2] = (HICON)::LoadImage(GetModuleHandle(NULL), pszIcon2Path, IMAGE_ICON, 24, 24,
+		LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+	tb.hIcon[3] = (HICON)::LoadImage(GetModuleHandle(NULL), pszIcon3Path, IMAGE_ICON, 24, 24,
+		LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+	strcpy_s(tb.szTooltip, 256, pszTooltip);
+	tb.bEnable = TRUE;
+	m_toolbtns.push_back(tb);
+
+	EnableToolTips(TRUE);
+}
+
+void CBaseView::SetToolBtnEnable(int id, BOOL bEnable)
+{
+	CBaseView::TOOLBTN* pBtn = GetToolBtn(id);
+	if (pBtn != nullptr) {
+		pBtn->bEnable = bEnable;
+		SendMessage(WM_NCPAINT);
+	}
+}
+
+void CBaseView::SetToolBtnMenu(int id, HMENU hMenu)
+{
+	CBaseView::TOOLBTN* pBtn = GetToolBtn(id);
+	if (pBtn != nullptr) {
+		pBtn->hMenu = hMenu;
+	}
+}
+
+void CBaseView::OnLButtonDown(UINT nFlags, CPoint point)
+{
+	// TODO: 在此添加消息处理程序代码和/或调用默认值
+
+	CDialogEx::OnLButtonDown(nFlags, point);
+}
+
+
+LRESULT CBaseView::OnNcHitTest(CPoint point)
+{
+	TOOLBTN* pBtn;
+	LRESULT hit = MyHitTest(point, pBtn);
+	if (hit == HTCAPTION || hit == CAPBTN) {
+		return hit;
+	}
+
+	return CDialogEx::OnNcHitTest(point);
+}
+
+void CBaseView::OnNcMouseMove(UINT nHitTest, CPoint point)
+{
+	TOOLBTN* pLastHot = m_pHotBtn;
+	int code = MyHitTest(point, m_pHotBtn);
+	if (pLastHot != m_pHotBtn) {
+		SendMessage(WM_NCPAINT, 0, 0);
+	}
+
+
+	CDialogEx::OnNcMouseMove(nHitTest, point);
+}
+
+void CBaseView::OnNcLButtonDown(UINT nHitTest, CPoint point)
+{
+	int code = MyHitTest(point, m_pPressBtn);
+	SendMessage(WM_NCPAINT, 0, 0);
+	GetParent()->GetParent()->SendMessage(ID_MSG_VIEW_ACTIVE, (WPARAM)this, MA_ACTIVATE);
+
+	CDialogEx::OnNcLButtonDown(nHitTest, point);
+}
+
+void CBaseView::OnNcLButtonUp(UINT nHitTest, CPoint point)
+{
+	MyHitTest(point, m_pHotBtn);
+	if (m_pPressBtn == m_pHotBtn && m_pPressBtn != nullptr && m_pPressBtn->bEnable) {
+		if (m_pPressBtn->hMenu != nullptr) {
+			int cmd = ::TrackPopupMenu(::GetSubMenu(m_pPressBtn->hMenu, 0),
+				TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
+				point.x, point.y + 2, 0, m_hWnd, NULL);
+			GetParent()->GetParent()->PostMessage(ID_MSG_BTN_MENU_ITEM, (WPARAM)this, cmd);
+		}
+		else {
+			GetParent()->GetParent()->PostMessage(ID_MSG_BTN_CLICKED, (WPARAM)this, m_pPressBtn->id);
+		}
+	}
+	m_pPressBtn = nullptr;
+
+	SendMessage(WM_NCPAINT, 0, 0);
+
+
+	CDialogEx::OnNcLButtonUp(nHitTest, point);
+}
+
+int CBaseView::MyHitTest(POINT& point, TOOLBTN*& pBtn)
+{
+	RECT rcWnd, rcCaption;
+	GetWindowRect(&rcWnd);
+	LRESULT hit = HTNOWHERE;
+	pBtn = nullptr;
+
+	rcCaption.left = rcWnd.left + 2;
+	rcCaption.right = rcWnd.right - 2;
+	rcCaption.top = rcWnd.top += 2;
+	rcCaption.bottom = rcCaption.top + 2 + CAPTION_HEIGHT;
+	if (::PtInRect(&rcCaption, point)) {
+		hit = HTCAPTION;
+
+		RECT rcIcon;
+		rcIcon.top = rcCaption.top + (rcCaption.bottom - rcCaption.top - 24) / 2;
+		rcIcon.bottom = rcIcon.top + 24;
+		rcIcon.right = rcCaption.right - 12;
+		for (auto& item : m_toolbtns) {
+			rcIcon.left = rcIcon.right - 24;
+			if (::PtInRect(&rcIcon, point)) {
+				pBtn = &item;
+				hit = CAPBTN;
+				break;
+			}
+			rcIcon.right = rcIcon.left - 3;
+		}
+	}
+
+	return (int)hit;
+}
+
+CBaseView::TOOLBTN* CBaseView::GetToolBtn(int id)
+{
+	for (auto& item : m_toolbtns) {
+		if (item.id == id) return &item;
+	}
+
+	return nullptr;
+}
+
+BOOL CBaseView::GetBtnRect(int id, LPRECT lprcBtn)
+{
+	RECT rcWnd, rcCaption;
+	GetWindowRect(&rcWnd);
+	::OffsetRect(&rcWnd, -rcWnd.left, -rcWnd.top);
+	rcCaption.left = rcWnd.left + 2;
+	rcCaption.right = rcWnd.right - 2;
+	rcCaption.top = rcWnd.top += 2;
+	rcCaption.bottom = rcCaption.top + 2 + CAPTION_HEIGHT;
+
+	lprcBtn->top = rcCaption.top + (rcCaption.bottom - rcCaption.top - 24) / 2;
+	lprcBtn->bottom = lprcBtn->top + 24;
+	lprcBtn->right = rcCaption.right - 12;
+	for (auto& item : m_toolbtns) {
+		lprcBtn->left = lprcBtn->right - 24;
+		if (item.id == id) {
+			return TRUE;
+		}
+		lprcBtn->right = lprcBtn->left - 3;
+	}
+
+	return FALSE;
+}
+
+INT_PTR CBaseView::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
+{
+	RECT rcClient, rcCaption, rcBtn;
+	::GetClientRect(m_hWnd, &rcClient);
+	rcCaption.bottom = 0;
+	rcCaption.top = rcCaption.bottom - CAPTION_HEIGHT;
+	rcCaption.left = rcClient.left;
+	rcCaption.right = rcClient.right;
+	rcBtn.top = rcCaption.top + (rcCaption.bottom - rcCaption.top - 24) / 2;
+	rcBtn.bottom = rcBtn.top + 24;
+	rcBtn.right = rcCaption.right - 12;
+	::OffsetRect(&rcBtn, +5, -5);		// 5为边框粗的修正
+
+	if ((point.y <= 0)) {
+		for (auto& item : m_toolbtns) {
+			rcBtn.left = rcBtn.right - 24;
+			if (::PtInRect(&rcBtn, point)) {
+				pTI->rect = rcBtn;
+				pTI->hwnd = m_hWnd;
+				pTI->uId = (UINT)1020; // Tooltip should show `1020
+				pTI->lpszText = _tcsdup(item.szTooltip);
+				return pTI->uId;
+			}
+
+			rcBtn.right = rcBtn.left - 3;
+		}
+	}
+
+
+	return CDialogEx::OnToolHitTest(point, pTI);
+}
+
+
diff --git a/SourceCode/Bond/BoounionPLC/CBaseView.h b/SourceCode/Bond/BoounionPLC/CBaseView.h
new file mode 100644
index 0000000..e3b4e2f
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/CBaseView.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#define ID_MSG_VIEW_ACTIVE		WM_USER+2356
+#define ID_MSG_BTN_CLICKED		WM_USER+2357
+#define ID_MSG_BTN_MENU_ITEM	WM_USER+2358
+
+
+class CBaseView : public CDialogEx
+{
+private:
+	typedef struct _TOOLBTN
+	{
+		int id;
+		HICON hIcon[4];
+		char szTooltip[256];
+		BOOL bEnable;
+		HMENU hMenu;
+	} TOOLBTN;
+
+
+	DECLARE_DYNAMIC(CBaseView)
+
+public:
+	CBaseView(UINT id, CWnd* pPage);   // 标准构造函数
+	virtual ~CBaseView();
+
+
+public:
+	void OnViewActive();
+	void OnViewInactive();
+	void AddToolBtn(int id, const char* pszIcon0Path, const char* pszIcon1Path, const char* pszIcon2Path, const char* pszIcon3Path, const char* pszTooltip);
+	void SetToolBtnEnable(int id, BOOL bEnable);
+	void SetToolBtnMenu(int id, HMENU hMenu);
+	void Show(CWnd* pParent, LPRECT lprcBtn);
+	virtual void SetContext(void* pContext);
+	void* GetContext();
+	virtual void OnApply();
+
+private:
+	int MyHitTest(POINT& point, TOOLBTN*& pBtn);
+	CBaseView::TOOLBTN* GetToolBtn(int id);
+	BOOL GetBtnRect(int id, LPRECT lprcBtn);
+
+
+private:
+	std::vector<TOOLBTN> m_toolbtns;
+	TOOLBTN* m_pHotBtn;
+	TOOLBTN* m_pPressBtn;
+	int m_nState;
+
+
+protected:
+	COLORREF m_crBkgnd;
+	HBRUSH m_hbrBkgnd;
+	void* m_pContext;
+
+
+	DECLARE_MESSAGE_MAP()
+public:
+	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+	afx_msg void OnDestroy();
+	afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
+	afx_msg void OnNcPaint();
+	afx_msg int OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message);
+	afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp);
+	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+	afx_msg LRESULT OnNcHitTest(CPoint point);
+	afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point);
+	afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point);
+	afx_msg void OnNcLButtonUp(UINT nHitTest, CPoint point);
+	virtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO* pTI) const;
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/CMainContainer.cpp b/SourceCode/Bond/BoounionPLC/CMainContainer.cpp
new file mode 100644
index 0000000..66365e6
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/CMainContainer.cpp
@@ -0,0 +1,110 @@
+锘�// CMainContainer.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "BoounionPLC.h"
+#include "Common.h"
+#include "CMainContainer.h"
+#include "afxdialogex.h"
+
+
+// CMainContainer 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CMainContainer, CDialogEx)
+
+CMainContainer::CMainContainer(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_MAIN_CONTAINER, pParent)
+{
+	m_crBkgnd = MAIN_CONTAINER_BACKGROUND;
+	m_hbrBkgnd = nullptr;
+}
+
+CMainContainer::~CMainContainer()
+{
+}
+
+void CMainContainer::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CMainContainer, CDialogEx)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_SIZE()
+END_MESSAGE_MAP()
+
+
+// CMainContainer 娑堟伅澶勭悊绋嬪簭
+
+
+BOOL CMainContainer::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	// TODO:  鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+
+HBRUSH CMainContainer::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
+
+	if (nCtlColor == CTLCOLOR_STATIC) {
+		pDC->SetBkColor(m_crBkgnd);
+	}
+
+	if (m_hbrBkgnd == nullptr) {
+		m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
+	}
+
+	return m_hbrBkgnd;
+}
+
+
+void CMainContainer::OnDestroy()
+{
+	CDialogEx::OnDestroy();
+
+	if (m_hbrBkgnd != nullptr) {
+		::DeleteObject(m_hbrBkgnd);
+	}
+}
+
+
+void CMainContainer::OnSize(UINT nType, int cx, int cy)
+{
+	CDialogEx::OnSize(nType, cx, cy);
+	Resize();
+}
+
+void CMainContainer::Resize()
+{
+	CRect rcClient;
+	GetClientRect(&rcClient);
+
+	// 鍏堝彇寰楀瓙绐楀彛鏁伴噺
+	int count = 0;
+	CWnd* pClild = FindWindowEx(m_hWnd, NULL, NULL, NULL);
+	while (pClild != nullptr) {
+		count++;
+		pClild = FindWindowEx(m_hWnd, pClild->m_hWnd, NULL, NULL);
+	}
+
+	pClild = FindWindowEx(m_hWnd, NULL, NULL, NULL);
+	while (pClild != nullptr) {
+		pClild->MoveWindow(&rcClient);
+		if (::GetProp(pClild->GetSafeHwnd(), "Home") == (HANDLE)1) {
+			pClild->ShowWindow(count == 1 ? SW_SHOW : SW_HIDE);
+		}
+		else {
+			pClild->ShowWindow(SW_SHOW);
+		}
+
+		pClild = FindWindowEx(m_hWnd, pClild->m_hWnd, NULL, NULL);
+	}
+}
diff --git a/SourceCode/Bond/BoounionPLC/CMainContainer.h b/SourceCode/Bond/BoounionPLC/CMainContainer.h
new file mode 100644
index 0000000..ff3d271
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/CMainContainer.h
@@ -0,0 +1,38 @@
+锘�#pragma once
+
+
+// CMainContainer 瀵硅瘽妗�
+
+class CMainContainer : public CDialogEx
+{
+	DECLARE_DYNAMIC(CMainContainer)
+
+public:
+	CMainContainer(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	virtual ~CMainContainer();
+
+
+public:
+	void Resize();
+
+
+private:
+	COLORREF m_crBkgnd;
+	HBRUSH m_hbrBkgnd;
+
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_MAIN_CONTAINER };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 鏀寔
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+	afx_msg void OnDestroy();
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+};
diff --git a/SourceCode/Bond/BoounionPLC/Common.h b/SourceCode/Bond/BoounionPLC/Common.h
index e58f33c..ee7db10 100644
--- a/SourceCode/Bond/BoounionPLC/Common.h
+++ b/SourceCode/Bond/BoounionPLC/Common.h
@@ -6,9 +6,17 @@
 #define RX_CODE_LOG						1000
 #define RX_CODE_ADD_PLC					1001
 #define RX_CODE_REMOVE_PLC				1002
+#define RX_CODE_SELECT_PLC				1003
 
 
 /* 定制颜色 */
 #define APP_MAIN_DLG_BACKGROUND			RGB(255, 255, 255)	
 #define TOP_TOOLBAR_BACKGROUND			RGB(240, 240, 240)	
-#define PAGE_PLC_LIST_BACKGROUND		RGB(245, 245, 250)	
\ No newline at end of file
+#define PAGE_PLC_LIST_BACKGROUND		RGB(245, 245, 250)	
+#define MAIN_CONTAINER_BACKGROUND		RGB(252, 252, 255)
+#define BASE_VIEW_BACKGROUND			RGB(252, 252, 255)
+#define PLC_VIEW_BACKGROUND				RGB(252, 252, 255)
+
+
+/* 按钮id */
+#define VIEW_TOOL_BTN_CLOSE				0x1016
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/PagePlcList.cpp b/SourceCode/Bond/BoounionPLC/PagePlcList.cpp
index a153ccb..3e0cc18 100644
--- a/SourceCode/Bond/BoounionPLC/PagePlcList.cpp
+++ b/SourceCode/Bond/BoounionPLC/PagePlcList.cpp
@@ -35,6 +35,7 @@
 	ON_WM_CTLCOLOR()
 	ON_WM_DESTROY()
 	ON_WM_SIZE()
+	ON_MESSAGE(ID_MSG_TREE_CLICK_ITEM, OnTreeClickItem)
 END_MESSAGE_MAP()
 
 
@@ -160,6 +161,17 @@
 		rcItem.Width(), rcItem.Height());
 }
 
+LRESULT CPagePlcList::OnTreeClickItem(WPARAM wParam, LPARAM lParam)
+{
+	HTREEITEM hItem = (HTREEITEM)wParam;
+	ASSERT(hItem);
+	CPLC* pPlc = (CPLC*)m_treeCtrl.GetItemData(hItem);
+	ASSERT(pPlc);
+	theApp.m_model.notifyPtr(RX_CODE_SELECT_PLC, pPlc);
+
+	return 0;
+}
+
 void CPagePlcList::ReadPLCList()
 {
 	//m_treeCtrl.InsertItem("PLC1", nullptr, nullptr);
@@ -186,4 +198,4 @@
 	}
 
 	return nullptr;
-}
\ No newline at end of file
+}
diff --git a/SourceCode/Bond/BoounionPLC/PagePlcList.h b/SourceCode/Bond/BoounionPLC/PagePlcList.h
index a2bf39e..fd9e31f 100644
--- a/SourceCode/Bond/BoounionPLC/PagePlcList.h
+++ b/SourceCode/Bond/BoounionPLC/PagePlcList.h
@@ -42,4 +42,5 @@
 	afx_msg void OnDestroy();
 	afx_msg void OnSize(UINT nType, int cx, int cy);
 	virtual BOOL PreTranslateMessage(MSG* pMsg);
+	afx_msg LRESULT OnTreeClickItem(WPARAM wParam, LPARAM lParam);
 };
diff --git a/SourceCode/Bond/BoounionPLC/PlcView.cpp b/SourceCode/Bond/BoounionPLC/PlcView.cpp
new file mode 100644
index 0000000..9fac0f2
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/PlcView.cpp
@@ -0,0 +1,126 @@
+#include "stdafx.h"
+#include "PlcView.h"
+#include "BoounionPLC.h"
+#include "Common.h"
+
+
+// CPlcView 对话框
+
+IMPLEMENT_DYNAMIC(CPlcView, CBaseView)
+
+CPlcView::CPlcView(CWnd* pParent /*=nullptr*/)
+	: CBaseView(IDD_VIEW_PLC, pParent)
+{
+	m_pObserver = nullptr;
+	m_crBkgnd = PLC_VIEW_BACKGROUND;
+	m_hbrBkgnd = nullptr;
+	m_pPlc = nullptr;
+}
+
+
+CPlcView::~CPlcView()
+{
+}
+
+void CPlcView::DoDataExchange(CDataExchange* pDX)
+{
+	CBaseView::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CPlcView, CBaseView)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_SIZE()
+END_MESSAGE_MAP()
+
+// CComponentData1Dlg 消息处理程序
+
+void CPlcView::SetContext(void* pContext)
+{
+	CBaseView::SetContext(pContext);
+
+	if (::IsWindow(m_hWnd) && m_pContext != nullptr) {
+		SetDlgItemText(IDC_LABEL_PLC_NAME, ((CPLC*)m_pContext)->getName().c_str());
+	}
+}
+
+void CPlcView::InitRxWindows()
+{
+	/* code */
+	// 订阅数据
+	IRxWindows* pRxWindows = RX_GetRxWindows();
+	if (m_pObserver == NULL) {
+		m_pObserver = pRxWindows->allocObserver([&](IAny* pAny) -> void {
+			// onNext
+			pAny->addRef();
+			int code = pAny->getCode();
+
+			pAny->release();
+		}, [&]() -> void {
+			// onComplete
+		}, [&](IThrowable* pThrowable) -> void {
+			// onErrorm
+			pThrowable->printf();
+		});
+
+		theApp.m_model.getObservable()->observeOn(pRxWindows->mainThread())
+			->subscribe(m_pObserver);
+	}
+}
+
+BOOL CPlcView::OnInitDialog()
+{
+	CBaseView::OnInitDialog();
+
+	if (m_pContext != nullptr) {
+		SetDlgItemText(IDC_LABEL_PLC_NAME, ((CPLC*)m_pContext)->getName().c_str());
+	}
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 异常: OCX 属性页应返回 FALSE
+}
+
+
+HBRUSH CPlcView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+	HBRUSH hbr = CBaseView::OnCtlColor(pDC, pWnd, nCtlColor);
+
+	if (nCtlColor == CTLCOLOR_STATIC) {
+		pDC->SetBkColor(m_crBkgnd);
+	}
+
+	if (m_hbrBkgnd == nullptr) {
+		m_hbrBkgnd = CreateSolidBrush(m_crBkgnd);
+	}
+
+	return m_hbrBkgnd;
+}
+
+void CPlcView::OnDestroy()
+{
+	CBaseView::OnDestroy();
+
+	if (m_hbrBkgnd != nullptr) {
+		::DeleteObject(m_hbrBkgnd);
+	}
+
+	if (m_pObserver != NULL) {
+		m_pObserver->unsubscribe();
+		m_pObserver = NULL;
+	}
+}
+
+void CPlcView::OnSize(UINT nType, int cx, int cy)
+{
+	CBaseView::OnSize(nType, cx, cy);
+}
+
+void CPlcView::Resize()
+{
+	int y = 12;
+	int x = 0;
+	CRect rcClient, rcItem;
+	CWnd* pItem;
+	GetClientRect(&rcClient);
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/BoounionPLC/PlcView.h b/SourceCode/Bond/BoounionPLC/PlcView.h
new file mode 100644
index 0000000..da44c6d
--- /dev/null
+++ b/SourceCode/Bond/BoounionPLC/PlcView.h
@@ -0,0 +1,43 @@
+#pragma once
+#include "CBaseView.h"
+#include "PLC.h"
+
+
+class CPlcView :public CBaseView
+{
+	DECLARE_DYNAMIC(CPlcView)
+
+public:
+	CPlcView(CWnd* pParent = nullptr);
+	~CPlcView();
+
+public:
+	virtual void SetContext(void* pContext);
+
+private:
+	void InitRxWindows();
+	void Resize();
+
+private:
+	COLORREF m_crBkgnd;
+	HBRUSH m_hbrBkgnd;
+	IObserver* m_pObserver;
+	CPLC* m_pPlc;
+
+
+	// 对话框数据
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_VIEW_PLC};
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+	afx_msg void OnDestroy();
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+};
+
diff --git a/SourceCode/Bond/BoounionPLC/Resource.h b/SourceCode/Bond/BoounionPLC/Resource.h
index 03dfed2..c8ecf6c 100644
--- a/SourceCode/Bond/BoounionPLC/Resource.h
+++ b/SourceCode/Bond/BoounionPLC/Resource.h
Binary files differ
diff --git a/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close0.ico b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close0.ico
new file mode 100644
index 0000000..84682fb
--- /dev/null
+++ b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close0.ico
Binary files differ
diff --git a/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close1.ico b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close1.ico
new file mode 100644
index 0000000..f8723ee
--- /dev/null
+++ b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close1.ico
Binary files differ
diff --git a/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close2.ico b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close2.ico
new file mode 100644
index 0000000..0debeac
--- /dev/null
+++ b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close2.ico
Binary files differ
diff --git a/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close3.ico b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close3.ico
new file mode 100644
index 0000000..ff2405e
--- /dev/null
+++ b/SourceCode/Bond/x64/BoounionPLC/Debug/Res/small_close3.ico
Binary files differ

--
Gitblit v1.9.3