// table_demo_efficient.cpp // ncurses table: FULL DRAW ONCE, then update ONLY changed cells (no clear, no border redraw) // Compile: g++ -o table_demo table_demo_efficient.cpp -lncurses -std=c++11 // Run: ./table_demo1 #include #include using namespace std; std::string pad_left(const std::string& s, int width) { std::string cell = s; if (cell.size() > static_cast(width)) cell.resize(width); return cell + std::string(width - static_cast(cell.size()), ' '); } std::string pad_center(const std::string& s, int width) { std::string cell = s; if (cell.size() > static_cast(width)) cell.resize(width); size_t len = cell.size(); int left = (width - static_cast(len)) / 2; return std::string(left, ' ') + cell + std::string(width - left - static_cast(len), ' '); } void draw_full_table(const std::vector& headers, const std::vector>& data, const std::vector& col_widths, const std::vector& content_x) { clear(); int y = 0; // Horizontal line (perfectly aligned with | positions) std::string hline = "+"; for (int w : col_widths) hline += std::string(w + 2, '-') + "+"; mvaddstr(y++, 0, hline.c_str()); // Header row (centered, full width padded) mvaddstr(y, 0, "|"); for (size_t i = 0; i < headers.size(); ++i) { std::string padded = pad_center(headers[i], col_widths[i]); mvaddstr(y, content_x[i], padded.c_str()); mvaddch(y, content_x[i] + col_widths[i] + 1, '|'); } y++; // Header separator mvaddstr(y++, 0, hline.c_str()); // Data rows (left-aligned, full width padded) for (const auto& row : data) { mvaddstr(y, 0, "|"); for (size_t i = 0; i < row.size(); ++i) { std::string padded = pad_left(row[i], col_widths[i]); mvaddstr(y, content_x[i], padded.c_str()); mvaddch(y, content_x[i] + col_widths[i] + 1, '|'); } y++; } // Bottom border mvaddstr(y, 0, hline.c_str()); refresh(); } void update_cell(int data_row, int col, const std::string& new_value, const std::vector& content_x, const std::vector& col_widths) { int y = 3 + data_row; // data starts at row 3 int x = content_x[col]; std::string padded = pad_left(new_value, col_widths[col]); mvaddstr(y, x, padded.c_str()); // ONLY the content area is overwritten refresh(); // ncurses still optimizes, but no full redraw } int main() { initscr(); cbreak(); noecho(); curs_set(0); keypad(stdscr, TRUE); std::vector headers = {"ID", "Name", "Score"}; std::vector> data = { {"1", "Alice", "100"}, {"2", "Bob", "95"}, {"3", "Charlie", "85"} }; std::vector col_widths = {6, 20, 10}; // Pre-compute exact content start positions (CRITICAL for correct alignment) std::vector content_x(headers.size()); int cx = 2; for (size_t i = 0; i < col_widths.size(); ++i) { content_x[i] = cx; cx += col_widths[i] + 3; // +3 = space + width + space } // === FULL DRAW ONLY ONCE === draw_full_table(headers, data, col_widths, content_x); // Simulate delay napms(2000); // ncurses sleep (milliseconds) // === UPDATE ONLY CHANGED CELLS (no clear, no borders touched) === update_cell(0, 2, "110", content_x, col_widths); // Alice score 100 → 110 napms(1000); update_cell(2, 1, "Chuck", content_x, col_widths); // Charlie → Chuck // Optional: update another cell to prove multiple updates work vector prices{"125","126","127","128","129","130","131"}; for (auto& px: prices) { update_cell(0, 2, px, content_x, col_widths); napms(500); } // Message below the table (static, never redrawn) int table_bottom = 3 + static_cast(data.size()); mvaddstr(table_bottom + 2, 0, "Only changed cells were updated, no full redraw, no clear()!"); mvaddstr(table_bottom + 3, 0, "Press any key to exit..."); refresh(); getch(); endwin(); return 0; }