#pragma once #include "Control.h" #include "Label.h" #include "TextBox.h" #include "CheckBox.h" #include "ComboBox.h" #include "VScrollBar.h" #include "HScrollBar.h" #include #include namespace ezui { // 第一列类型枚举 enum class FirstColumnType { TextBox, // 空白文本框(默认) Index, // 不可编辑的序号(从1开始) CheckBox // 选择框 }; // 单元格类型枚举 enum class CellType { TextBox, // 文本框(默认) CheckBox, // 选择框 ComboBox, // 下拉选择框 ReadOnly // 不可编辑(可选中复制但不能修改) }; // 边框类型(复用框架的 StrokeStyle) // StrokeStyle::None - 无边框 // StrokeStyle::Solid - 实线 // StrokeStyle::Dash - 虚线 // 排序方向 enum class SortOrder { None, // 未排序 Ascending, // 升序 Descending // 降序 }; // 单元格独立样式(用于单独设置某个单元格的样式) struct CellStyle { Color BorderColor; StrokeStyle BorderStyle = StrokeStyle::None; Color BackColor; Color ForeColor; TextAlign Align = TextAlign::TopLeft; bool HasBorderColor = false; bool HasBorderStyle = false; bool HasBackColor = false; bool HasForeColor = false; bool HasTextAlign = false; void SetBorderColor(const Color& color) { BorderColor = color; HasBorderColor = true; } void SetBorderStyle(StrokeStyle style) { BorderStyle = style; HasBorderStyle = true; } void SetBackColor(const Color& color) { BackColor = color; HasBackColor = true; } void SetForeColor(const Color& color) { ForeColor = color; HasForeColor = true; } void SetTextAlign(ezui::TextAlign align) { Align = align; HasTextAlign = true; } void Reset() { HasBorderColor = false; HasBorderStyle = false; HasBackColor = false; HasForeColor = false; HasTextAlign = false; } }; // 单元格数据 struct CellData { UIString Text; // 单元格文本内容 bool Checked = false; // 用于 CheckBox 类型 int ComboIndex = -1; // 用于 ComboBox 类型,选中的索引 CellStyle Style; // 单元格独立样式 }; // 列信息 struct ColumnInfo { UIString HeaderText; // 表头文字 int Width = 100; // 列宽 CellType Type = CellType::TextBox; // 单元格类型 std::vector ComboItems; // 下拉选项(仅 ComboBox 类型有效) SortOrder CurrentSort = SortOrder::None; // 当前排序状态 TextAlign CellTextAlign = TextAlign::TopLeft; // 该列的默认对齐方式 }; class UI_EXPORT TableView : public Control { private: // 滚动条 VScrollBar m_vScrollBar; HScrollBar m_hScrollBar; // 数据存储 std::vector m_columns; // 列信息 std::vector> m_data; // 二维数据 [row][col] std::vector m_rowHeights; // 每行高度 std::vector m_rowChecked; // 每行的选中状态(第一列为CheckBox时使用) // 第一列配置 FirstColumnType m_firstColumnType = FirstColumnType::TextBox; int m_firstColumnWidth = 50; // 第一列宽度 // 表头配置 int m_headerHeight = 30; // 表头高度 bool m_headerSelectAll = false; // 表头全选状态 // 默认行高 int m_defaultRowHeight = 30; // 统一单元格样式 int m_cellBorderSize = 1; StrokeStyle m_cellBorderStyle = StrokeStyle::Solid; Color m_cellBorderColor = Color::LightGray; Color m_cellBackColor = Color::White; Color m_cellForeColor = Color::Black; int m_cellFontSize = 14; std::wstring m_cellFontFamily = L"Microsoft YaHei"; TextAlign m_cellTextAlign = TextAlign::TopLeft; // 默认对齐方式 std::vector m_rowTextAlign; // 每行的对齐方式(未设置时使用默认值) // 表头样式 Color m_headerBackColor = Color(0xFFE0E0E0); Color m_headerForeColor = Color::Black; // 滚动偏移 int m_scrollOffsetX = 0; int m_scrollOffsetY = 0; // 内容大小缓存(供GetContentSize使用) mutable Size m_contentSize; // 编辑状态 bool m_editing = false; int m_editRow = -1; int m_editCol = -1; TextBox* m_editBox = nullptr; ComboBox* m_editCombo = nullptr; CheckBox* m_editCheck = nullptr; // 列宽拖动 bool m_draggingColumn = false; int m_dragColumnIndex = -1; int m_dragStartX = 0; int m_dragStartWidth = 0; // 排序 int m_sortColumnIndex = -1; // 鼠标悬停 int m_hoverRow = -1; int m_hoverCol = -1; // 双击检测 ULONGLONG m_lastClickTime = 0; int m_lastClickRow = -1; int m_lastClickCol = -1; // 选中行(非CheckBox模式下,通过单击第一列选中的行) int m_selectedRow = -1; // 编辑前的原始值(用于编辑完成回调) UIString m_editOriginalValue; private: void Init(); // 计算总内容宽度 int GetContentWidth() const; // 计算总内容高度 int GetContentHeight() const; // 获取列起始X坐标(考虑滚动偏移) int GetColumnX(int colIndex) const; // 获取行起始Y坐标(考虑滚动偏移) int GetRowY(int rowIndex) const; // 根据坐标获取单元格位置 bool HitTestCell(const Point& pt, int* outRow, int* outCol) const; // 根据坐标检测是否在列边界上(用于拖动调整列宽) int HitTestColumnBorder(const Point& pt) const; // 检测是否点击在垂直滚动条上 bool HitTestVScrollBar(const Point& pt); // 检测是否点击在水平滚动条上 bool HitTestHScrollBar(const Point& pt); // 绘制表头 void DrawHeader(PaintEventArgs& args); // 绘制单元格 void DrawCells(PaintEventArgs& args); // 绘制单个单元格 void DrawCell(PaintEventArgs& args, int row, int col, const Rect& cellRect); // 绘制第一列 void DrawFirstColumn(PaintEventArgs& args, int row, const Rect& cellRect); // 开始编辑单元格 void BeginEdit(int row, int col); // 结束编辑 void EndEdit(bool save = true); // 更新行高(根据内容) void UpdateRowHeight(int row); // 计算文本需要的行数 int CalculateTextLines(const UIString& text, int width) const; // 刷新滚动条 void RefreshScrollBars(); // 滚动偏移处理 void OffsetX(int offset); void OffsetY(int offset); // 执行排序 void DoSort(int colIndex); protected: virtual void OnPaint(PaintEventArgs& args) override; virtual void OnChildPaint(PaintEventArgs& args) override; virtual void OnLayout() override; virtual void OnMouseMove(const MouseEventArgs& args) override; virtual void OnMouseDown(const MouseEventArgs& args) override; virtual void OnMouseUp(const MouseEventArgs& args) override; virtual void OnMouseDoubleClick(const MouseEventArgs& args) override; virtual void OnMouseWheel(const MouseEventArgs& args) override; virtual void OnMouseLeave(const MouseEventArgs& args) override; virtual void OnSize(const SizeEventArgs& args) override; virtual void OnKeyDown(const KeyboardEventArgs& args) override; virtual void OnKeyChar(const KeyboardEventArgs& args) override; virtual const Size& GetContentSize() override; public: // 选中行背景色(当第一列为CheckBox且被选中时使用,或者单击选中行时使用) Color SelectedRowBackColor = Color(0xFFADD8E6); // 浅蓝色 /* table->CellValueChanged = [](int row, int col, const UIString& value) { // 处理内容变化 }; */ // 单元格内容变化回调(内容变化时立即触发) // 参数: row, col, newValue std::function CellValueChanged = nullptr; /* table->CellEditFinished = [](int row, int col, const UIString& oldValue, const UIString& newValue) { // 处理内容变化 }; */ // 单元格编辑完成回调(编辑结束时触发,比如TextBox失去焦点或按Enter时) // 参数: row, col, oldValue, newValue std::function CellEditFinished = nullptr; /* tableView->RightClick= [tableView](int row, int col) { // 处理内容变化 }; */ // 鼠标右键单击回调 // 参数: row, col (row=-1 表示点击在表头,col=-1 表示点击在第一列) std::function RightClick = nullptr; public: TableView(Object* parentObject = nullptr); virtual ~TableView(); // ============ 表头设置 ============ // 设置表头(传入表头名数组) void SetHeaders(const std::vector& headers); // 获取表头数量(不包含第一列) int GetColumnCount() const; // 设置表头高度 void SetHeaderHeight(int height); // 获取表头高度 int GetHeaderHeight() const; // ============ 第一列设置 ============ // 设置第一列类型 void SetFirstColumnType(FirstColumnType type); // 获取第一列类型 FirstColumnType GetFirstColumnType() const; // 设置第一列宽度 void SetFirstColumnWidth(int width); // 获取第一列宽度 int GetFirstColumnWidth() const; // ============ 列设置 ============ // 设置某列宽度 void SetColumnWidth(int colIndex, int width); // 获取某列宽度 int GetColumnWidth(int colIndex) const; // 获取所有列宽 const std::vector GetColumnWidths() const; // 设置某列单元格类型 void SetColumnType(int colIndex, CellType type); // 获取某列单元格类型 CellType GetColumnType(int colIndex) const; // 设置某列的下拉选项(仅对 ComboBox 类型有效) void SetColumnComboItems(int colIndex, const std::vector& items); // ============ 行设置 ============ // 获取行数 int GetRowCount() const; // 添加行 void AddRow(); // 插入行 void InsertRow(int rowIndex); // 删除行 void RemoveRow(int rowIndex); // 清空所有行 void ClearRows(); // 添加列 void AddColumn(const UIString& headerText = L"", int width = 100); // 插入列 void InsertColumn(int colIndex, const UIString& headerText = L"", int width = 100); // 删除列 void RemoveColumn(int colIndex); // 获取行高 int GetRowHeight(int rowIndex) const; // 获取所有行高 const std::vector GetRowHeights() const; // 设置默认行高 void SetDefaultRowHeight(int height); // ============ 数据操作 ============ // 设置单个单元格数据 void SetData(int row, int col, const UIString& value); // 获取单个单元格数据 UIString GetData(int row, int col) const; // 设置整行数据 void SetRowData(int row, const std::vector& values); // 获取整行数据 std::vector GetRowData(int row) const; // 获取整列数据 std::vector GetColData(int col) const; // 设置全部数据(二维数组) void SetAllData(const std::vector>& data); // 获取全部数据 std::vector> GetAllData() const; // 设置单元格 CheckBox 状态 void SetCellChecked(int row, int col, bool checked); // 获取单元格 CheckBox 状态 bool GetCellChecked(int row, int col) const; // 设置单元格 ComboBox 选中索引 void SetCellComboIndex(int row, int col, int index); // 获取单元格 ComboBox 选中索引 int GetCellComboIndex(int row, int col) const; // ============ 行选中(第一列为CheckBox时) ============ // 设置某行选中状态 void SetRowChecked(int row, bool checked); // 获取某行选中状态 bool GetRowChecked(int row) const; // 获取所有选中的行索引 std::vector GetCheckedRows() const; // 获取当前选中的行(非CheckBox模式,通过单击第一列选中) int GetSelectedRow() const; // 设置当前选中的行(非CheckBox模式) void SetSelectedRow(int row); // 清除选中行(非CheckBox模式) void ClearSelection(); // 全选 void SelectAll(); // 取消全选 void DeselectAll(); // ============ 样式设置 ============ // 设置统一单元格样式 void SetCellBorderSize(int size); void SetCellBorderStyle(StrokeStyle style); void SetCellBorderColor(const Color& color); void SetCellBackColor(const Color& color); void SetCellForeColor(const Color& color); void SetCellFontSize(int size); void SetCellFontFamily(const std::wstring& fontFamily); // 设置单独单元格样式 void SetCellStyle(int row, int col, const CellStyle& style); // 获取单独单元格样式 CellStyle GetCellStyle(int row, int col) const; // 重置单独单元格样式(使用统一样式) void ResetCellStyle(int row, int col); // 设置表头样式 void SetHeaderBackColor(const Color& color); void SetHeaderForeColor(const Color& color); // ============ 对齐方式设置 ============ // 设置默认对齐方式(影响所有未单独设置对齐方式的单元格) void SetDefaultTextAlign(TextAlign align); // 设置某列的对齐方式 void SetColumnTextAlign(int colIndex, TextAlign align); // 设置某行的对齐方式 void SetRowTextAlign(int rowIndex, TextAlign align); // 设置单个单元格的对齐方式 void SetCellTextAlign(int row, int col, TextAlign align); // 获取单元格的对齐方式(考虑优先级:单元格 > 行 > 列 > 默认) TextAlign GetCellTextAlign(int row, int col) const; // ============ 鼠标悬停信息 ============ // 获取鼠标当前悬停的行号(-1表示表头或未悬停在任何行) int GetHoverRow() const; // 获取鼠标当前悬停的列号(-1表示第一列或未悬停在任何列) int GetHoverCol() const; // 获取鼠标当前悬停的行列号(通过指针返回) void GetHoverCell(int* outRow, int* outCol) const; // ============ 滚动条 ============ virtual ScrollBar* GetVScrollBar(); virtual ScrollBar* GetHScrollBar(); // ============ 属性设置(XML支持) ============ virtual void SetAttribute(const UIString& key, const UIString& value) override; }; };