C++实现基于EasyX的简单表格类TableWidget

本文展示了如何在C++中利用EasyX库创建简单的GUI组件,包括按钮类Button、文本框类TextBox和一个具有滚动功能的表格类TableWidget。TableWidget支持数据设置、滚动和选择行的功能,是构建图形界面的基础元素。
摘要由CSDN通过智能技术生成

系列文章目录

C++实现基于EasyX的简单按钮类Button以及简单界面跳转

C++实现基于EasyX的简单文本框类TextBox


目录

一、效果展示

二、代码


一、效果展示

二、代码

#include <graphics.h>
#include <string>
#include <vector>
using namespace std;
//表格类
class TableWidget {
private:
    int x;
    int y;
    int width;
    int height;
    int visibleRowCount;//最多可见行数
    int rowHeight;      //行的高度
    int scrollOffset;   //偏移
    vector<vector<wstring>> data;
    vector<int> columnWidths;//列的宽度
    int selectedRow;        //被选中的行
    int scrollbarWidth;
    int handleHeight;
    int handleY;

public:
    TableWidget(int x, int y, int width, int height, int visibleRowCount)
        : x(x), y(y), width(width), height(height), visibleRowCount(visibleRowCount) {
        data = { {} };
        rowHeight = height / visibleRowCount;
        selectedRow = -1;
        scrollOffset = 0;
        scrollbarWidth = 20;
        handleHeight = 30;
        handleY = 0;
    }

    int getSelectedRow() const
    {
        return selectedRow;
    }

    wstring getSelectedInfo(int col) const
    {
        return data[selectedRow][col];
    }

    void setData(const vector<vector<wstring>>& newData)
    {
        data = newData;
        calculateColumnWidths();
    }

    //计算每列的宽度
    void calculateColumnWidths()
    {
        columnWidths.clear();
        if (!data.empty())
        {
            columnWidths.resize(data[0].size(), 0);
            for (const auto& row : data)
            {
                for (size_t j = 0; j < row.size(); ++j)
                {
                    int width = textwidth(row[j].c_str());
                    if (width > columnWidths[j])    //每列的最大宽度(即每列中字符最大长度)
                    {
                        columnWidths[j] = width;
                    }
                }
            }
        }
        //根据每列最大宽度计算该列长度
        int sumWidth = 0;
        for (auto it : columnWidths)
            sumWidth += it;
        for (auto& it : columnWidths)
            it = (float)it / sumWidth * width;
    }

    void scrollUp()
    {
        if (scrollOffset > 0)
        {
            scrollOffset--;
        }
        if (scrollOffset < 0)
        {
            scrollOffset = 0;
        }
    }

    void scrollDown()
    {
        int maxScrollOffset = data.size() - visibleRowCount;
        if (scrollOffset < maxScrollOffset)
        {
            scrollOffset++;
        }
    }

    void scroll(int mouseX, int mouseY, int wheel)
    {
        if (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height)
        {
            if (wheel > 0)
            {
                scrollUp();
            }
            else if (wheel < 0) {
                scrollDown();
            }
        }
    }

    void handleMouseClick(int mouseX, int mouseY)
    {
        if (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height)
        {
            int clickedRow = (mouseY - y) / rowHeight + scrollOffset;

            if (clickedRow >= 0 && clickedRow < static_cast<int>(data.size()))
            {
                selectedRow = clickedRow;
            }
            else
            {
                selectedRow = -1;
            }
        }
    }

    void draw()
    {
        setbkmode(1);
        // 绘制表格区域
        setfillcolor(WHITE);
        solidrectangle(x, y, x + width, y + height);
        setlinecolor(BLACK);
        settextstyle(12, 0, _T("宋体"));

        // 计算需要绘制的行数
        int rowCount = min(visibleRowCount, static_cast<int>(data.size()));

        // 绘制表头
        int headerY = y;
        int columnX = x;
        for (int j = 0; j < data[0].size(); ++j) {
            int columnWidth = columnWidths[j];
            rectangle(columnX, headerY, columnX + columnWidth, headerY + rowHeight);
            int textX = columnX + (columnWidth - textwidth(data[0][j].c_str())) / 2;
            int textY = headerY + (rowHeight - textheight(_T("宋体"))) / 2;
            outtextxy(textX, textY, data[0][j].c_str());
            columnX += columnWidth;
        }

        // 绘制表格内容
        for (int i = 1; i < rowCount; ++i) {
            int rowY = y + i * rowHeight;
            int dataIndex = i + scrollOffset;
            columnX = x;
            for (int j = 0; j < data[dataIndex].size(); ++j) {
                int columnWidth = columnWidths[j];
                bool isSelectedRow = (dataIndex == selectedRow);
                if (isSelectedRow) {
                    setfillcolor(LIGHTBLUE);
                    settextcolor(RED);
                }
                else {
                    setfillcolor(WHITE);
                    settextcolor(BLACK);
                }
                fillrectangle(columnX, rowY, columnX + columnWidth, rowY + rowHeight);
                int textX = columnX + (columnWidth - textwidth(data[dataIndex][j].c_str())) / 2;
                int textY = rowY + (rowHeight - textheight(_T("宋体"))) / 2;
                outtextxy(textX, textY, data[dataIndex][j].c_str());
                columnX += columnWidth;
            }
        }
        // 绘制滚动条背景
        int scrollbarX = x + width;
        setfillcolor(LIGHTGRAY);
        solidrectangle(scrollbarX, y, scrollbarX + scrollbarWidth, y + height);

        // 计算滑块位置和大小
        int handleX = scrollbarX;
        int handleWidth = scrollbarWidth;
        int maxHandleY = height - handleHeight;
        handleY = maxHandleY * double(scrollOffset) / (data.size() - visibleRowCount);

        // 绘制滑块
        setfillcolor(DARKGRAY);
        solidrectangle(handleX, y + handleY, handleX + handleWidth, y + handleY + handleHeight);
    }
};


