#include "stdafx.h" #include "JobSlotGrid.h" #ifdef _DEBUG #define new DEBUG_NEW #endif IMPLEMENT_DYNAMIC(CJobSlotGrid, CWnd) BEGIN_MESSAGE_MAP(CJobSlotGrid, CWnd) ON_WM_PAINT() ON_WM_ERASEBKGND() ON_WM_MOUSEMOVE() ON_WM_MOUSELEAVE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() END_MESSAGE_MAP() CJobSlotGrid::CJobSlotGrid() { // 初始化默认行列数 int m_nRows = 12; int m_nCols = 16; // 初始化默认字体 m_fontText.CreatePointFont(60, _T("Arial")); // 初始化默认颜色 COLORREF m_colorHasJob = RGB(0, 200, 0); // 默认绿色 COLORREF m_colorNoJob = RGB(220, 220, 220); // 默认灰色 // 初始化默认画刷 m_brushHasJob.CreateSolidBrush(m_colorHasJob); m_brushNoJob.CreateSolidBrush(m_colorNoJob); } CJobSlotGrid::~CJobSlotGrid() { if (m_fontText.GetSafeHandle()) { m_fontText.DeleteObject(); } if (m_brushHasJob.GetSafeHandle()) { m_brushHasJob.DeleteObject(); } if (m_brushNoJob.GetSafeHandle()) { m_brushNoJob.DeleteObject(); } } void CJobSlotGrid::SetGridSize(int nRows, int nCols) { m_nRows = nRows; m_nCols = nCols; m_vSlotStatus.assign(nRows, std::vector(nCols, false)); m_vSlotClickable.assign(nRows, std::vector(nCols, false)); // 初始化文本数组 m_vSlotText.assign(nRows, std::vector(nCols)); for (int i = 0; i < nRows; ++i) { for (int j = 0; j < nCols; ++j) { if (i == 0) { m_vSlotText[i][j].Format(_T("%d"), j + 1); } else if (j == 0) { m_vSlotText[i][j].Format(_T("%d"), i + 1); } } } Invalidate(); } void CJobSlotGrid::SetColors(COLORREF colorHasJob, COLORREF colorNoJob) { m_colorHasJob = colorHasJob; m_colorNoJob = colorNoJob; if (m_brushHasJob.GetSafeHandle()) { m_brushHasJob.DeleteObject(); } if (m_brushNoJob.GetSafeHandle()) { m_brushNoJob.DeleteObject(); } m_brushHasJob.CreateSolidBrush(m_colorHasJob); m_brushNoJob.CreateSolidBrush(m_colorNoJob); Invalidate(); } void CJobSlotGrid::SetSlotStatus(int nRow, int nCol, bool bHasJob, BOOL bInvalidate/* = TRUE*/) { if (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols) { m_vSlotStatus[nRow][nCol] = bHasJob; if (bInvalidate) { Invalidate(); } } } void CJobSlotGrid::SetSlotText(int nRow, int nCol, const CString& strText) { if (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols) { m_vSlotText[nRow][nCol] = strText; Invalidate(); } } void CJobSlotGrid::SetTextFont(const CString& strFontName, int nPointSize) { // 删除旧字体 if (m_fontText.GetSafeHandle()) { m_fontText.DeleteObject(); } // CreatePointFont expects size in 1/10 pt m_fontText.CreatePointFont(nPointSize * 10, strFontName); Invalidate(); } void CJobSlotGrid::ClearAll() { if (m_vSlotStatus.empty()) { return; } for (int i = 0; i < m_nRows; ++i) { if (i < (int)m_vSlotStatus.size()) { std::fill(m_vSlotStatus[i].begin(), m_vSlotStatus[i].end(), false); } } Invalidate(); } void CJobSlotGrid::SetSlotClickable(int nRow, int nCol, bool bClickable) { if (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols) { m_vSlotClickable[nRow][nCol] = bClickable; } } bool CJobSlotGrid::IsSlotClickable(int nRow, int nCol) const { if (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols) { return m_vSlotClickable[nRow][nCol]; } return false; } void CJobSlotGrid::SetSlotClickCallback(SlotClickCallback fnCallback) { m_fnSlotClickCallback = fnCallback; } BOOL CJobSlotGrid::OnEraseBkgnd(CDC* pDC) { return TRUE; } void CJobSlotGrid::OnMouseMove(UINT nFlags, CPoint point) { TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_hWnd }; ::TrackMouseEvent(&tme); CRect rect; GetClientRect(&rect); int nCellWidth = rect.Width() / m_nCols; int nCellHeight = rect.Height() / m_nRows; int nCol = point.x / nCellWidth; int nRow = point.y / nCellHeight; if (nRow != m_ptHover.y || nCol != m_ptHover.x) { m_ptHover = CPoint(nCol, nRow); Invalidate(); } CWnd::OnMouseMove(nFlags, point); } void CJobSlotGrid::OnMouseLeave() { m_ptHover = CPoint(-1, -1); Invalidate(); CWnd::OnMouseLeave(); } void CJobSlotGrid::OnLButtonDown(UINT nFlags, CPoint point) { m_bLButtonDown = true; Invalidate(); CWnd::OnLButtonDown(nFlags, point); } void CJobSlotGrid::OnLButtonUp(UINT nFlags, CPoint point) { m_bLButtonDown = false; Invalidate(); // 保持原有逻辑不变 CRect rect; GetClientRect(&rect); int nCellWidth = rect.Width() / m_nCols; int nCellHeight = rect.Height() / m_nRows; int nCol = point.x / nCellWidth; int nRow = point.y / nCellHeight; if (IsSlotClickable(nRow, nCol)) { if (m_fnSlotClickCallback) { m_fnSlotClickCallback(nRow, nCol); } } CWnd::OnLButtonUp(nFlags, point); } void CJobSlotGrid::OnPaint() { CPaintDC dc(this); DrawGrid(&dc); } void CJobSlotGrid::DrawGrid(CDC* pDC) { CRect rect; GetClientRect(&rect); int nCellWidth = rect.Width() / m_nCols; int nCellHeight = rect.Height() / m_nRows; CFont* pOldFont = pDC->SelectObject(&m_fontText); for (int i = 0; i < m_nRows; ++i) { for (int j = 0; j < m_nCols; ++j) { CRect cellRect(j * nCellWidth, i * nCellHeight, (j + 1) * nCellWidth, (i + 1) * nCellHeight); // 判断状态:悬停 / 按下 bool bIsHover = (m_ptHover.x == j && m_ptHover.y == i); bool bIsClicking = bIsHover && m_bLButtonDown; // 选择颜色 COLORREF fillColor; if (bIsClicking) { fillColor = RGB(0, 120, 215); // 鼠标按下色 } else if (bIsHover) { fillColor = RGB(200, 230, 255); // 悬停高亮 } else { fillColor = m_vSlotStatus[i][j] ? m_colorHasJob : m_colorNoJob; } // 画背景 CBrush brush(fillColor); pDC->FillRect(&cellRect, &brush); // 边框 pDC->DrawEdge(&cellRect, EDGE_SUNKEN, BF_RECT); // 文本 pDC->SetBkMode(TRANSPARENT); pDC->SetTextColor(RGB(0, 0, 0)); pDC->DrawText(m_vSlotText[i][j], &cellRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } } pDC->SelectObject(pOldFont); }