Files
EzUI/sources/TableView.cpp

1712 lines
46 KiB
C++
Raw Normal View History

2026-01-28 15:00:12 +08:00
#include "TableView.h"
namespace ezui {
TableView::TableView(Object* parentObject) : Control(parentObject) {
Init();
}
TableView::~TableView() {
EndEdit(false);
// 注意m_editBox、m_editCombo、m_editCheck 作为子控件,由父控件自动管理
// 不需要手动 delete否则会导致双重释放
m_editBox = nullptr;
m_editCombo = nullptr;
m_editCheck = nullptr;
}
void TableView::Init() {
// 初始化垂直滚动条
m_vScrollBar.SetWidth(10);
m_vScrollBar.Parent = this;
m_vScrollBar.OffsetCallback = [this](int offset) {
this->OffsetY(offset);
};
// 初始化水平滚动条
m_hScrollBar.SetHeight(10);
m_hScrollBar.Parent = this;
m_hScrollBar.OffsetCallback = [this](int offset) {
this->OffsetX(offset);
};
// 创建编辑控件(初始隐藏)
m_editBox = new TextBox();
m_editBox->SetVisible(false);
m_editBox->SetMultiLine(true);
// 为编辑框设置默认字体样式
m_editBox->Style.FontSize = m_cellFontSize;
m_editBox->Style.FontFamily = L"Microsoft YaHei";
// 添加到子控件列表,这样才能正确处理事件和绘制
this->Add(m_editBox);
m_editBox->TextChanged = [this](const UIString& text) {
if (m_editing && m_editRow >= 0 && m_editCol >= 0) {
// 实时更新数据
if (m_editRow < (int)m_data.size() && m_editCol < (int)m_data[m_editRow].size()) {
m_data[m_editRow][m_editCol].Text = text;
UpdateRowHeight(m_editRow);
if (CellValueChanged) {
CellValueChanged(m_editRow, m_editCol, text);
}
}
}
};
}
int TableView::GetContentWidth() const {
int width = m_firstColumnWidth;
for (const auto& col : m_columns) {
width += col.Width;
}
return width;
}
int TableView::GetContentHeight() const {
int height = m_headerHeight;
for (int h : m_rowHeights) {
height += h;
}
return height;
}
int TableView::GetColumnX(int colIndex) const {
int x = m_firstColumnWidth - m_scrollOffsetX;
for (int i = 0; i < colIndex && i < (int)m_columns.size(); ++i) {
x += m_columns[i].Width;
}
return x;
}
int TableView::GetRowY(int rowIndex) const {
int y = m_headerHeight - m_scrollOffsetY;
for (int i = 0; i < rowIndex && i < (int)m_rowHeights.size(); ++i) {
y += m_rowHeights[i];
}
return y;
}
bool TableView::HitTestCell(const Point& pt, int* outRow, int* outCol) const {
// 检查是否在表头区域
if (pt.Y < m_headerHeight) {
*outRow = -1;
// 检查是否在第一列
if (pt.X < m_firstColumnWidth) {
*outCol = -1;
return true;
}
// 检查是否在数据列
int x = m_firstColumnWidth;
for (int i = 0; i < (int)m_columns.size(); ++i) {
if (pt.X >= x - m_scrollOffsetX && pt.X < x - m_scrollOffsetX + m_columns[i].Width) {
*outCol = i;
return true;
}
x += m_columns[i].Width;
}
return false;
}
// 检查行
int y = m_headerHeight;
for (int row = 0; row < (int)m_rowHeights.size(); ++row) {
int rowY = y - m_scrollOffsetY;
if (pt.Y >= rowY && pt.Y < rowY + m_rowHeights[row]) {
*outRow = row;
// 检查列
if (pt.X < m_firstColumnWidth) {
*outCol = -1; // 第一列
return true;
}
int x = m_firstColumnWidth;
for (int col = 0; col < (int)m_columns.size(); ++col) {
int colX = x - m_scrollOffsetX;
if (pt.X >= colX && pt.X < colX + m_columns[col].Width) {
*outCol = col;
return true;
}
x += m_columns[col].Width;
}
return false;
}
y += m_rowHeights[row];
}
*outRow = -1;
*outCol = -1;
return false;
}
int TableView::HitTestColumnBorder(const Point& pt) const {
const int borderHitWidth = 5; // 边界检测宽度
// 只在表头区域检测
if (pt.Y >= m_headerHeight) {
return -2; // 返回-2表示不在表头区域不应该显示拖动光标
}
// 检测第一列右边界
int x = m_firstColumnWidth;
if (std::abs(pt.X - x) <= borderHitWidth) {
return -1; // 返回-1表示第一列边界特殊处理
}
// 检测数据列边界
for (int i = 0; i < (int)m_columns.size(); ++i) {
x += m_columns[i].Width;
int borderX = x - m_scrollOffsetX;
if (std::abs(pt.X - borderX) <= borderHitWidth) {
return i;
}
}
return -2; // 未命中任何边界
}
bool TableView::HitTestVScrollBar(const Point& pt) {
if (!m_vScrollBar.IsVisible()) {
return false;
}
Rect scrollRect = m_vScrollBar.GetRect();
return scrollRect.Contains(pt);
}
bool TableView::HitTestHScrollBar(const Point& pt) {
if (!m_hScrollBar.IsVisible()) {
return false;
}
Rect scrollRect = m_hScrollBar.GetRect();
return scrollRect.Contains(pt);
}
void TableView::DrawHeader(PaintEventArgs& args) {
auto& g = args.Graphics;
// 绘制表头背景
Rect headerRect(0, 0, Width(), m_headerHeight);
g.SetColor(m_headerBackColor);
g.FillRectangle(RectF(headerRect));
// 绘制第一列表头
Rect firstColRect(0, 0, m_firstColumnWidth, m_headerHeight);
g.SetColor(m_headerBackColor);
g.FillRectangle(RectF(firstColRect));
// 如果第一列是 CheckBox 类型,绘制全选复选框
if (m_firstColumnType == FirstColumnType::CheckBox) {
int checkSize = (std::min)(m_headerHeight - 8, 16);
int checkX = (m_firstColumnWidth - checkSize) / 2;
int checkY = (m_headerHeight - checkSize) / 2;
Rect checkRect(checkX, checkY, checkSize, checkSize);
// 绘制复选框边框
g.SetColor(m_cellBorderColor);
g.DrawRectangle(RectF(checkRect));
// 如果全选,绘制勾选标记
if (m_headerSelectAll) {
g.SetColor(m_headerForeColor);
// 简单的勾选线
PointF p1(checkX + 3, checkY + checkSize / 2);
PointF p2(checkX + checkSize / 3, checkY + checkSize - 4);
PointF p3(checkX + checkSize - 3, checkY + 4);
g.DrawLine(p1, p2);
g.DrawLine(p2, p3);
}
} else if (m_firstColumnType == FirstColumnType::Index) {
// 绘制 "#" 或序号标题
Font font(m_cellFontFamily, m_cellFontSize);
g.SetFont(font);
g.SetColor(m_headerForeColor);
TextLayout layout(L"#", font, SizeF(m_firstColumnWidth, m_headerHeight), TextAlign::MiddleCenter);
g.DrawTextLayout(layout, PointF(0, 0));
}
// 绘制第一列边框
if (m_cellBorderStyle != StrokeStyle::None) {
g.SetColor(m_cellBorderColor);
g.DrawRectangle(RectF(firstColRect));
}
// 绘制数据列表头
int x = m_firstColumnWidth - m_scrollOffsetX;
for (int i = 0; i < (int)m_columns.size(); ++i) {
const auto& col = m_columns[i];
// 裁剪到可见区域
if (x + col.Width <= m_firstColumnWidth || x >= Width()) {
x += col.Width;
continue;
}
Rect colRect(x, 0, col.Width, m_headerHeight);
// 绘制表头文字
Font font(m_cellFontFamily, m_cellFontSize);
g.SetFont(font);
g.SetColor(m_headerForeColor);
// 添加排序指示器
std::wstring headerText = col.HeaderText.unicode();
if (col.CurrentSort == SortOrder::Ascending) {
headerText = headerText + L"";
} else if (col.CurrentSort == SortOrder::Descending) {
headerText = headerText + L"";
}
TextLayout layout(headerText, font, SizeF(col.Width - 4, m_headerHeight), TextAlign::MiddleCenter);
g.DrawTextLayout(layout, PointF(x + 2, 0));
// 绘制边框
if (m_cellBorderStyle != StrokeStyle::None) {
g.SetColor(m_cellBorderColor);
g.DrawRectangle(RectF(colRect));
}
x += col.Width;
}
}
void TableView::DrawCells(PaintEventArgs& args) {
int startY = m_headerHeight;
for (int row = 0; row < (int)m_data.size(); ++row) {
int rowY = startY + GetRowY(row) - m_headerHeight;
int rowHeight = m_rowHeights[row];
// 跳过不可见行
if (rowY + rowHeight <= m_headerHeight || rowY >= Height()) {
continue;
}
// 绘制第一列
Rect firstColRect(0, rowY, m_firstColumnWidth, rowHeight);
DrawFirstColumn(args, row, firstColRect);
// 绘制数据列
int x = m_firstColumnWidth - m_scrollOffsetX;
for (int col = 0; col < (int)m_columns.size(); ++col) {
int colWidth = m_columns[col].Width;
// 跳过不可见列
if (x + colWidth <= m_firstColumnWidth || x >= Width()) {
x += colWidth;
continue;
}
Rect cellRect(x, rowY, colWidth, rowHeight);
DrawCell(args, row, col, cellRect);
x += colWidth;
}
}
}
void TableView::DrawFirstColumn(PaintEventArgs& args, int row, const Rect& cellRect) {
auto& g = args.Graphics;
// 获取行选中状态背景色
Color backColor = m_cellBackColor;
if (m_firstColumnType == FirstColumnType::CheckBox && row < (int)m_rowChecked.size() && m_rowChecked[row]) {
backColor = SelectedRowBackColor;
}
// 绘制背景
g.SetColor(backColor);
g.FillRectangle(RectF(cellRect));
// 根据第一列类型绘制内容
if (m_firstColumnType == FirstColumnType::Index) {
// 绘制序号
Font font(m_cellFontFamily, m_cellFontSize);
g.SetFont(font);
g.SetColor(m_cellForeColor);
std::wstring indexText = std::to_wstring(row + 1); // 从1开始
TextLayout layout(indexText, font, SizeF(m_firstColumnWidth - 4, cellRect.Height), TextAlign::MiddleCenter);
g.DrawTextLayout(layout, PointF(cellRect.X + 2, cellRect.Y));
} else if (m_firstColumnType == FirstColumnType::CheckBox) {
// 绘制复选框
int checkSize = (std::min)(cellRect.Height - 8, 16);
int checkX = cellRect.X + (m_firstColumnWidth - checkSize) / 2;
int checkY = cellRect.Y + (cellRect.Height - checkSize) / 2;
Rect checkRect(checkX, checkY, checkSize, checkSize);
g.SetColor(m_cellBorderColor);
g.DrawRectangle(RectF(checkRect));
if (row < (int)m_rowChecked.size() && m_rowChecked[row]) {
g.SetColor(m_cellForeColor);
PointF p1(checkX + 3, checkY + checkSize / 2);
PointF p2(checkX + checkSize / 3, checkY + checkSize - 4);
PointF p3(checkX + checkSize - 3, checkY + 4);
g.DrawLine(p1, p2);
g.DrawLine(p2, p3);
}
}
// TextBox 类型第一列留空
// 绘制边框
if (m_cellBorderStyle != StrokeStyle::None) {
g.SetColor(m_cellBorderColor);
g.DrawRectangle(RectF(cellRect));
}
}
void TableView::DrawCell(PaintEventArgs& args, int row, int col, const Rect& cellRect) {
auto& g = args.Graphics;
if (row >= (int)m_data.size() || col >= (int)m_data[row].size()) {
return;
}
const auto& cellData = m_data[row][col];
const auto& colInfo = m_columns[col];
// 确定背景色
Color backColor = m_cellBackColor;
// 如果第一列是 CheckBox 且选中,使用选中行背景色(优先级低)
if (m_firstColumnType == FirstColumnType::CheckBox && row < (int)m_rowChecked.size() && m_rowChecked[row]) {
backColor = SelectedRowBackColor;
}
// 如果单元格有独立背景色,使用独立设置(优先级高)
if (cellData.Style.HasBackColor) {
backColor = cellData.Style.BackColor;
}
// 如果正在编辑此单元格,跳过内容绘制(只绘制背景),让 TextBox 绘制内容
bool isEditing = m_editing && m_editRow == row && m_editCol == col;
// 绘制背景(编辑时也需要绘制,但使用白色以匹配 TextBox
if (isEditing) {
g.SetColor(Color::White);
} else {
g.SetColor(backColor);
}
g.FillRectangle(RectF(cellRect));
// 如果正在编辑此单元格,跳过内容绘制
if (isEditing) {
return;
}
// 确定前景色
Color foreColor = m_cellForeColor;
if (cellData.Style.HasForeColor) {
foreColor = cellData.Style.ForeColor;
}
// 根据单元格类型绘制内容
Font font(m_cellFontFamily, m_cellFontSize);
g.SetFont(font);
g.SetColor(foreColor);
switch (colInfo.Type) {
case CellType::TextBox:
case CellType::ReadOnly: {
// 绘制文本
TextLayout layout(cellData.Text.unicode(), font,
SizeF(cellRect.Width - 4, cellRect.Height - 2), TextAlign::MiddleLeft);
g.DrawTextLayout(layout, PointF(cellRect.X + 2, cellRect.Y + 1));
break;
}
case CellType::CheckBox: {
// 绘制复选框
int checkSize = (std::min)(cellRect.Height - 8, 16);
int checkX = cellRect.X + (cellRect.Width - checkSize) / 2;
int checkY = cellRect.Y + (cellRect.Height - checkSize) / 2;
Rect checkRect(checkX, checkY, checkSize, checkSize);
g.SetColor(m_cellBorderColor);
g.DrawRectangle(RectF(checkRect));
if (cellData.Checked) {
g.SetColor(foreColor);
PointF p1(checkX + 3, checkY + checkSize / 2);
PointF p2(checkX + checkSize / 3, checkY + checkSize - 4);
PointF p3(checkX + checkSize - 3, checkY + 4);
g.DrawLine(p1, p2);
g.DrawLine(p2, p3);
}
break;
}
case CellType::ComboBox: {
// 绘制下拉框文本
UIString displayText;
if (cellData.ComboIndex >= 0 && cellData.ComboIndex < (int)colInfo.ComboItems.size()) {
displayText = colInfo.ComboItems[cellData.ComboIndex];
}
TextLayout layout(displayText.unicode(), font,
SizeF(cellRect.Width - 20, cellRect.Height - 2), TextAlign::MiddleLeft);
g.DrawTextLayout(layout, PointF(cellRect.X + 2, cellRect.Y + 1));
// 绘制下拉箭头
int arrowSize = 8;
int arrowX = cellRect.GetRight() - arrowSize - 4;
int arrowY = cellRect.Y + (cellRect.Height - arrowSize / 2) / 2;
PointF ap1(arrowX, arrowY);
PointF ap2(arrowX + arrowSize, arrowY);
PointF ap3(arrowX + arrowSize / 2, arrowY + arrowSize / 2);
g.SetColor(foreColor);
g.DrawLine(ap1, ap3);
g.DrawLine(ap2, ap3);
break;
}
}
// 绘制边框
StrokeStyle borderStyle = m_cellBorderStyle;
Color borderColor = m_cellBorderColor;
if (cellData.Style.HasBorderStyle) {
borderStyle = cellData.Style.BorderStyle;
}
if (cellData.Style.HasBorderColor) {
borderColor = cellData.Style.BorderColor;
}
if (borderStyle != StrokeStyle::None) {
g.SetColor(borderColor);
// TODO: 支持虚线样式
g.DrawRectangle(RectF(cellRect));
}
}
void TableView::BeginEdit(int row, int col) {
if (row < 0 || col < 0 || row >= (int)m_data.size() || col >= (int)m_columns.size()) {
return;
}
const auto& colInfo = m_columns[col];
// ReadOnly 类型不能编辑
if (colInfo.Type == CellType::ReadOnly) {
return;
}
EndEdit(true); // 结束之前的编辑
m_editing = true;
m_editRow = row;
m_editCol = col;
// 计算单元格位置
int x = GetColumnX(col);
int y = GetRowY(row);
int width = colInfo.Width;
int height = m_rowHeights[row];
Rect editRect(x, y, width, height);
switch (colInfo.Type) {
case CellType::TextBox: {
// 确保 TextBox 字体与单元格字体一致
m_editBox->Style.FontSize = m_cellFontSize;
m_editBox->Style.FontFamily = m_cellFontFamily;
m_editBox->SetRect(editRect);
m_editBox->SetText(m_data[row][col].Text);
m_editBox->SetVisible(true);
// 确保 TextBox 获得正确的窗口句柄(从 TableView 继承)
m_editBox->SetHwnd(this->Hwnd());
// 触发焦点事件(这会启动光标闪烁计时器)
m_editBox->SendEvent(FocusEventArgs(m_editBox));
Invalidate();
break;
}
case CellType::CheckBox: {
// 直接切换状态
m_data[row][col].Checked = !m_data[row][col].Checked;
m_editing = false;
m_editRow = -1;
m_editCol = -1;
if (CellValueChanged) {
CellValueChanged(row, col, m_data[row][col].Checked ? L"true" : L"false");
}
Invalidate();
break;
}
case CellType::ComboBox: {
// TODO: 显示下拉列表
// 暂时简化处理,循环选择
int nextIndex = (m_data[row][col].ComboIndex + 1) % (std::max)(1, (int)colInfo.ComboItems.size());
m_data[row][col].ComboIndex = nextIndex;
m_editing = false;
m_editRow = -1;
m_editCol = -1;
UIString newValue;
if (nextIndex >= 0 && nextIndex < (int)colInfo.ComboItems.size()) {
newValue = colInfo.ComboItems[nextIndex];
}
if (CellValueChanged) {
CellValueChanged(row, col, newValue);
}
Invalidate();
break;
}
default:
m_editing = false;
m_editRow = -1;
m_editCol = -1;
break;
}
}
void TableView::EndEdit(bool save) {
if (!m_editing) {
return;
}
if (save && m_editRow >= 0 && m_editCol >= 0) {
if (m_editRow < (int)m_data.size() && m_editCol < (int)m_data[m_editRow].size()) {
const auto& colInfo = m_columns[m_editCol];
if (colInfo.Type == CellType::TextBox) {
m_data[m_editRow][m_editCol].Text = m_editBox->GetText();
UpdateRowHeight(m_editRow);
}
}
}
m_editBox->SetVisible(false);
m_editing = false;
m_editRow = -1;
m_editCol = -1;
Invalidate();
}
void TableView::UpdateRowHeight(int row) {
if (row < 0 || row >= (int)m_data.size()) {
return;
}
int maxHeight = m_defaultRowHeight;
// 遍历该行所有单元格,计算最大需要的高度
for (int col = 0; col < (int)m_data[row].size() && col < (int)m_columns.size(); ++col) {
const auto& cellData = m_data[row][col];
const auto& colInfo = m_columns[col];
if (colInfo.Type == CellType::TextBox || colInfo.Type == CellType::ReadOnly) {
int lines = CalculateTextLines(cellData.Text, colInfo.Width - 4);
int neededHeight = lines * (m_cellFontSize + 4) + 8;
if (neededHeight > maxHeight) {
maxHeight = neededHeight;
}
}
}
if (row < (int)m_rowHeights.size()) {
m_rowHeights[row] = maxHeight;
}
RefreshScrollBars();
Invalidate();
}
int TableView::CalculateTextLines(const UIString& text, int width) const {
if (text.empty() || width <= 0) {
return 1;
}
Font font(m_cellFontFamily, m_cellFontSize);
TextLayout layout(text.unicode(), font, SizeF(width, EZUI_FLOAT_MAX));
Size box = layout.GetFontBox();
int fontHeight = m_cellFontSize + 4;
int lines = (box.Height + fontHeight - 1) / fontHeight;
return (std::max)(1, lines);
}
void TableView::RefreshScrollBars() {
int contentWidth = GetContentWidth();
int contentHeight = GetContentHeight();
// 可视区域大小(初步计算,不考虑滚动条)
int viewWidth = Width();
int viewHeight = Height() - m_headerHeight;
// 判断是否需要滚动条
bool needVScroll = (contentHeight - m_headerHeight) > viewHeight;
bool needHScroll = contentWidth > viewWidth;
// 如果需要垂直滚动条,水平可视区域要减去滚动条宽度
if (needVScroll) {
viewWidth -= m_vScrollBar.Width();
// 重新判断是否需要水平滚动条
needHScroll = contentWidth > viewWidth;
}
// 如果需要水平滚动条,垂直可视区域要减去滚动条高度
if (needHScroll) {
viewHeight -= m_hScrollBar.Height();
// 重新判断是否需要垂直滚动条
if (!needVScroll) {
needVScroll = (contentHeight - m_headerHeight) > viewHeight;
if (needVScroll) {
viewWidth -= m_vScrollBar.Width();
}
}
}
// 设置垂直滚动条
if (needVScroll) {
m_vScrollBar.SetVisible(true);
int vScrollHeight = Height() - m_headerHeight - (needHScroll ? m_hScrollBar.Height() : 0);
m_vScrollBar.SetRect(Rect(Width() - m_vScrollBar.Width(), m_headerHeight,
m_vScrollBar.Width(), vScrollHeight));
} else {
m_vScrollBar.SetVisible(false);
m_scrollOffsetY = 0;
}
// 设置水平滚动条
if (needHScroll) {
m_hScrollBar.SetVisible(true);
int hScrollWidth = Width() - m_firstColumnWidth - (needVScroll ? m_vScrollBar.Width() : 0);
m_hScrollBar.SetRect(Rect(m_firstColumnWidth, Height() - m_hScrollBar.Height(),
hScrollWidth, m_hScrollBar.Height()));
} else {
m_hScrollBar.SetVisible(false);
m_scrollOffsetX = 0;
}
m_vScrollBar.RefreshScroll();
m_hScrollBar.RefreshScroll();
}
void TableView::OffsetX(int offset) {
m_scrollOffsetX = -offset;
Invalidate();
}
void TableView::OffsetY(int offset) {
m_scrollOffsetY = -offset;
Invalidate();
}
void TableView::DoSort(int colIndex) {
if (colIndex < 0 || colIndex >= (int)m_columns.size()) {
return;
}
// 更新排序状态
SortOrder newOrder = SortOrder::Ascending;
if (m_columns[colIndex].CurrentSort == SortOrder::Ascending) {
newOrder = SortOrder::Descending;
} else if (m_columns[colIndex].CurrentSort == SortOrder::Descending) {
newOrder = SortOrder::None;
}
// 重置其他列的排序状态
for (auto& col : m_columns) {
col.CurrentSort = SortOrder::None;
}
m_columns[colIndex].CurrentSort = newOrder;
if (newOrder == SortOrder::None) {
Invalidate();
return;
}
// 创建索引数组进行排序
std::vector<int> indices(m_data.size());
for (int i = 0; i < (int)indices.size(); ++i) {
indices[i] = i;
}
// 排序
std::sort(indices.begin(), indices.end(), [this, colIndex, newOrder](int a, int b) {
UIString textA, textB;
if (colIndex < (int)m_data[a].size()) {
textA = m_data[a][colIndex].Text;
}
if (colIndex < (int)m_data[b].size()) {
textB = m_data[b][colIndex].Text;
}
if (newOrder == SortOrder::Ascending) {
return textA < textB;
} else {
return textA > textB;
}
});
// 重新排列数据
std::vector<std::vector<CellData>> newData(m_data.size());
std::vector<int> newRowHeights(m_rowHeights.size());
std::vector<bool> newRowChecked(m_rowChecked.size());
for (int i = 0; i < (int)indices.size(); ++i) {
int oldIndex = indices[i];
newData[i] = std::move(m_data[oldIndex]);
if (oldIndex < (int)m_rowHeights.size()) {
newRowHeights[i] = m_rowHeights[oldIndex];
}
if (oldIndex < (int)m_rowChecked.size()) {
newRowChecked[i] = m_rowChecked[oldIndex];
}
}
m_data = std::move(newData);
m_rowHeights = std::move(newRowHeights);
m_rowChecked = std::move(newRowChecked);
Invalidate();
}
// ============ 重写的虚函数 ============
void TableView::OnPaint(PaintEventArgs& args) {
__super::OnPaint(args);
// 绘制单元格(先绘制,这样表头会覆盖在上面)
DrawCells(args);
// 绘制表头
DrawHeader(args);
// 绘制滚动条
if (m_vScrollBar.IsVisible()) {
m_vScrollBar.SendEvent(args);
}
if (m_hScrollBar.IsVisible()) {
m_hScrollBar.SendEvent(args);
}
// 绘制编辑控件(放在最后确保在最上层)
if (m_editBox->IsVisible()) {
m_editBox->SendEvent(args);
}
}
void TableView::OnChildPaint(PaintEventArgs& args) {
// 重写子控件绘制,跳过 m_editBox因为我们在 OnPaint 中单独处理)
// 其他子控件正常绘制
ViewControls.clear();
Rect rect(0, 0, Width(), Height());
for (auto& it : GetControls()) {
if (it == m_editBox) {
continue; // 跳过编辑框,由 OnPaint 单独处理
}
if (rect.IntersectsWith(it->GetRect())) {
ViewControls.push_back(it);
}
it->SendEvent(args);
}
}
void TableView::OnLayout() {
// 设置滚动条位置
m_vScrollBar.SetRect(Rect(Width() - m_vScrollBar.Width(), m_headerHeight,
m_vScrollBar.Width(), Height() - m_headerHeight - (m_hScrollBar.IsVisible() ? m_hScrollBar.Height() : 0)));
m_hScrollBar.SetRect(Rect(m_firstColumnWidth, Height() - m_hScrollBar.Height(),
Width() - m_firstColumnWidth - (m_vScrollBar.IsVisible() ? m_vScrollBar.Width() : 0), m_hScrollBar.Height()));
RefreshScrollBars();
__super::OnLayout();
}
void TableView::OnMouseMove(const MouseEventArgs& args) {
__super::OnMouseMove(args);
// 转发事件给编辑框(用于文本选择)
if (m_editBox->IsVisible()) {
Rect editRect = m_editBox->GetRect();
m_editBox->SendEvent(MouseEventArgs(Event::OnMouseMove,
Point(args.Location.X - editRect.X, args.Location.Y - editRect.Y),
args.Button, args.ZDelta));
}
// 转发事件给滚动条
if (m_vScrollBar.IsVisible()) {
m_vScrollBar.SendEvent(MouseEventArgs(Event::OnMouseMove,
Point(args.Location.X - m_vScrollBar.X(), args.Location.Y - m_vScrollBar.Y()),
args.Button, args.ZDelta));
}
if (m_hScrollBar.IsVisible()) {
m_hScrollBar.SendEvent(MouseEventArgs(Event::OnMouseMove,
Point(args.Location.X - m_hScrollBar.X(), args.Location.Y - m_hScrollBar.Y()),
args.Button, args.ZDelta));
}
// 列宽拖动
if (m_draggingColumn) {
int delta = args.Location.X - m_dragStartX;
int newWidth = (std::max)(20, m_dragStartWidth + delta);
if (m_dragColumnIndex == -1) {
// 拖动第一列
m_firstColumnWidth = newWidth;
} else if (m_dragColumnIndex >= 0 && m_dragColumnIndex < (int)m_columns.size()) {
m_columns[m_dragColumnIndex].Width = newWidth;
}
RefreshScrollBars();
Invalidate();
return;
}
// 检测鼠标是否在列边界上
int borderCol = HitTestColumnBorder(args.Location);
if (borderCol >= -1) { // -1 表示第一列边界
// 设置调整大小的光标
Style.Cursor = LoadCursor(Cursor::SIZEWE);
} else {
Style.Cursor = LoadCursor(Cursor::ARROW);
}
// 更新悬停状态
int row, col;
if (HitTestCell(args.Location, &row, &col)) {
if (m_hoverRow != row || m_hoverCol != col) {
m_hoverRow = row;
m_hoverCol = col;
Invalidate();
}
}
}
void TableView::OnMouseDown(const MouseEventArgs& args) {
__super::OnMouseDown(args);
if (args.Button != MouseButton::Left) {
return;
}
// 检查是否点击在编辑框上
if (m_editBox->IsVisible()) {
Rect editRect = m_editBox->GetRect();
if (editRect.Contains(args.Location)) {
m_editBox->SendEvent(MouseEventArgs(Event::OnMouseDown,
Point(args.Location.X - editRect.X, args.Location.Y - editRect.Y),
args.Button, args.ZDelta));
return;
}
}
// 检查是否点击在滚动条上
if (HitTestVScrollBar(args.Location)) {
m_vScrollBar.SendEvent(MouseEventArgs(Event::OnMouseDown,
Point(args.Location.X - m_vScrollBar.X(), args.Location.Y - m_vScrollBar.Y()),
args.Button, args.ZDelta));
return;
}
if (HitTestHScrollBar(args.Location)) {
m_hScrollBar.SendEvent(MouseEventArgs(Event::OnMouseDown,
Point(args.Location.X - m_hScrollBar.X(), args.Location.Y - m_hScrollBar.Y()),
args.Button, args.ZDelta));
return;
}
// 检测是否点击在列边界上
int borderCol = HitTestColumnBorder(args.Location);
if (borderCol >= -1) {
m_draggingColumn = true;
m_dragColumnIndex = borderCol;
m_dragStartX = args.Location.X;
if (borderCol == -1) {
m_dragStartWidth = m_firstColumnWidth;
} else {
m_dragStartWidth = m_columns[borderCol].Width;
}
return;
}
int row, col;
if (!HitTestCell(args.Location, &row, &col)) {
EndEdit(true);
return;
}
// 点击表头
if (row == -1) {
if (col == -1) {
// 点击第一列表头(全选)
if (m_firstColumnType == FirstColumnType::CheckBox) {
m_headerSelectAll = !m_headerSelectAll;
for (int i = 0; i < (int)m_rowChecked.size(); ++i) {
m_rowChecked[i] = m_headerSelectAll;
}
Invalidate();
}
} else {
// 点击数据列表头(排序)
DoSort(col);
}
return;
}
// 点击第一列
if (col == -1) {
if (m_firstColumnType == FirstColumnType::CheckBox && row < (int)m_rowChecked.size()) {
m_rowChecked[row] = !m_rowChecked[row];
// 更新全选状态
bool allChecked = true;
for (bool checked : m_rowChecked) {
if (!checked) {
allChecked = false;
break;
}
}
m_headerSelectAll = allChecked;
Invalidate();
}
return;
}
// 点击数据单元格
// 获取单元格类型
CellType cellType = CellType::TextBox;
if (col >= 0 && col < (int)m_columns.size()) {
cellType = m_columns[col].Type;
}
// CheckBox 和 ComboBox 单击就触发
if (cellType == CellType::CheckBox || cellType == CellType::ComboBox) {
BeginEdit(row, col);
m_lastClickTime = 0;
m_lastClickRow = -1;
m_lastClickCol = -1;
return;
}
// TextBox 类型需要双击才进入编辑
ULONGLONG currentTime = ::GetTickCount64();
if (currentTime - m_lastClickTime < 300 &&
m_lastClickRow == row && m_lastClickCol == col) {
// 双击,开始编辑
BeginEdit(row, col);
m_lastClickTime = 0; // 重置,避免三击触发
m_lastClickRow = -1;
m_lastClickCol = -1;
} else {
// 单击,记录时间和位置
m_lastClickTime = currentTime;
m_lastClickRow = row;
m_lastClickCol = col;
EndEdit(true);
}
}
void TableView::OnMouseUp(const MouseEventArgs& args) {
__super::OnMouseUp(args);
m_draggingColumn = false;
// 转发事件给编辑框
if (m_editBox->IsVisible()) {
Rect editRect = m_editBox->GetRect();
m_editBox->SendEvent(MouseEventArgs(Event::OnMouseUp,
Point(args.Location.X - editRect.X, args.Location.Y - editRect.Y),
args.Button, args.ZDelta));
}
// 转发事件给滚动条
if (m_vScrollBar.IsVisible()) {
m_vScrollBar.SendEvent(MouseEventArgs(Event::OnMouseUp,
Point(args.Location.X - m_vScrollBar.X(), args.Location.Y - m_vScrollBar.Y()),
args.Button, args.ZDelta));
}
if (m_hScrollBar.IsVisible()) {
m_hScrollBar.SendEvent(MouseEventArgs(Event::OnMouseUp,
Point(args.Location.X - m_hScrollBar.X(), args.Location.Y - m_hScrollBar.Y()),
args.Button, args.ZDelta));
}
}
void TableView::OnMouseDoubleClick(const MouseEventArgs& args) {
__super::OnMouseDoubleClick(args);
int row, col;
if (HitTestCell(args.Location, &row, &col) && row >= 0 && col >= 0) {
BeginEdit(row, col);
}
}
void TableView::OnMouseWheel(const MouseEventArgs& args) {
__super::OnMouseWheel(args);
if (m_vScrollBar.IsVisible()) {
m_vScrollBar.SendEvent(MouseEventArgs(Event::OnMouseWheel, args.Location, args.Button, args.ZDelta));
}
}
void TableView::OnMouseLeave(const MouseEventArgs& args) {
__super::OnMouseLeave(args);
m_hoverRow = -1;
m_hoverCol = -1;
Style.Cursor = LoadCursor(Cursor::ARROW);
}
void TableView::OnSize(const SizeEventArgs& args) {
__super::OnSize(args);
RefreshScrollBars();
}
void TableView::OnKeyDown(const KeyboardEventArgs& args) {
__super::OnKeyDown(args);
// 如果编辑框可见,将键盘事件转发给编辑框
if (m_editBox->IsVisible()) {
m_editBox->SendEvent(args);
}
if (args.wParam == VK_ESCAPE) {
EndEdit(false);
} else if (args.wParam == VK_RETURN && !m_editing) {
// 如果不是多行编辑,回车可以结束编辑
}
}
void TableView::OnKeyChar(const KeyboardEventArgs& args) {
__super::OnKeyChar(args);
// 如果编辑框可见,将字符输入事件转发给编辑框
if (m_editBox->IsVisible()) {
m_editBox->SendEvent(args);
}
}
// ============ 公共接口实现 ============
void TableView::SetHeaders(const std::vector<UIString>& headers) {
m_columns.clear();
for (const auto& header : headers) {
ColumnInfo col;
col.HeaderText = header;
col.Width = 100;
m_columns.push_back(col);
}
// 更新现有数据的列数
for (auto& row : m_data) {
row.resize(m_columns.size());
}
RefreshScrollBars();
Invalidate();
}
int TableView::GetColumnCount() const {
return (int)m_columns.size();
}
void TableView::SetHeaderHeight(int height) {
m_headerHeight = (std::max)(20, height);
RefreshScrollBars();
Invalidate();
}
int TableView::GetHeaderHeight() const {
return m_headerHeight;
}
void TableView::SetFirstColumnType(FirstColumnType type) {
m_firstColumnType = type;
// 如果切换到 CheckBox 类型,初始化选中状态
if (type == FirstColumnType::CheckBox) {
m_rowChecked.resize(m_data.size(), false);
}
Invalidate();
}
FirstColumnType TableView::GetFirstColumnType() const {
return m_firstColumnType;
}
void TableView::SetFirstColumnWidth(int width) {
m_firstColumnWidth = (std::max)(20, width);
RefreshScrollBars();
Invalidate();
}
int TableView::GetFirstColumnWidth() const {
return m_firstColumnWidth;
}
void TableView::SetColumnWidth(int colIndex, int width) {
if (colIndex >= 0 && colIndex < (int)m_columns.size()) {
m_columns[colIndex].Width = (std::max)(20, width);
RefreshScrollBars();
Invalidate();
}
}
int TableView::GetColumnWidth(int colIndex) const {
if (colIndex >= 0 && colIndex < (int)m_columns.size()) {
return m_columns[colIndex].Width;
}
return 0;
}
const std::vector<int> TableView::GetColumnWidths() const {
std::vector<int> widths;
for (const auto& col : m_columns) {
widths.push_back(col.Width);
}
return widths;
}
void TableView::SetColumnType(int colIndex, CellType type) {
if (colIndex >= 0 && colIndex < (int)m_columns.size()) {
m_columns[colIndex].Type = type;
Invalidate();
}
}
CellType TableView::GetColumnType(int colIndex) const {
if (colIndex >= 0 && colIndex < (int)m_columns.size()) {
return m_columns[colIndex].Type;
}
return CellType::TextBox;
}
void TableView::SetColumnComboItems(int colIndex, const std::vector<UIString>& items) {
if (colIndex >= 0 && colIndex < (int)m_columns.size()) {
m_columns[colIndex].ComboItems = items;
}
}
int TableView::GetRowCount() const {
return (int)m_data.size();
}
void TableView::AddRow() {
std::vector<CellData> newRow(m_columns.size());
m_data.push_back(newRow);
m_rowHeights.push_back(m_defaultRowHeight);
if (m_firstColumnType == FirstColumnType::CheckBox) {
m_rowChecked.push_back(false);
}
RefreshScrollBars();
Invalidate();
}
void TableView::InsertRow(int rowIndex) {
if (rowIndex < 0) rowIndex = 0;
if (rowIndex > (int)m_data.size()) rowIndex = (int)m_data.size();
std::vector<CellData> newRow(m_columns.size());
m_data.insert(m_data.begin() + rowIndex, newRow);
m_rowHeights.insert(m_rowHeights.begin() + rowIndex, m_defaultRowHeight);
if (m_firstColumnType == FirstColumnType::CheckBox) {
m_rowChecked.insert(m_rowChecked.begin() + rowIndex, false);
}
RefreshScrollBars();
Invalidate();
}
void TableView::RemoveRow(int rowIndex) {
if (rowIndex >= 0 && rowIndex < (int)m_data.size()) {
m_data.erase(m_data.begin() + rowIndex);
m_rowHeights.erase(m_rowHeights.begin() + rowIndex);
if (rowIndex < (int)m_rowChecked.size()) {
m_rowChecked.erase(m_rowChecked.begin() + rowIndex);
}
RefreshScrollBars();
Invalidate();
}
}
void TableView::ClearRows() {
m_data.clear();
m_rowHeights.clear();
m_rowChecked.clear();
m_headerSelectAll = false;
m_scrollOffsetX = 0;
m_scrollOffsetY = 0;
RefreshScrollBars();
Invalidate();
}
void TableView::AddColumn(const UIString& headerText, int width) {
ColumnInfo col;
col.HeaderText = headerText;
col.Width = (std::max)(20, width);
m_columns.push_back(col);
// 为所有行添加新列的数据
for (auto& row : m_data) {
row.push_back(CellData());
}
RefreshScrollBars();
Invalidate();
}
void TableView::InsertColumn(int colIndex, const UIString& headerText, int width) {
if (colIndex < 0) colIndex = 0;
if (colIndex > (int)m_columns.size()) colIndex = (int)m_columns.size();
ColumnInfo col;
col.HeaderText = headerText;
col.Width = (std::max)(20, width);
m_columns.insert(m_columns.begin() + colIndex, col);
// 为所有行插入新列的数据
for (auto& row : m_data) {
row.insert(row.begin() + colIndex, CellData());
}
RefreshScrollBars();
Invalidate();
}
void TableView::RemoveColumn(int colIndex) {
if (colIndex >= 0 && colIndex < (int)m_columns.size()) {
m_columns.erase(m_columns.begin() + colIndex);
// 从所有行删除该列的数据
for (auto& row : m_data) {
if (colIndex < (int)row.size()) {
row.erase(row.begin() + colIndex);
}
}
RefreshScrollBars();
Invalidate();
}
}
int TableView::GetRowHeight(int rowIndex) const {
if (rowIndex >= 0 && rowIndex < (int)m_rowHeights.size()) {
return m_rowHeights[rowIndex];
}
return m_defaultRowHeight;
}
const std::vector<int> TableView::GetRowHeights() const {
return m_rowHeights;
}
void TableView::SetDefaultRowHeight(int height) {
m_defaultRowHeight = (std::max)(20, height);
}
void TableView::SetData(int row, int col, const UIString& value) {
// 自动扩展行
while (row >= (int)m_data.size()) {
AddRow();
}
// 确保列足够
if (col >= 0 && col < (int)m_columns.size()) {
if (col >= (int)m_data[row].size()) {
m_data[row].resize(m_columns.size());
}
m_data[row][col].Text = value;
UpdateRowHeight(row);
if (CellValueChanged) {
CellValueChanged(row, col, value);
}
}
}
UIString TableView::GetData(int row, int col) const {
if (row >= 0 && row < (int)m_data.size() &&
col >= 0 && col < (int)m_data[row].size()) {
return m_data[row][col].Text;
}
return UIString();
}
void TableView::SetRowData(int row, const std::vector<UIString>& values) {
// 自动扩展行
while (row >= (int)m_data.size()) {
AddRow();
}
for (int col = 0; col < (int)values.size() && col < (int)m_columns.size(); ++col) {
if (col >= (int)m_data[row].size()) {
m_data[row].resize(m_columns.size());
}
m_data[row][col].Text = values[col];
}
UpdateRowHeight(row);
}
std::vector<UIString> TableView::GetRowData(int row) const {
std::vector<UIString> result;
if (row >= 0 && row < (int)m_data.size()) {
for (const auto& cell : m_data[row]) {
result.push_back(cell.Text);
}
}
return result;
}
std::vector<UIString> TableView::GetColData(int col) const {
std::vector<UIString> result;
if (col >= 0 && col < (int)m_columns.size()) {
for (const auto& row : m_data) {
if (col < (int)row.size()) {
result.push_back(row[col].Text);
} else {
result.push_back(UIString());
}
}
}
return result;
}
void TableView::SetAllData(const std::vector<std::vector<UIString>>& data) {
ClearRows();
for (const auto& rowData : data) {
AddRow();
int row = (int)m_data.size() - 1;
for (int col = 0; col < (int)rowData.size() && col < (int)m_columns.size(); ++col) {
m_data[row][col].Text = rowData[col];
}
UpdateRowHeight(row);
}
}
std::vector<std::vector<UIString>> TableView::GetAllData() const {
std::vector<std::vector<UIString>> result;
for (int row = 0; row < (int)m_data.size(); ++row) {
result.push_back(GetRowData(row));
}
return result;
}
void TableView::SetCellChecked(int row, int col, bool checked) {
if (row >= 0 && row < (int)m_data.size() &&
col >= 0 && col < (int)m_data[row].size()) {
m_data[row][col].Checked = checked;
Invalidate();
}
}
bool TableView::GetCellChecked(int row, int col) const {
if (row >= 0 && row < (int)m_data.size() &&
col >= 0 && col < (int)m_data[row].size()) {
return m_data[row][col].Checked;
}
return false;
}
void TableView::SetCellComboIndex(int row, int col, int index) {
if (row >= 0 && row < (int)m_data.size() &&
col >= 0 && col < (int)m_data[row].size()) {
m_data[row][col].ComboIndex = index;
Invalidate();
}
}
int TableView::GetCellComboIndex(int row, int col) const {
if (row >= 0 && row < (int)m_data.size() &&
col >= 0 && col < (int)m_data[row].size()) {
return m_data[row][col].ComboIndex;
}
return -1;
}
void TableView::SetRowChecked(int row, bool checked) {
if (m_firstColumnType == FirstColumnType::CheckBox &&
row >= 0 && row < (int)m_rowChecked.size()) {
m_rowChecked[row] = checked;
// 更新全选状态
bool allChecked = true;
for (bool c : m_rowChecked) {
if (!c) {
allChecked = false;
break;
}
}
m_headerSelectAll = allChecked;
Invalidate();
}
}
bool TableView::GetRowChecked(int row) const {
if (row >= 0 && row < (int)m_rowChecked.size()) {
return m_rowChecked[row];
}
return false;
}
std::vector<int> TableView::GetCheckedRows() const {
std::vector<int> result;
for (int i = 0; i < (int)m_rowChecked.size(); ++i) {
if (m_rowChecked[i]) {
result.push_back(i);
}
}
return result;
}
void TableView::SelectAll() {
if (m_firstColumnType == FirstColumnType::CheckBox) {
m_headerSelectAll = true;
for (int i = 0; i < (int)m_rowChecked.size(); ++i) {
m_rowChecked[i] = true;
}
Invalidate();
}
}
void TableView::DeselectAll() {
if (m_firstColumnType == FirstColumnType::CheckBox) {
m_headerSelectAll = false;
for (int i = 0; i < (int)m_rowChecked.size(); ++i) {
m_rowChecked[i] = false;
}
Invalidate();
}
}
void TableView::SetCellBorderSize(int size) {
m_cellBorderSize = (std::max)(0, size);
Invalidate();
}
void TableView::SetCellBorderStyle(StrokeStyle style) {
m_cellBorderStyle = style;
Invalidate();
}
void TableView::SetCellBorderColor(const Color& color) {
m_cellBorderColor = color;
Invalidate();
}
void TableView::SetCellBackColor(const Color& color) {
m_cellBackColor = color;
Invalidate();
}
void TableView::SetCellForeColor(const Color& color) {
m_cellForeColor = color;
Invalidate();
}
void TableView::SetCellFontSize(int size) {
m_cellFontSize = (std::max)(8, size);
// 同步更新编辑框字体
m_editBox->Style.FontSize = m_cellFontSize;
// 更新所有行高
for (int i = 0; i < (int)m_data.size(); ++i) {
UpdateRowHeight(i);
}
}
void TableView::SetCellFontFamily(const std::wstring& fontFamily) {
m_cellFontFamily = fontFamily;
// 同步更新编辑框字体
m_editBox->Style.FontFamily = m_cellFontFamily;
// 更新所有行高
for (int i = 0; i < (int)m_data.size(); ++i) {
UpdateRowHeight(i);
}
}
void TableView::SetCellStyle(int row, int col, const CellStyle& style) {
if (row >= 0 && row < (int)m_data.size() &&
col >= 0 && col < (int)m_data[row].size()) {
m_data[row][col].Style = style;
Invalidate();
}
}
CellStyle TableView::GetCellStyle(int row, int col) const {
if (row >= 0 && row < (int)m_data.size() &&
col >= 0 && col < (int)m_data[row].size()) {
return m_data[row][col].Style;
}
return CellStyle();
}
void TableView::ResetCellStyle(int row, int col) {
if (row >= 0 && row < (int)m_data.size() &&
col >= 0 && col < (int)m_data[row].size()) {
m_data[row][col].Style.Reset();
Invalidate();
}
}
void TableView::SetHeaderBackColor(const Color& color) {
m_headerBackColor = color;
Invalidate();
}
void TableView::SetHeaderForeColor(const Color& color) {
m_headerForeColor = color;
Invalidate();
}
int TableView::GetHoverRow() const {
return m_hoverRow;
}
int TableView::GetHoverCol() const {
return m_hoverCol;
}
void TableView::GetHoverCell(int* outRow, int* outCol) const {
if (outRow) *outRow = m_hoverRow;
if (outCol) *outCol = m_hoverCol;
}
const Size& TableView::GetContentSize() {
// 计算内容大小供滚动条使用
m_contentSize.Width = GetContentWidth();
m_contentSize.Height = GetContentHeight();
return m_contentSize;
}
ScrollBar* TableView::GetVScrollBar() {
return &m_vScrollBar;
}
ScrollBar* TableView::GetHScrollBar() {
return &m_hScrollBar;
}
void TableView::SetAttribute(const UIString& key, const UIString& value) {
__super::SetAttribute(key, value);
// 辅助函数:解析整数
auto parseInt = [](const UIString& v) -> int {
UIString tmp = v;
ui_text::Replace(&tmp, "px", "");
tmp = tmp.trim();
return std::atoi(tmp.c_str());
};
// 辅助函数:解析颜色
auto parseColor = [](const UIString& v) -> Color {
bool isGood = false;
return Color::Make(v, &isGood);
};
do {
// 表头高度
if (key == "header-height" || key == "headerheight") {
SetHeaderHeight(parseInt(value));
break;
}
// 第一列类型
if (key == "first-column-type" || key == "firstcolumntype") {
if (value == "index" || value == "number") {
SetFirstColumnType(FirstColumnType::Index);
} else if (value == "checkbox" || value == "check") {
SetFirstColumnType(FirstColumnType::CheckBox);
} else {
SetFirstColumnType(FirstColumnType::TextBox);
}
break;
}
// 第一列宽度
if (key == "first-column-width" || key == "firstcolumnwidth") {
SetFirstColumnWidth(parseInt(value));
break;
}
// 默认行高
if (key == "default-row-height" || key == "defaultrowheight" || key == "row-height" || key == "rowheight") {
SetDefaultRowHeight(parseInt(value));
break;
}
// 单元格边框大小
if (key == "cell-border-size" || key == "cellbordersize" || key == "border-size" || key == "bordersize") {
SetCellBorderSize(parseInt(value));
break;
}
// 单元格边框样式
if (key == "cell-border-style" || key == "cellborderstyle" || key == "border-style" || key == "borderstyle") {
if (value == "solid") {
SetCellBorderStyle(StrokeStyle::Solid);
} else if (value == "dash" || value == "dashed") {
SetCellBorderStyle(StrokeStyle::Dash);
} else if (value == "none") {
SetCellBorderStyle(StrokeStyle::None);
}
break;
}
// 单元格边框颜色
if (key == "cell-border-color" || key == "cellbordercolor" || key == "border-color" || key == "bordercolor") {
SetCellBorderColor(parseColor(value));
break;
}
// 单元格背景颜色
if (key == "cell-back-color" || key == "cellbackcolor" || key == "cell-background" || key == "cellbackground") {
SetCellBackColor(parseColor(value));
break;
}
// 单元格前景颜色(文字颜色)
if (key == "cell-fore-color" || key == "cellforecolor" || key == "cell-color" || key == "cellcolor") {
SetCellForeColor(parseColor(value));
break;
}
// 单元格字体大小
if (key == "cell-font-size" || key == "cellfontsize") {
SetCellFontSize(parseInt(value));
break;
}
// 单元格字体
if (key == "cell-font-family" || key == "cellfontfamily" || key == "cell-font" || key == "cellfont") {
SetCellFontFamily(value.unicode());
break;
}
// 表头背景颜色
if (key == "header-back-color" || key == "headerbackcolor" || key == "header-background" || key == "headerbackground") {
SetHeaderBackColor(parseColor(value));
break;
}
// 表头前景颜色(文字颜色)
if (key == "header-fore-color" || key == "headerforecolor" || key == "header-color" || key == "headercolor") {
SetHeaderForeColor(parseColor(value));
break;
}
// 选中行背景颜色
if (key == "selected-row-back-color" || key == "selectedrowbackcolor" || key == "selected-color" || key == "selectedcolor") {
SelectedRowBackColor = parseColor(value);
Invalidate();
break;
}
// 表头文字(逗号分隔)
if (key == "headers" || key == "columns") {
auto headers = value.split(",");
std::vector<UIString> headerList;
for (auto& h : headers) {
headerList.push_back(h.trim());
}
SetHeaders(headerList);
break;
}
} while (false);
}
}