TA的每日心情 | 开心 6 天前 |
---|
签到天数: 942 天 [LV.10]以坛为家III
管理员
- 积分
- 28797
|
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Wuzm_/article/details/85053812
一些知识的补充:
/*
2018-12-14 14:32:42
单项选择设置背景color ListCtrl
*/
通过重写ListCtrl加入部分属性
详细代码参照ListCtrlex
核心思想:
通过记录设置的几行使用什么颜color(没有设置颜color则使用缺省参数)
通过数据结构map来组织
设置一次颜color相当于在map中插入一条数据
擦除颜color相当于在map中删除一条数据
最后整理好的数据结构在 OnPaint中进行处理
Tip:删除完数据后 记得需要Invalid 刷新一下控件
扩展 LLPoint结构 可以用CPoint数组来代替
//列表中的行的线
CPoint pts[2];
pts[0] = { rcItem.left, rcItem.top };
pts[1] = { rcItem.right, rcItem.top };
pRT->DrawLines(pts, 2);
/*
2018-12-17 14:47:26
记录在ListCtrl中提供的一个特殊的坐标值
*/
CPoint m_ptOrigin;
一个原点坐标
在列表没有滚动条的时候 m_ptOrigin = {0,0}
当滚动条进行滑动的时候 这个时候原点坐标也会改变
详细计算过程见 SListCtrl::UpdateScrollBar()
在重新实现了左键按下的消息事件的时候 m_nSelectItem 这个值将为-1
也就是选中哪一行 这个需要自己实现。实现过程和选中哪一列类似
需求:设置多个行选项的背景color,加上框线 列表单元格可编辑
设计思想:
背景color思路:
确定背景的绘制在OnPaint中 通过确认几行需要绘制 通过一些数据结构的处理 很容易在OnPaint中进行实现
编辑功能思路:
通过控件SListCtrl中可以很轻松的得到 宽 高 行 列 这些参数 然后可以知道点击的每个单元格的Rect
在单元格需要编辑的地方双击 通过new SEdit 来进行编辑框的输入 最后将输入的值写入ListCtrl控件
当Edit失去焦点的时候就是写入值的时候 并销毁SEdit
代码设计如下
SListCtrlEx.h
- #pragma once
- /*
- 2018-12-14 14:30:30
- 拓展ListCtrl控件 增加背景color 和 编辑功能
- */
- #include <map>
- namespace SOUI
- {
- #define COLORRED RGBA(255, 0, 0, 155)
- class ListCtrlExEdit;
- class SListCtrlEx : public SListCtrl
- {
- SOUI_CLASS_NAME(SListCtrlEx,L"listctrlex")
-
- public:
- SListCtrlEx();
- ~SListCtrlEx();
-
- public:
- void SetRowBackGndColor(int iRow, COLORREF clr = COLORRED); //设置某行的背景color
- void EraseRowBackGndColor(int iRow); //去掉某行设置的颜color iRow从0开始
- void OnSetEditText();
-
- protected:
- void OnLButtonDown(UINT nFlags, CPoint point);
- void OnLButtonDblClk(UINT nFlags, CPoint point);
- void OnPaint(IRenderTarget * pRT);
- void DrawItem(IRenderTarget *pRT, CRect rcItem, int nItem);
-
-
- SOUI_MSG_MAP_BEGIN()
- MSG_WM_PAINT_EX(OnPaint)
- MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
- MSG_WM_LBUTTONDOWN(OnLButtonDown)
- SOUI_MSG_MAP_END()
-
- private:
- std::map<int, COLORREF> m_maplistexRow;
- ListCtrlExEdit *m_edit;
- int m_iRow;
- int m_iCol;
-
- };
-
- class ListCtrlExEdit : public SEdit
- {
- public:
- SOUI_CLASS_NAME(ListCtrlExEdit, L"listctrlexedit")
-
- ListCtrlExEdit(SListCtrlEx* pOwner) :m_ListCtrlEx(pOwner) {}
-
- void OnKillFocus(SWND wndFocus)
- {
- __super::OnKillFocus(wndFocus);
- m_ListCtrlEx->OnSetEditText();
- }
-
- SOUI_MSG_MAP_BEGIN()
- MSG_WM_KILLFOCUS_EX(OnKillFocus)
- SOUI_MSG_MAP_END()
-
- virtual void OnFinalRelease()
- {
- delete this;
- }
- private:
- SListCtrlEx * m_ListCtrlEx;
- };
-
- }
复制代码 SListCtrlEx.cpp
- #include "stdafx.h"
- #include "SListCtrlEx.h"
-
- namespace SOUI
- {
- SListCtrlEx::SListCtrlEx():m_iRow(0),m_iCol(0), m_edit(nullptr)
- {
- m_maplistexRow.swap(std::map<int, COLORREF>());
- }
-
- SListCtrlEx::~SListCtrlEx()
- {
- if (m_maplistexRow.size() > 0)
- {
- m_maplistexRow.swap(std::map<int, COLORREF>());
- }
-
- if (m_edit != nullptr)
- {
- m_edit->Release();
- m_edit = nullptr;
- }
- }
-
- void SListCtrlEx::SetRowBackGndColor(int iRow, COLORREF clr)
- {
- if (iRow > GetItemCount())
- {
- return;
- }
- bool bflag = false;
- for (auto value : m_maplistexRow)
- {
- if (value.first == iRow && value.second == clr)
- {
- bflag = true;
- break;
- }
- }
-
- if (!bflag)
- {
- m_maplistexRow.insert(std::pair<int, COLORREF>(iRow, clr));
- }
- }
-
- void SListCtrlEx::EraseRowBackGndColor(int iRow)
- {
- auto pValue = m_maplistexRow.find(iRow);
- if (pValue != m_maplistexRow.end())
- {
- m_maplistexRow.erase(pValue);
- }
- Invalidate();
- }
-
- void SListCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
- {
- if (m_edit != nullptr)
- {
- m_edit->KillFocus();
- }
- }
-
- void SListCtrlEx::OnLButtonDblClk(UINT nFlags, CPoint point)
- {
- //计算鼠标点击的位置 在 列表中的是哪一行哪一列 行高:m_nItemHeight
- m_iRow = 0;
- m_iCol = 0;
- CRect rclist = GetListRect();
- CPoint pt{ 0,0 };
- pt.x = point.x - rclist.left + m_ptOrigin.x;
- pt.y = point.y - rclist.top + m_ptOrigin.y;
- int WidthHead = 0;
- int WidthBack = 0;
-
- //判断第几行 在重写了左键按下事件后 就无法使用基类中给出的选中第几行的那个变量了
- for (int i = 0; i < GetItemCount(); ++i)
- {
- WidthBack = WidthHead + m_nItemHeight;
- if (pt.y > WidthHead && pt.y < WidthBack)
- {
- m_iRow = i;
- break;
- }
- WidthHead = WidthBack;
- }
-
- WidthHead = 0;
- WidthBack = 0;
- //获取第几列
- for (int i = 0; i < GetColumnCount(); ++i)
- {
- //获取列的宽度 然后计算坐标 与 得到的坐标进行比较 判断区域
- WidthBack = WidthHead + m_pHeader->GetItemWidth(i);
- if (pt.x > WidthHead && pt.x < WidthBack)
- {
- m_iCol = i;
- break;
- }
- WidthHead = WidthBack;
- }
-
- //SMessageBox(NULL, SStringT().Format(L"%d,%d", m_iRow,m_iCol), L"", NULL);
- //return;
-
- //得到了行列 就可以得到区域
- CRect ItemRect = GetItemRect(m_iRow, m_iCol);
-
- wchar_t szEditAttr[] = L"<listctrlexedit transparent="1" align="left" mouse***="1" colorBkgnd="#FFFFFF" colorText="#000000" />";
- pugi::xml_document xmlDoc;
- xmlDoc.load_buffer(szEditAttr, sizeof(szEditAttr));
- if (m_edit == nullptr)
- {
- m_edit = new ListCtrlExEdit(this);
- }
-
- InsertChild(m_edit);
- m_edit->InitFromXml(xmlDoc.first_child());
- ItemRect.left += 4;
- m_edit->Move(ItemRect); //将窗口移动到指定位置
- SStringT strText = GetSubItemText(m_iRow, m_iCol);
- m_edit->SetWindowTextW(strText);
- m_edit->SetFocus();
- }
-
- void SListCtrlEx::OnPaint(IRenderTarget * pRT)
- {
- SPainter painter;
- BeforePaint(pRT, painter);
- CRect rcList = GetListRect();
- int nTopItem = GetTopIndex();
- pRT->PushClipRect(&rcList);
- CRect rcItem(rcList);
- pRT->DrawRectangle(rcList);
-
- rcItem.bottom = rcItem.top;
- int ilistitem = GetItemCount();
- rcItem.OffsetRect(0, -(m_ptOrigin.y%m_nItemHeight));
- for (int nItem = nTopItem; nItem <= (nTopItem + GetCountPerPage(TRUE)) && nItem < GetItemCount(); nItem++)
- {
- rcItem.bottom = rcItem.top + m_nItemHeight;
-
- DrawItem(pRT, rcItem, nItem);
-
- //列表中的行的线
- CPoint pts[2];
- pts[0] = { rcItem.left, rcItem.top };
- pts[1] = { rcItem.right, rcItem.top };
- pRT->DrawLines(pts, 2);
-
- for (auto value : m_maplistexRow)
- {
- if (nItem == value.first)
- {
- pRT->FillSolidRect(rcItem, value.second); //设置变color的行
- break;
- }
- }
-
- rcItem.top = rcItem.bottom;
- }
-
- pRT->PopClip();
- AfterPaint(pRT, painter);
- }
-
- void SListCtrlEx::DrawItem(IRenderTarget * pRT, CRect rcItem, int nItem)
- {
- BOOL bTextColorChanged = FALSE;
- int nBgImg = 0;
- COLORREF crOldText = RGBA(0xFF, 0xFF, 0xFF, 0xFF);
- COLORREF crItemBg = m_crItemBg;
- COLORREF crText = m_crText;
- DXLVITEM lvItem = m_arrItems[nItem];
- CRect rcIcon, rcText;
-
- if (nItem % 2)
- {
- if (CR_INVALID != m_crItemBg2)
- {
- crItemBg = m_crItemBg2;
- }
- }
-
- if (lvItem.checked)
- {
- if (m_pItemSkin != NULL)
- {
- nBgImg = 2;
- }
- else if (CR_INVALID != m_crItemSelBg)
- {
- crItemBg = m_crItemSelBg;
- }
-
- if (CR_INVALID != m_crSelText)
- {
- crText = m_crSelText;
- }
- }
- else if (m_bHotTrack && nItem == m_nHoverItem)
- {
- if (m_pItemSkin != NULL)
- {
- nBgImg = 1;
- }
- else if (CR_INVALID != m_crItemHotBg)
- {
- crItemBg = m_crItemHotBg;
- }
-
- if (CR_INVALID != m_crSelText)
- {
- crText = m_crSelText;
- }
- }
-
- //绘制背景
- if (CR_INVALID != crItemBg)//先画背景
- {
- pRT->FillSolidRect(rcItem, crItemBg);
- }
-
- if (m_pItemSkin != NULL)//有skin,则覆盖背景
- {
- m_pItemSkin->Draw(pRT, rcItem, nBgImg);
- }
-
-
- // 左边加上空白
- rcItem.left += 4;
-
- if (CR_INVALID != crText)
- {
- bTextColorChanged = TRUE;
- crOldText = pRT->SetTextColor(crText);
- }
-
- CRect rcCol(rcItem);
- rcCol.right = rcCol.left;
- rcCol.OffsetRect(-m_ptOrigin.x, 0);
-
- for (int nCol = 0; nCol < GetColumnCount(); nCol++)
- {
- CRect rcVisiblePart;
-
- SHDITEM hdi;
- hdi.mask = SHDI_WIDTH | SHDI_ORDER;
- m_pHeader->GetItem(nCol, &hdi);
- rcCol.left = rcCol.right;
- rcCol.right = rcCol.left + hdi.cx.toPixelSize(GetScale());
-
- rcVisiblePart.IntersectRect(rcItem, rcCol);
-
- if (rcVisiblePart.IsRectEmpty())
- {
- continue;
- }
-
- // 绘制 checkbox
- if (nCol == 0 && m_bCheckBox && m_pCheckSkin)
- {
- CSize sizeSkin = m_pCheckSkin->GetSkinSize();
- int nOffsetX = 3;
- int nOffsetY = (m_nItemHeight - sizeSkin.cy) / 2;
- CRect rcCheck;
- rcCheck.SetRect(0, 0, sizeSkin.cx, sizeSkin.cy);
- rcCheck.OffsetRect(rcCol.left + nOffsetX, rcCol.top + nOffsetY);
- m_pCheckSkin->Draw(pRT, rcCheck, lvItem.checked ? 4 : 0);
-
- rcCol.left = sizeSkin.cx + 6 + rcCol.left;
- }
-
- DXLVSUBITEM& subItem = lvItem.arSubItems->GetAt(hdi.iOrder);
-
- if (subItem.nImage != -1 && m_pIconSkin)
- {
- int nOffsetX = m_ptIcon.x;
- int nOffsetY = m_ptIcon.y;
- CSize sizeSkin = m_pIconSkin->GetSkinSize();
- rcIcon.SetRect(0, 0, sizeSkin.cx, sizeSkin.cy);
-
- if (m_ptIcon.x == -1)
- {
- nOffsetX = m_nItemHeight / 6;
- }
-
- if (m_ptIcon.y == -1)
- {
- nOffsetY = (m_nItemHeight - sizeSkin.cy) / 2;
- }
-
- rcIcon.OffsetRect(rcCol.left + nOffsetX, rcCol.top + nOffsetY);
- m_pIconSkin->Draw(pRT, rcIcon, subItem.nImage);
- }
-
- UINT align = DT_SINGLELINE;
- rcText = rcCol;
-
- if (m_ptText.x == -1)
- {
- rcText.left = rcIcon.Width() > 0 ? rcIcon.right + m_nItemHeight / 6 : rcCol.left;
- }
- else
- {
- rcText.left = rcCol.left + m_ptText.x;
- }
-
- if (m_ptText.y == -1)
- {
- align |= DT_VCENTER;
- }
- else
- {
- rcText.top = rcCol.top + m_ptText.y;
- }
-
- pRT->DrawText(subItem.strText, subItem.cchTextMax, rcText, align);
-
- //划线 列的线段
- CPoint pt[2];
- pt[0] = { rcText.left,rcText.top };
- pt[1] = { rcText.left,rcText.bottom };
- pRT->DrawLines(pt, 2);
- }
-
- if (bTextColorChanged)
- {
- pRT->SetTextColor(crOldText);
- }
- CPoint pt[2];
- pt[0] = { rcText.left,rcText.top };
- pt[1] = { rcText.left,rcText.bottom };
- pRT->DrawLines(pt, 2);
- }
-
- void SListCtrlEx::OnSetEditText()
- {
- if (m_edit != nullptr)
- {
- SStringT strEdit = m_edit->GetWindowTextW();
- SetSubItemText(m_iRow, m_iCol, strEdit);
- m_edit->Release();
- RemoveChild(m_edit);
- m_edit = nullptr;
- }
- }
- }
复制代码 测试代码:
- BOOL TestDlg::OnInitDialog(HWND wnd, LPARAM lInitParam)
- {
- SListCtrlEx *plist = FindChildByName2<SListCtrlEx>(L"list_testlist");
- SASSERT(plist);
-
- int pos = 0;
- for (int i = 0; i < 10; ++i)
- {
- pos = plist->InsertItem(i, L"");
- plist->SetSubItemText(pos, 0, L"Test");
- plist->SetSubItemText(pos, 1, L"Test");
- plist->SetSubItemText(pos, 2, L"Test");
- plist->SetSubItemText(pos, 3, L"Test");
- plist->SetSubItemText(pos, 4, L"Test");
- plist->SetSubItemText(pos, 5, L"Test");
- plist->SetSubItemText(pos, 6, L"Test");
- }
-
- plist->SetRowBackGndColor(1);
-
- plist->SetRowBackGndColor(3);
-
- plist->SetRowBackGndColor(5);
-
- plist->SetRowBackGndColor(7);
-
- plist->SetRowBackGndColor(9);
-
- return 0;
- }
复制代码 XML :
- <listctrlex pos="16,40" size="562, 200" hotTrack="1" itemHeight="30" headerHeight="30" name="list_testlist" margin="1,1" colorBorder="#000000">
- <!-- colorBkgnd="#F8E4EA" -->
- <header align="left" itemSwapEnable="1" fixWidth="1">
- <items>
- <item width="150">name</item>
- <item width="150">age</item>
- <item width="150">score</item>
- <item width="150">age</item>
- <item width="150">score</item>
- <item width="150">age</item>
- <item width="150">score</item>
- <item width="100" />
- </items>
- </header>
- </listctrlex>
复制代码 最后实现的效果:
|
|