class Widget
{
private:
    int width;
    int height;
    int currentIndex;
    vector<IMAGE*> pages;
    vector<vector<TableWidget*>> tables;

    void addPage(IMAGE* page)
    {
        pages.push_back(page);
        tables.push_back({});
    }

    void addTable(int index, TableWidget* button)
    {
        if (index >= 0 && index < tables.size())
        {
            tables[index].push_back(button);
        }
    }

    void mouseClick(int mouseX, int mouseY)
    {
        if (currentIndex >= 0 && currentIndex < tables.size())
        {
            for (TableWidget* table : tables[currentIndex])
            {
                table->handleMouseClick(mouseX, mouseY);
            }
        }
    }

    void mouseWheel(int mouseX, int mouseY, int wheel)
    {

        if (currentIndex >= 0 && currentIndex < tables.size())
        {
            for (TableWidget* table : tables[currentIndex])
            {
                table->scroll(mouseX, mouseY, wheel);
            }
        }
    }

    void draw()
    {
        if (currentIndex >= 0 && currentIndex < tables.size())
        {
            putimage(0, 0, pages[currentIndex]);
            for (TableWidget* table : tables[currentIndex])
            {
                table->draw();
            }
        }
    }

public:
    Widget(int width, int height)
        :width(width), height(height), currentIndex(-1)
    {
    }
    ~Widget() {}

    void init()
    {
        initgraph(width, height);

        // 创建页面1
        IMAGE* page1 = new IMAGE(width, height);
        setfillcolor(RGB(240, 240, 240));
        solidrectangle(0, 0, width, height);
        getimage(page1, 0, 0, width, height);
        addPage(page1);

        TableWidget* table1 = new TableWidget(100, 100, 400, 300, 12);
        table1->setData({ {L"学号",L"姓名",L"性别",L"成绩"},
            {L"2023001",L"张三",L"男",L"60"},
            {L"2023002",L"李四",L"男",L"50"},
            {L"2023003",L"王五",L"男",L"90"},
            {L"2023004",L"小红",L"女",L"80"},
            {L"2023005",L"小黑",L"男",L"70"},
            {L"2023006",L"小白",L"男",L"60"},
            {L"2023007",L"李红",L"女",L"75"},
            {L"2023008",L"王五",L"男",L"60"},
            {L"2023009",L"王五",L"女",L"40"},
            {L"2023010",L"王五",L"男",L"30"},
            {L"2023011",L"王五",L"男",L"20"},
            {L"2023012",L"王五",L"女",L"10"},
            {L"2023013",L"王五",L"男",L"80"},
            {L"2023014",L"王五",L"女",L"90"},
            {L"2023015",L"王五",L"女",L"100"},
            });
        addTable(0, table1);

        currentIndex = 0;
    }

    void run()
    {
        ExMessage msg;

        BeginBatchDraw();
        while (true)
        {
            if (peekmessage(&msg))
            {
                int mouseX = msg.x;
                int mouseY = msg.y;
                switch (msg.message)
                {
                case WM_LBUTTONDOWN:
                    mouseClick(mouseX, mouseY);
                    break;
                case WM_MOUSEWHEEL:
                    mouseWheel(mouseX, mouseY,msg.wheel);
                    break;
                }
            }
            draw();
            FlushBatchDraw();
            Sleep(10);
        }
        EndBatchDraw();
    }

    void close()
    {
        closegraph();
    }
};

int main()
{
    Widget widget(800, 600);
    widget.init();
    widget.run();
    widget.close();
    return 0;
}
  • 6
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会修bug的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值