feature: Support drawing board to add text
This commit is contained in:
Binary file not shown.
@@ -13,10 +13,20 @@ CDrawingBoard::CDrawingBoard(CWnd* pParent, Server* IOCPServer, CONTEXT_OBJECT*
|
||||
m_bTransport = true;
|
||||
m_bMoving = false;
|
||||
m_bSizing = false;
|
||||
m_pInputEdit = nullptr;
|
||||
}
|
||||
|
||||
CDrawingBoard::~CDrawingBoard()
|
||||
{
|
||||
if (m_pInputEdit != nullptr) {
|
||||
m_pInputEdit->DestroyWindow();
|
||||
delete m_pInputEdit;
|
||||
m_pInputEdit = nullptr;
|
||||
}
|
||||
if (m_font.GetSafeHandle())
|
||||
m_font.DeleteObject();
|
||||
if (m_pen.GetSafeHandle())
|
||||
m_pen.DeleteObject();
|
||||
}
|
||||
|
||||
void CDrawingBoard::DoDataExchange(CDataExchange* pDX)
|
||||
@@ -32,11 +42,13 @@ BEGIN_MESSAGE_MAP(CDrawingBoard, CDialog)
|
||||
ON_WM_MOUSEMOVE()
|
||||
ON_WM_LBUTTONUP()
|
||||
ON_WM_WINDOWPOSCHANGED()
|
||||
ON_WM_RBUTTONDOWN()
|
||||
ON_COMMAND(ID_DRAWING_TOPMOST, &CDrawingBoard::OnDrawingTopmost)
|
||||
ON_COMMAND(ID_DRAWING_TRANSPORT, &CDrawingBoard::OnDrawingTransport)
|
||||
ON_COMMAND(ID_DRAWING_MOVE, &CDrawingBoard::OnDrawingMove)
|
||||
ON_COMMAND(ID_DRAWING_SIZE, &CDrawingBoard::OnDrawingSize)
|
||||
ON_COMMAND(ID_DRAWING_CLEAR, &CDrawingBoard::OnDrawingClear)
|
||||
ON_COMMAND(IDM_CLEAR_DRAWING, &CDrawingBoard::OnDrawingClear)
|
||||
ON_COMMAND(ID_DRAWING_TEXT, &CDrawingBoard::OnDrawingText)
|
||||
END_MESSAGE_MAP()
|
||||
|
||||
void CDrawingBoard::OnReceiveComplete()
|
||||
@@ -58,8 +70,7 @@ void CDrawingBoard::OnPaint()
|
||||
{
|
||||
CPaintDC dc(this);
|
||||
|
||||
CPen pen(PS_SOLID, 2, RGB(0, 0, 0));
|
||||
CPen* pOldPen = dc.SelectObject(&pen);
|
||||
CPen* pOldPen = dc.SelectObject(&m_pen);
|
||||
|
||||
for (const auto& path : m_paths)
|
||||
{
|
||||
@@ -77,6 +88,15 @@ void CDrawingBoard::OnPaint()
|
||||
dc.LineTo(m_currentPath[i]);
|
||||
}
|
||||
|
||||
CFont* pOldFont = dc.SelectObject(&m_font);
|
||||
dc.SetTextColor(RGB(0, 0, 0));
|
||||
dc.SetBkMode(TRANSPARENT);
|
||||
|
||||
for (const auto& entry : m_Texts)
|
||||
dc.TextOut(entry.first.x, entry.first.y, entry.second);
|
||||
|
||||
dc.SelectObject(pOldFont);
|
||||
|
||||
dc.SelectObject(pOldPen);
|
||||
}
|
||||
|
||||
@@ -162,7 +182,7 @@ void CDrawingBoard::OnDrawingTopmost()
|
||||
void CDrawingBoard::OnDrawingTransport()
|
||||
{
|
||||
m_bTransport = !m_bTransport;
|
||||
BYTE cmd[2] = { CMD_TRANSPORT, m_bTransport };
|
||||
BYTE cmd[2] = { CMD_TRANSPORT, m_bTransport ? 150 : 255 };
|
||||
m_ContextObject->Send2Client((PBYTE)cmd, sizeof(cmd));
|
||||
HMENU hMenu = ::GetMenu(this->GetSafeHwnd());
|
||||
int n = m_bTransport ? MF_CHECKED : MF_UNCHECKED;
|
||||
@@ -199,6 +219,13 @@ BOOL CDrawingBoard::OnInitDialog()
|
||||
str.Format("%s - 画板演示", m_IPAddress);
|
||||
SetWindowText(str);
|
||||
|
||||
m_font.CreateFont(
|
||||
20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
|
||||
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
|
||||
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Arial"));
|
||||
|
||||
m_pen.CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
|
||||
|
||||
HMENU hMenu = ::GetMenu(this->GetSafeHwnd());
|
||||
::CheckMenuItem(hMenu, ID_DRAWING_TOPMOST, MF_BYCOMMAND | MF_CHECKED);
|
||||
::CheckMenuItem(hMenu, ID_DRAWING_TRANSPORT, MF_BYCOMMAND | MF_CHECKED);
|
||||
@@ -211,8 +238,103 @@ void CDrawingBoard::OnDrawingClear()
|
||||
{
|
||||
m_paths.clear();
|
||||
m_currentPath.clear();
|
||||
m_Texts.clear();
|
||||
BYTE cmd[2] = { CMD_DRAW_CLEAR, 0 };
|
||||
m_ContextObject->Send2Client((PBYTE)cmd, sizeof(cmd));
|
||||
if (m_hWnd && IsWindow(m_hWnd))
|
||||
::InvalidateRect(m_hWnd, NULL, TRUE); // 重绘整个窗口,清除痕迹
|
||||
}
|
||||
|
||||
void CDrawingBoard::OnRButtonDown(UINT nFlags, CPoint point)
|
||||
{
|
||||
m_RightClickPos = point; // 记录鼠标点
|
||||
ClientToScreen(&m_RightClickPos); // 变为屏幕坐标
|
||||
|
||||
CMenu menu;
|
||||
menu.LoadMenu(IDR_MENU_POPUP);
|
||||
CMenu* pSubMenu = menu.GetSubMenu(0);
|
||||
|
||||
if (pSubMenu)
|
||||
pSubMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, m_RightClickPos.x, m_RightClickPos.y, this);
|
||||
|
||||
CDialog::OnRButtonDown(nFlags, point);
|
||||
}
|
||||
|
||||
|
||||
void CDrawingBoard::OnDrawingText()
|
||||
{
|
||||
if (m_pInputEdit != nullptr) {
|
||||
m_pInputEdit->DestroyWindow();
|
||||
delete m_pInputEdit;
|
||||
m_pInputEdit = nullptr;
|
||||
}
|
||||
|
||||
CPoint ptClient = m_RightClickPos;
|
||||
ScreenToClient(&ptClient);
|
||||
|
||||
m_pInputEdit = new CEdit();
|
||||
m_pInputEdit->Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
|
||||
CRect(ptClient.x, ptClient.y, ptClient.x + 200, ptClient.y + 25),
|
||||
this, 1234); // 控件 ID 可自定
|
||||
m_pInputEdit->SetFocus();
|
||||
}
|
||||
|
||||
BOOL CDrawingBoard::PreTranslateMessage(MSG* pMsg)
|
||||
{
|
||||
if (m_pInputEdit && pMsg->hwnd == m_pInputEdit->m_hWnd)
|
||||
{
|
||||
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
|
||||
{
|
||||
CString strText;
|
||||
m_pInputEdit->GetWindowText(strText);
|
||||
|
||||
// TODO: 将文字位置和内容加入列表并触发绘图
|
||||
if (!strText.IsEmpty()) {
|
||||
CPoint ptClient = m_RightClickPos;
|
||||
ScreenToClient(&ptClient);
|
||||
m_Texts.push_back(std::make_pair(ptClient, strText));
|
||||
SendTextsToRemote(ptClient, strText);
|
||||
}
|
||||
|
||||
m_pInputEdit->DestroyWindow();
|
||||
delete m_pInputEdit;
|
||||
m_pInputEdit = nullptr;
|
||||
|
||||
return TRUE; // 吞掉回车
|
||||
}
|
||||
}
|
||||
return CDialog::PreTranslateMessage(pMsg);
|
||||
}
|
||||
|
||||
void CDrawingBoard::SendTextsToRemote(const CPoint& pt, const CString& text)
|
||||
{
|
||||
if (text.IsEmpty()) return;
|
||||
|
||||
// 1. 转换为 UTF-8
|
||||
// CString 是 TCHAR 类型,若项目是多字节字符集,则需先转为宽字符
|
||||
#ifdef _UNICODE
|
||||
LPCWSTR lpWideStr = text;
|
||||
#else
|
||||
// 从 ANSI 转为宽字符
|
||||
int wideLen = MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0);
|
||||
std::wstring wideStr(wideLen, 0);
|
||||
MultiByteToWideChar(CP_ACP, 0, text, -1, &wideStr[0], wideLen);
|
||||
LPCWSTR lpWideStr = wideStr.c_str();
|
||||
#endif
|
||||
|
||||
int utf8Len = WideCharToMultiByte(CP_UTF8, 0, lpWideStr, -1, NULL, 0, NULL, NULL);
|
||||
if (utf8Len <= 1) return; // 空或失败
|
||||
|
||||
std::vector<char> utf8Text(utf8Len - 1); // 去掉末尾的 \0
|
||||
WideCharToMultiByte(CP_UTF8, 0, lpWideStr, -1, utf8Text.data(), utf8Len - 1, NULL, NULL);
|
||||
|
||||
// 2. 构造发送 buffer
|
||||
std::vector<char> buffer;
|
||||
buffer.push_back(CMD_DRAW_TEXT); // 自定义命令码
|
||||
|
||||
buffer.insert(buffer.end(), (char*)&pt, (char*)&pt + sizeof(CPoint));
|
||||
buffer.insert(buffer.end(), utf8Text.begin(), utf8Text.end());
|
||||
|
||||
// 3. 发送
|
||||
m_ContextObject->Send2Client((LPBYTE)buffer.data(), (ULONG)buffer.size());
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ public:
|
||||
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
|
||||
afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos);
|
||||
afx_msg void OnSize(UINT nType, int cx, int cy);
|
||||
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
|
||||
|
||||
protected:
|
||||
virtual void DoDataExchange(CDataExchange* pDX);
|
||||
@@ -32,6 +33,10 @@ protected:
|
||||
|
||||
DECLARE_MESSAGE_MAP()
|
||||
|
||||
BOOL PreTranslateMessage(MSG* pMsg);
|
||||
|
||||
void SendTextsToRemote(const CPoint& pt, const CString& inputText);
|
||||
|
||||
private:
|
||||
bool m_bTopMost; // 置顶
|
||||
bool m_bTransport; // 半透明
|
||||
@@ -40,6 +45,11 @@ private:
|
||||
bool m_bDrawing; // 是否正在绘图
|
||||
std::vector<CPoint> m_currentPath; // 当前路径点
|
||||
std::vector<std::vector<CPoint>> m_paths; // 所有路径
|
||||
CPoint m_RightClickPos; // 右键点击位置
|
||||
CEdit* m_pInputEdit = nullptr; // 类成员变量
|
||||
std::vector<std::pair<CPoint, CString>> m_Texts;
|
||||
CFont m_font; // 添加字体成员
|
||||
CPen m_pen; // 画笔
|
||||
public:
|
||||
afx_msg void OnDrawingTopmost();
|
||||
afx_msg void OnDrawingTransport();
|
||||
@@ -47,4 +57,5 @@ public:
|
||||
afx_msg void OnDrawingSize();
|
||||
virtual BOOL OnInitDialog();
|
||||
afx_msg void OnDrawingClear();
|
||||
afx_msg void OnDrawingText();
|
||||
};
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user