#include "Table_View.h" #include #include #include "../../Generate_Mock_Data.h" #include "Base_Table_Data.h" #include "Base_Info.h" namespace Psc { /* 我的表格是一个存粹的painter 实现 这样的话 我任何东西都可以 通过 虚函数去实现 我可以虚函数 给这些所有 视觉上元素的拓展无非就是 位置,如何绘制,允许传来自定义参数, 允许嵌入自己的组件 所以我每一个视觉上的组件都要有这个信息 那么元素上的事件处理呢? 无非是鼠标 键盘 */ QPoint Table_View::to_inside_pos(QPoint widget_pos) { auto rect = get_view_rect(); return widget_pos + this->_view_pos - QPoint(rect.left(), rect.top()); } QPoint Table_View::to_widget_pos(QPoint inside_pos) { auto rect = get_view_rect(); return inside_pos - this->_view_pos + QPoint(rect.left(), rect.top()); } QRect Table_View::get_view_rect() { int left = row_info_w + row_info_inside_space + left_margin; int top = col_info_h + col_info_inside_space + top_margin; int right = (v_bar.show ? static_cast(v_bar.w) : 0) + right_margin; int bottom = (h_bar.show ? static_cast(h_bar.h) : 0) + bottom_margin; QRect all_view_rect = QRect(left, top, width() - left - right, height() - top - bottom); return all_view_rect; } Table_View::Table_View() { setAttribute(Qt::WA_Hover); setMouseTracking(true); edit = new QTextEdit(); container = new Container(this); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } void Table_View::resizeEvent(QResizeEvent* event) { QRect vr = get_view_rect(); h_bar.start = vr.x(); h_bar.resize(vr.width(), vr.width(), model->width()); v_bar.start = vr.y(); v_bar.resize(vr.height(), vr.height(), model->height()); container->setGeometry(vr); QWidget::resizeEvent(event); } bool Table_View::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::Enter) { setCursor(Qt::ArrowCursor); } return QObject::eventFilter(obj, event); } void Table_View::paintEvent(QPaintEvent* event) { static QImage img(":/jian_hao.png"); static QImage img2(":/jia_hao.png"); static int space = 4; QPainter painter(this); // 视图位置转换为绝对位置 QRect cells_widget_rect = get_view_rect(); QPen pen(Qt::black, 1); painter.setPen(pen); painter.drawRect(cells_widget_rect.adjusted(-1, -1, 0, 0)); auto inside_sta_pos = to_inside_pos(cells_widget_rect.topLeft()); auto inside_end_pos = to_inside_pos(cells_widget_rect.bottomRight()); Pos x_sta = model->get_col(inside_sta_pos.rx()); Pos y_sta = model->get_row(inside_sta_pos.ry()); Pos x_end = model->get_col(inside_end_pos.rx()); Pos y_end = model->get_row(inside_end_pos.ry()); struct Paint_Cache { int cell_abs_pos; int index; Base_Info* info; }; // 计算横着每个格子起点的绝对位置 int xsi = x_sta.index; int max_col_num = std::min(x_end.index - x_sta.index + 1, model->total_col()); int col_num = 0; QVector xs; { int cur_x = x_sta.cell_pos; for (int i = 0; i < max_col_num; ++i) { auto cur = model->get_col_info(xsi + i); if (cur->hide) continue; xs.push_back({cur_x, i, cur}); cur_x += cur->len + model->col_space; } col_num = xs.size(); } // 计算竖着每个格子起点的绝对位置 int ysi = y_sta.index; int max_row_num = std::min(y_end.index - y_sta.index + 1, model->total_row()); int row_num = 0; QVector ys; { int cur_y = y_sta.cell_pos; for (int i = 0; i < max_row_num; ++i) { auto cur = model->get_row_info(ysi + i); if (cur->hide) continue; ys.push_back({cur_y, i, cur}); cur_y += cur->len + model->row_space; } row_num = ys.size(); } // 绘制表头 水平 { painter.setPen(Qt::black); int end_y = cells_widget_rect.y() - col_info_inside_space; int sta_y = end_y - col_info_h; { QPoint s = QPoint(cells_widget_rect.x(), sta_y); QPoint e = QPoint(cells_widget_rect.right(), end_y); painter.setClipRect(QRect(s, e)); } QVector middle_xs(col_num + 1); for (int i = 0; i < col_num; ++i) { auto& xd = xs[i]; int sta_x = to_widget_pos({xd.cell_abs_pos, 0}).rx(); int end_x = to_widget_pos({xd.cell_abs_pos + xd.info->len, 0}).rx(); if (i == 0) { middle_xs[0] = sta_x - model->row_space / 2; } middle_xs[i + 1] = end_x + model->row_space / 2; QRect re(QPoint(sta_x, sta_y), QPoint(end_x, end_y)); xd.info->paint(&painter, re); } { QPoint s = QPoint(cells_widget_rect.x(), sta_y); painter.setClipRect(QRect(s, cells_widget_rect.bottomRight())); } painter.setPen(Qt::black); for (int i = 0; i < col_num; ++i) { int middle_x = middle_xs[i]; painter.drawLine(QPoint(middle_x, 0), QPoint(middle_x, height())); } } // 绘制表头 竖直 { painter.setPen(Qt::black); int end_x = cells_widget_rect.x() - row_info_inside_space; int sta_x = end_x - row_info_w; { QPoint s = QPoint(sta_x, cells_widget_rect.y()); QPoint e = QPoint(end_x, cells_widget_rect.bottom()); painter.setClipRect(QRect(s, e)); } QVector middle_ys(row_num); for (int i = 0; i < row_num; ++i) { auto& yd = ys[i]; int sta_y = to_widget_pos({0, yd.cell_abs_pos}).ry(); int end_y = to_widget_pos({0, yd.cell_abs_pos + yd.info->len}).ry(); middle_ys[i] = end_y + model->col_space / 2; QRect re(QPoint(sta_x, sta_y), QPoint(end_x, end_y)); yd.info->paint(&painter, re); } { QPoint s = QPoint(sta_x, cells_widget_rect.y()); painter.setClipRect(QRect(s, cells_widget_rect.bottomRight())); } painter.setPen(Qt::black); for (int i = 0; i < row_num; ++i) { int middle_y = middle_ys[i]; painter.drawLine(QPoint(0, middle_y), QPoint(width(), middle_y)); } } // 绘制滚动条 if (h_bar.show) { h_bar.draw(&painter); } if (v_bar.show) { v_bar.draw(&painter); } QSet set; // 绘制小方格 painter.setClipRect(cells_widget_rect); painter.setPen(Qt::black); for (auto& xd : xs) { for (auto& yd : ys) { int xi = xsi + xd.index; int yi = ysi + yd.index; auto cur_cell = model->get_table_data(xi, yi); QPoint cur_inside_sta_pos; QPoint cur_inside_end_pos; auto show_cell = cur_cell; bool show = true; if (cur_cell->parent != nullptr && cur_cell->parent != cur_cell) { auto r = model->find_parent(cur_cell->parent, xi, yi); if ( r.col_index < xsi || r.row_index < ysi ) { if (!set.contains(cur_cell->parent)) { set.insert(cur_cell->parent); int sxi = r.col_index; int syi = r.row_index; show = true; auto info = model->get_span(sxi, syi); int x = model->cell_x(sxi); int y = model->cell_y(syi); cur_inside_sta_pos = {x, y}; cur_inside_end_pos = {x + info.sw, y + info.sh}; show_cell = model->get_table_data(sxi, syi); } else { show = false; } } } else { auto info = model->get_span(xi, yi); cur_inside_sta_pos = {xd.cell_abs_pos, yd.cell_abs_pos}; cur_inside_end_pos = {xd.cell_abs_pos + info.sw, yd.cell_abs_pos + info.sh}; } QPoint cur_widget_sta_pos = to_widget_pos(cur_inside_sta_pos); QPoint cur_widget_end_pos = to_widget_pos(cur_inside_end_pos); QRect cur_view_rect = QRect(cur_widget_sta_pos, cur_widget_end_pos); show_cell->update(show, this, &painter, cur_view_rect); } } } bool Table_View::event(QEvent* e) { if ( e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseMove || e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::MouseButtonDblClick ) { auto event = static_cast(e); mouse_event(event, event->type()); return true; } return QWidget::event(e); } void Table_View::leaveEvent(QEvent* event) { QWidget::leaveEvent(event); } void Table_View::mouse_event(QMouseEvent* event, QEvent::Type type) { QRect cells_widget_rect = get_view_rect(); auto pos = event->pos(); auto abs_pos = to_inside_pos(pos); Pos px = model->get_col(abs_pos.x()); Pos py = model->get_row(abs_pos.y()); bool drag_on_col_space = false; bool drag_on_row_space = false; Col_Info* cur_col{}; Row_Info* cur_row{}; if (model->total_col() != 0) { cur_col = model->get_col_info(px.index); if (use_drag_w&& px.offset > cur_col->len && px.offset < cur_col->len + model->col_space) { drag_on_col_space = true; } } if (model->total_row() != 0) { cur_row = model->get_row_info(py.index); if (use_drag_h&& py.offset > cur_row->len && py.offset < cur_row->len + model->row_space) { drag_on_row_space = true; } } bool on_h_slider = h_bar.get_slider_rect(width(), height()).contains(event->pos()); bool on_v_slider = v_bar.get_slider_rect(width(), height()).contains(event->pos()); bool on_cells_view = cells_widget_rect.contains(pos); if (cur_col && cur_row) { auto cur_cell = model->get_table_data(px.index, py.index); auto parent_pos = model->find_parent(cur_cell->parent, px.index, py.index); auto show_cell = model->get_table_data(parent_pos.col_index, parent_pos.row_index); int sci = parent_pos.col_index; int sri = parent_pos.row_index; auto sx = model->cell_x(sci); auto sy = model->cell_y(sri); auto info = model->get_span(parent_pos.col_index, parent_pos.row_index); QPoint s_sta = to_widget_pos({sx, sy}); QPoint s_end = to_widget_pos({sx + info.sw, sy + info.sh}); QRect srect = QRect(s_sta, s_end); if (type == QEvent::MouseButtonDblClick) { if (on_cells_view && srect.contains(s_sta)) { edit->setGeometry(srect); prev_data = show_cell; auto ttd = dynamic_cast(show_cell); if (ttd) { edit->setText(ttd->content); edit->setParent(this); edit->show(); } } } } if (type == QEvent::MouseButtonPress) { //qDebug() << "cur_cell " << cur_cell->content ; //qDebug() << "cur_cell_parent "<< (cur_cell->parent ? cur_cell->parent->content : "nullptr"); edit->hide(); if (prev_data) { auto ttd = dynamic_cast(prev_data); if (ttd) { ttd->content = edit->toPlainText(); prev_data = nullptr; update(); } } // qDebug() << log; if (is_ctrl_pressed()) { isDragging = true; drag_type = Table_Move; setCursor(Qt::OpenHandCursor); } else if (on_h_slider) { isDragging = true; drag_type = H_scrollBar; setCursor(Qt::SizeHorCursor); } else if (on_v_slider) { isDragging = true; drag_type = V_scrollBar; setCursor(Qt::SizeVerCursor); } else if (drag_on_col_space) { isDragging = true; drag_type = H_Expand; col_expand = cur_col; start_expand_len = col_expand->len; setCursor(Qt::SplitHCursor); } else if (drag_on_row_space) { isDragging = true; drag_type = V_Expand; row_expand = cur_row; start_expand_len = row_expand->len; setCursor(Qt::SplitVCursor); } else { setCursor(Qt::ArrowCursor); } if (isDragging) { start_pos = event->pos(); save_pos = _view_pos; } } else if (type == QEvent::MouseButtonRelease) { isDragging = false; if (drag_on_col_space) { setCursor(Qt::SplitHCursor); } else if (drag_on_row_space) { setCursor(Qt::SplitVCursor); } else if (on_h_slider) { setCursor(Qt::SizeHorCursor); } else if (on_v_slider) { setCursor(Qt::SizeVerCursor); } else { setCursor(Qt::ArrowCursor); } } else if (type == QEvent::MouseMove) { if (is_ctrl_pressed()) { if (isDragging) { setCursor(Qt::ClosedHandCursor); } else { setCursor(Qt::OpenHandCursor); } } else { if (!isDragging) { if (drag_on_col_space) { setCursor(Qt::SplitHCursor); } else if (drag_on_row_space) { setCursor(Qt::SplitVCursor); } else if (on_h_slider) { setCursor(Qt::SizeHorCursor); } else if (on_v_slider) { setCursor(Qt::SizeVerCursor); } else { setCursor(Qt::ArrowCursor); } } } if (!isDragging) return; QPoint cur_pos = event->pos(); int deltaX = cur_pos.x() - start_pos.x(); // 计算X轴的拖动距离 int deltaY = cur_pos.y() - start_pos.y(); // 计算Y轴的拖动距离 if (drag_type == Table_Move && is_ctrl_pressed()) { int end_x = save_pos.x() - deltaX; int end_y = save_pos.y() - deltaY; _view_pos.setX(end_x); _view_pos.setY(end_y); h_bar.set_view_pos(_view_pos.rx()); v_bar.set_view_pos(_view_pos.ry()); } else if (drag_type == H_scrollBar) { int end_x = save_pos.x() + deltaX / h_bar.rate(); _view_pos.setX(end_x); h_bar.set_view_pos(end_x); } else if (drag_type == V_scrollBar) { int end_y = save_pos.y() + deltaY / v_bar.rate(); _view_pos.setY(end_y); v_bar.set_view_pos(end_y); } else if (drag_type == H_Expand) { col_expand->len = std::max(model->col_min_w, start_expand_len + deltaX); } else if (drag_type == V_Expand) { row_expand->len = std::max(model->row_min_h, start_expand_len + deltaY); } update(); } } void Table_View::wheelEvent(QWheelEvent* event) { int single_step = 12; double v_steps = event->angleDelta().y() / 120; v_bar.set_view_pos(v_bar.get_view_pos() - v_steps * single_step); double h_steps = event->angleDelta().x() / 120; h_bar.set_view_pos(h_bar.get_view_pos() - h_steps * single_step); _view_pos.setX(h_bar.view_pos()); _view_pos.setY(v_bar.view_pos()); update(); } } #ifdef YC_USE_GTEST #include TEST(Table, get_pos_test) { QVector info_list; // 4 2 1 // 4 6 7 info_list.push_back(new Base_info(4, "")); info_list.push_back(new Base_info(1, "")); auto size = static_cast(info_list.size()); auto d = info_list.data(); QVector> combinedData = { {Base_Table_Info::Pos{0, 0, -7}, -7}, {Base_Table_Info::Pos{0, 0, 4}, 4}, {Base_Table_Info::Pos{1, 6, 1}, 7}, {Base_Table_Info::Pos{1, 6, 2}, 8}, }; for (auto it : combinedData) { auto answer = it.first; auto input = it.second; auto pos = get_pos(d, size, 2, input, 0); EXPECT_TRUE(pos == answer) << "输入:" << input << "\n" << "结果:" + pos.to_string() << "\n" << "期望:" + answer.to_string() << "\n"; } } // 测试 Matrix 类的基本操作 TEST(MatrixTest, BasicOperations) { // 初始化一个 3x3 矩阵 Table mat; mat.data = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; // 测试 total_row 和 total_col EXPECT_EQ(mat.total_row(), 3); EXPECT_EQ(mat.total_col(), 3); // 测试 at 方法 EXPECT_EQ(mat.at(0, 0), 1); EXPECT_EQ(mat.at(1, 1), 5); EXPECT_EQ(mat.at(2, 2), 9); // 测试 row 方法 QVector row_0 = mat.row(0); EXPECT_EQ(row_0.size(), 3); EXPECT_EQ(row_0[0], 1); EXPECT_EQ(row_0[1], 2); EXPECT_EQ(row_0[2], 3); // 测试 col 方法 QVector col_0 = mat.col(0); EXPECT_EQ(col_0.size(), 3); EXPECT_EQ(col_0[0], 1); EXPECT_EQ(col_0[1], 4); EXPECT_EQ(col_0[2], 7); // 测试 sub_matrix 方法 Table sub_mat = mat.sub_table(0, 0, 2, 2); EXPECT_EQ(sub_mat.total_row(), 2); EXPECT_EQ(sub_mat.total_col(), 2); EXPECT_EQ(sub_mat.at(0, 0), 1); EXPECT_EQ(sub_mat.at(1, 1), 5); } TEST(MatrixTest, SubMatrix) { // 测试提取子矩阵 Table mat; mat.data = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; Table sub_mat = mat.sub_table(1, 1, 2, 2); EXPECT_EQ(sub_mat.total_row(), 2); EXPECT_EQ(sub_mat.total_col(), 2); EXPECT_EQ(sub_mat.at(0, 0), 5); EXPECT_EQ(sub_mat.at(0, 1), 6); EXPECT_EQ(sub_mat.at(1, 0), 8); EXPECT_EQ(sub_mat.at(1, 1), 9); } TEST(MatrixTest, EmptyMatrix) { // 测试空矩阵 Table mat; EXPECT_EQ(mat.total_row(), 0); EXPECT_EQ(mat.total_col(), 0); } TEST(MatrixTest, SingleElementMatrix) { // 测试 1x1 矩阵 Table mat; mat.data = {{42}}; EXPECT_EQ(mat.total_row(), 1); EXPECT_EQ(mat.total_col(), 1); EXPECT_EQ(mat.at(0, 0), 42); } #include #ifdef _WINDOWS #include #endif int main() { QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); #ifdef _WINDOWS SetConsoleOutputCP (CP_UTF8); #endif testing::InitGoogleTest(); RUN_ALL_TESTS(); return 0; } #endif