230 lines
5.9 KiB
C++
230 lines
5.9 KiB
C++
// LogSearchBar.cpp - 日志列表搜索条实现
|
||
#include "stdafx.h"
|
||
#include "LogSearchBar.h"
|
||
#include "LangManager.h"
|
||
|
||
BEGIN_MESSAGE_MAP(CLogSearchBar, CWnd)
|
||
ON_WM_CREATE()
|
||
ON_WM_SIZE()
|
||
ON_WM_ERASEBKGND()
|
||
ON_WM_TIMER()
|
||
ON_EN_CHANGE(IDC_LOG_SEARCH_EDIT, OnEnChangeSearch)
|
||
ON_BN_CLICKED(IDC_LOG_SEARCH_PREV, OnBnClickedPrev)
|
||
ON_BN_CLICKED(IDC_LOG_SEARCH_NEXT, OnBnClickedNext)
|
||
ON_BN_CLICKED(IDC_LOG_SEARCH_CLEAR, OnBnClickedClear)
|
||
END_MESSAGE_MAP()
|
||
|
||
CLogSearchBar::CLogSearchBar()
|
||
{
|
||
}
|
||
|
||
CLogSearchBar::~CLogSearchBar()
|
||
{
|
||
}
|
||
|
||
BOOL CLogSearchBar::Create(CWnd* pParent, CListCtrl* pList)
|
||
{
|
||
m_pList = pList;
|
||
LPCTSTR cls = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
|
||
::LoadCursor(NULL, IDC_ARROW));
|
||
return CWnd::Create(cls, _T(""), WS_CHILD | WS_CLIPCHILDREN,
|
||
CRect(0, 0, 1, 1), pParent, 0);
|
||
}
|
||
|
||
int CLogSearchBar::OnCreate(LPCREATESTRUCT lpcs)
|
||
{
|
||
if (CWnd::OnCreate(lpcs) == -1) return -1;
|
||
|
||
// 搜索输入框
|
||
m_editSearch.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
|
||
CRect(0, 0, 1, 1), this, IDC_LOG_SEARCH_EDIT);
|
||
m_editSearch.SetCueBanner(L"搜索日志...", TRUE);
|
||
|
||
// 清除按钮
|
||
m_btnClear.Create(_T("X"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_FLAT,
|
||
CRect(0, 0, 1, 1), this, IDC_LOG_SEARCH_CLEAR);
|
||
|
||
// 上一个 / 下一个按钮(系统样式,与浅色背景融合)
|
||
m_btnPrev.Create(_T("▲"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_FLAT,
|
||
CRect(0, 0, 1, 1), this, IDC_LOG_SEARCH_PREV);
|
||
|
||
m_btnNext.Create(_T("▼"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_FLAT,
|
||
CRect(0, 0, 1, 1), this, IDC_LOG_SEARCH_NEXT);
|
||
|
||
// 结果计数
|
||
m_staticCount.Create(_T(""), WS_CHILD | WS_VISIBLE | SS_CENTER | SS_CENTERIMAGE,
|
||
CRect(0, 0, 1, 1), this, IDC_LOG_SEARCH_COUNT);
|
||
|
||
// 统一字体:跟父窗口(主对话框)保持一致
|
||
CFont* pFont = GetParent()->GetFont();
|
||
if (pFont) {
|
||
m_staticCount.SetFont(pFont);
|
||
m_editSearch.SetFont(pFont);
|
||
m_btnClear.SetFont(pFont);
|
||
m_btnPrev.SetFont(pFont);
|
||
m_btnNext.SetFont(pFont);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
void CLogSearchBar::LayoutControls(int cx, int cy)
|
||
{
|
||
if (!m_editSearch.GetSafeHwnd()) return;
|
||
const int m = 2;
|
||
const int h = cy - 2 * m;
|
||
if (h <= 0) return;
|
||
const int btnW = h;
|
||
const int cntW = 62;
|
||
// 搜索框填满剩余空间(barW 由外部控制总宽,这里保证控件铺满)
|
||
const int editW = max(20, cx - 2 * m - 3 * btnW - 2 * m - cntW);
|
||
|
||
int x = m;
|
||
m_staticCount.MoveWindow(x, m, cntW, h);
|
||
x += cntW + m;
|
||
m_editSearch.MoveWindow(x, m, editW, h);
|
||
x += editW + m;
|
||
m_btnClear.MoveWindow(x, m, btnW, h);
|
||
x += btnW;
|
||
m_btnPrev.MoveWindow(x, m, btnW, h);
|
||
x += btnW;
|
||
m_btnNext.MoveWindow(x, m, btnW, h);
|
||
}
|
||
|
||
void CLogSearchBar::OnSize(UINT nType, int cx, int cy)
|
||
{
|
||
CWnd::OnSize(nType, cx, cy);
|
||
LayoutControls(cx, cy);
|
||
}
|
||
|
||
BOOL CLogSearchBar::OnEraseBkgnd(CDC* pDC)
|
||
{
|
||
CRect rc;
|
||
GetClientRect(&rc);
|
||
pDC->FillSolidRect(rc, ::GetSysColor(COLOR_3DFACE));
|
||
return TRUE;
|
||
}
|
||
|
||
void CLogSearchBar::OnEnChangeSearch()
|
||
{
|
||
KillTimer(TIMER_SEARCH);
|
||
SetTimer(TIMER_SEARCH, SEARCH_DELAY_MS, NULL);
|
||
}
|
||
|
||
void CLogSearchBar::OnTimer(UINT_PTR nIDEvent)
|
||
{
|
||
if (nIDEvent == TIMER_SEARCH) {
|
||
KillTimer(TIMER_SEARCH);
|
||
DoSearch();
|
||
}
|
||
CWnd::OnTimer(nIDEvent);
|
||
}
|
||
|
||
void CLogSearchBar::DoSearch()
|
||
{
|
||
if (!m_pList || !m_pList->GetSafeHwnd()) return;
|
||
|
||
CString kw;
|
||
m_editSearch.GetWindowText(kw);
|
||
|
||
m_Results.clear();
|
||
m_nCurrentIndex = -1;
|
||
|
||
if (kw.IsEmpty()) {
|
||
UpdateCountText();
|
||
return;
|
||
}
|
||
|
||
CString kwLow = kw;
|
||
kwLow.MakeLower();
|
||
|
||
int nCols = m_pList->GetHeaderCtrl() ? m_pList->GetHeaderCtrl()->GetItemCount() : 1;
|
||
int nItems = m_pList->GetItemCount();
|
||
|
||
for (int i = 0; i < nItems; i++) {
|
||
for (int c = 0; c < nCols; c++) {
|
||
CString cell = m_pList->GetItemText(i, c);
|
||
cell.MakeLower();
|
||
if (cell.Find(kwLow) >= 0) {
|
||
m_Results.push_back(i);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!m_Results.empty()) {
|
||
m_nCurrentIndex = 0;
|
||
GotoMatch(m_nCurrentIndex);
|
||
}
|
||
UpdateCountText();
|
||
}
|
||
|
||
void CLogSearchBar::GotoMatch(int idx)
|
||
{
|
||
if (!m_pList || idx < 0 || idx >= (int)m_Results.size()) return;
|
||
int item = m_Results[idx];
|
||
|
||
// 取消所有选中
|
||
int n = -1;
|
||
while ((n = m_pList->GetNextItem(-1, LVNI_SELECTED)) != -1)
|
||
m_pList->SetItemState(n, 0, LVIS_SELECTED | LVIS_FOCUSED);
|
||
|
||
m_pList->SetItemState(item, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
|
||
m_pList->EnsureVisible(item, FALSE);
|
||
}
|
||
|
||
void CLogSearchBar::UpdateCountText()
|
||
{
|
||
CString text;
|
||
if (m_Results.empty()) {
|
||
CString kw;
|
||
m_editSearch.GetWindowText(kw);
|
||
text = kw.IsEmpty() ? _TR("") : _TR("无结果");
|
||
} else {
|
||
text.Format(_T("%d/%d"), m_nCurrentIndex + 1, (int)m_Results.size());
|
||
}
|
||
m_staticCount.SetWindowText(text);
|
||
}
|
||
|
||
void CLogSearchBar::InvalidateSearch()
|
||
{
|
||
KillTimer(TIMER_SEARCH);
|
||
m_Results.clear();
|
||
m_nCurrentIndex = -1;
|
||
UpdateCountText();
|
||
|
||
if (m_editSearch.GetSafeHwnd()) {
|
||
CString kw;
|
||
m_editSearch.GetWindowText(kw);
|
||
if (!kw.IsEmpty())
|
||
SetTimer(TIMER_SEARCH, SEARCH_DELAY_MS, NULL);
|
||
}
|
||
}
|
||
|
||
void CLogSearchBar::OnBnClickedPrev()
|
||
{
|
||
if (m_Results.empty()) return;
|
||
m_nCurrentIndex--;
|
||
if (m_nCurrentIndex < 0)
|
||
m_nCurrentIndex = (int)m_Results.size() - 1;
|
||
GotoMatch(m_nCurrentIndex);
|
||
UpdateCountText();
|
||
}
|
||
|
||
void CLogSearchBar::OnBnClickedNext()
|
||
{
|
||
if (m_Results.empty()) return;
|
||
m_nCurrentIndex++;
|
||
if (m_nCurrentIndex >= (int)m_Results.size())
|
||
m_nCurrentIndex = 0;
|
||
GotoMatch(m_nCurrentIndex);
|
||
UpdateCountText();
|
||
}
|
||
|
||
void CLogSearchBar::OnBnClickedClear()
|
||
{
|
||
m_editSearch.SetWindowText(_T(""));
|
||
m_editSearch.SetFocus();
|
||
// 触发 EN_CHANGE → 定时器 → DoSearch 清空结果
|
||
}
|