initial commit
This commit is contained in:
344
src/Button.cpp
Normal file
344
src/Button.cpp
Normal file
@@ -0,0 +1,344 @@
|
||||
#include "button.h"
|
||||
|
||||
button::button(int x, int y, int width, int height, const std::string text, StellarX::buttonMode mode, StellarX::controlShape shape)
|
||||
: Control(x, y, width, height)
|
||||
{
|
||||
initButton(text, mode, shape, RGB(202, 255, 255), RGB(171, 196, 220), RGB(255, 255, 0));
|
||||
}
|
||||
|
||||
button::button(int x, int y, int width, int height, const std::string text, COLORREF ct, COLORREF cf, StellarX::buttonMode mode, StellarX::controlShape shape)
|
||||
: Control(x, y, width, height)
|
||||
{
|
||||
initButton(text, mode, shape, ct, cf, RGB(255, 255, 0));
|
||||
}
|
||||
|
||||
button::button(int x, int y, int width, int height, const std::string text, COLORREF ct, COLORREF cf, COLORREF ch, StellarX::buttonMode mode, StellarX::controlShape shape)
|
||||
: Control(x, y, width, height)
|
||||
{
|
||||
initButton(text, mode, shape, ct, cf, ch);
|
||||
}
|
||||
|
||||
void button::initButton(const std::string text, StellarX::buttonMode mode, StellarX::controlShape shape, COLORREF ct, COLORREF cf, COLORREF ch)
|
||||
{
|
||||
this->text = text;
|
||||
this->mode = mode;
|
||||
this->shape = shape;
|
||||
this->buttonTrueColor = ct;
|
||||
this->buttonFalseColor = cf;
|
||||
this->buttonHoverColor = ch;
|
||||
this->click = false;
|
||||
this->hover = false;
|
||||
}
|
||||
|
||||
|
||||
button::~button()
|
||||
{
|
||||
if (buttonFileIMAGE)
|
||||
delete buttonFileIMAGE;
|
||||
buttonFileIMAGE = nullptr;
|
||||
}
|
||||
|
||||
void button::draw()
|
||||
{
|
||||
if (dirty)
|
||||
{
|
||||
//保存当前样式和颜色
|
||||
saveStyle();
|
||||
|
||||
if (StellarX::buttonMode::DISABLED == mode) //设置禁用按钮色
|
||||
{
|
||||
setfillcolor(RGB(96, 96, 96));
|
||||
textStyle.bStrikeOut = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hover)
|
||||
setfillcolor(buttonHoverColor);
|
||||
else
|
||||
setfillcolor(click ? buttonTrueColor : buttonFalseColor);
|
||||
}
|
||||
|
||||
|
||||
//设置字体背景色透明
|
||||
setbkmode(TRANSPARENT);
|
||||
//边框颜色
|
||||
setlinecolor(buttonBorderColor);
|
||||
if(this->textStyle !=oldStyle)
|
||||
{
|
||||
//设置字体颜色
|
||||
settextcolor(textStyle.color);
|
||||
|
||||
//设置字体样式
|
||||
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
|
||||
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
|
||||
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut); //设置字体样式
|
||||
}
|
||||
//设置按钮填充模式
|
||||
setfillstyle(buttonFillMode, (int)buttonFillIma, buttonFileIMAGE);
|
||||
|
||||
//获取字符串像素高度和宽度
|
||||
if((this->oldtext_width!= this->text_width|| this->oldtext_height!= this->text_height)
|
||||
||(-1 == oldtext_width &&oldtext_height == -1))
|
||||
{
|
||||
this->oldtext_width = this->text_width = textwidth(LPCTSTR(this->text.c_str()));;
|
||||
this->oldtext_height = this->text_height = textheight(LPCTSTR(this->text.c_str()));;
|
||||
}
|
||||
|
||||
|
||||
//根据按钮形状绘制
|
||||
switch (shape)
|
||||
{
|
||||
case StellarX::controlShape::RECTANGLE:
|
||||
fillrectangle(x, y, width, height);//有边框填充矩形
|
||||
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::B_RECTANGLE:
|
||||
solidrectangle(x, y, width, height);//无边框填充矩形
|
||||
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::ROUND_RECTANGLE:
|
||||
fillroundrect(x, y, width, height, ROUND_RECTANGLEwidth, ROUND_RECTANGLEheight);//有边框填充圆角矩形
|
||||
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::B_ROUND_RECTANGLE:
|
||||
solidroundrect(x, y, width, height, ROUND_RECTANGLEwidth, ROUND_RECTANGLEheight);//无边框填充圆角矩形
|
||||
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::CIRCLE:
|
||||
fillcircle(x, y, (width - x) / 2);//有边框填充圆形
|
||||
outtextxy(x - text_width / 2, y - text_height / 2, LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::B_CIRCLE:
|
||||
solidcircle(x, y, (width - x) / 2);//无边框填充圆形
|
||||
outtextxy(x - text_width / 2, y - text_height / 2, LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::ELLIPSE:
|
||||
fillellipse(x, y, width, height);//有边框填充椭圆
|
||||
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::B_ELLIPSE:
|
||||
solidellipse(x, y, width, height);//无边框填充椭圆
|
||||
outtextxy((x + (width - x - text_width) / 2), (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
restoreStyle();//恢复默认字体样式和颜色
|
||||
|
||||
dirty = false; //标记按钮不需要重绘
|
||||
}
|
||||
|
||||
}
|
||||
// 处理鼠标事件,检测点击和悬停状态
|
||||
// 根据按钮模式和形状进行不同的处理
|
||||
void button::handleEvent(const ExMessage& msg)
|
||||
{
|
||||
bool oldHover = hover;
|
||||
bool oldClick = click;
|
||||
// 检测悬停状态(根据不同形状)
|
||||
switch (shape)
|
||||
{
|
||||
case StellarX::controlShape::RECTANGLE:
|
||||
case StellarX::controlShape::B_RECTANGLE:
|
||||
case StellarX::controlShape::ROUND_RECTANGLE:
|
||||
case StellarX::controlShape::B_ROUND_RECTANGLE:
|
||||
hover = (msg.x > x && msg.x < width && msg.y > y && msg.y < height);//判断鼠标是否在矩形按钮内
|
||||
break;
|
||||
case StellarX::controlShape::CIRCLE:
|
||||
case StellarX::controlShape::B_CIRCLE:
|
||||
hover = isMouseInCircle(msg.x, msg.y, x, y, (width - x) / 2);//判断鼠标是否在圆形按钮内
|
||||
break;
|
||||
case StellarX::controlShape::ELLIPSE:
|
||||
case StellarX::controlShape::B_ELLIPSE:
|
||||
hover = isMouseInEllipse(msg.x, msg.y, x, y, width, height);//判断鼠标是否在椭圆按钮内
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (hover && msg.message == WM_LBUTTONUP)
|
||||
{
|
||||
if (mode == StellarX::buttonMode::NORMAL) // 普通按钮 NORMAL
|
||||
{
|
||||
click = true;
|
||||
if (onClickCallback) onClickCallback();
|
||||
// 刷新消息队列,避免重复处理
|
||||
flushmessage(EX_MOUSE | EX_KEY);
|
||||
}
|
||||
else if (mode == StellarX::buttonMode::TOGGLE) // 切换状态 Toggle
|
||||
{
|
||||
click = !click;
|
||||
if (click && onToggleOnCallback) onToggleOnCallback();
|
||||
else if (!click && onToggleOffCallback) onToggleOffCallback();
|
||||
flushmessage(EX_MOUSE | EX_KEY);
|
||||
}
|
||||
else if (mode == StellarX::buttonMode::DISABLED) // 禁用状态 Disabled
|
||||
flushmessage(EX_MOUSE | EX_KEY);
|
||||
}
|
||||
if (hover != oldHover || click != oldClick)
|
||||
dirty = true; // 标记按钮需要重绘
|
||||
|
||||
if (dirty)
|
||||
draw();
|
||||
|
||||
if (StellarX::buttonMode::NORMAL == mode)
|
||||
if (isClicked())
|
||||
click = false;
|
||||
}
|
||||
|
||||
void button::setOnClickListener(const std::function<void()>&& callback)
|
||||
{
|
||||
this->onClickCallback = callback;
|
||||
}
|
||||
|
||||
void button::setOnToggleOnListener(const std::function<void()>&& callback)
|
||||
{
|
||||
this->onToggleOnCallback = callback;
|
||||
}
|
||||
void button::setOnToggleOffListener(const std::function<void()>&& callback)
|
||||
{
|
||||
this->onToggleOffCallback = callback;
|
||||
}
|
||||
|
||||
void button::setbuttonMode(StellarX::buttonMode mode)
|
||||
{
|
||||
//取值范围参考 buttMode的枚举注释
|
||||
this->mode = mode;
|
||||
}
|
||||
|
||||
int button::setROUND_RECTANGLEwidth(int width)
|
||||
{
|
||||
return ROUND_RECTANGLEwidth = width;
|
||||
}
|
||||
|
||||
int button::setROUND_RECTANGLEheight(int height)
|
||||
{
|
||||
return ROUND_RECTANGLEheight = height;
|
||||
}
|
||||
|
||||
bool button::isClicked() const
|
||||
{
|
||||
return this->click;
|
||||
}
|
||||
|
||||
void button::setFillMode(int mode)
|
||||
{
|
||||
buttonFillMode = mode;
|
||||
}
|
||||
|
||||
void button::setFillIma(StellarX::fillStyle ima)
|
||||
{
|
||||
buttonFillIma = ima;
|
||||
}
|
||||
|
||||
void button::setFillIma(std::string imaNAme)
|
||||
{
|
||||
buttonFileIMAGE = new IMAGE;
|
||||
loadimage(buttonFileIMAGE, imaNAme.c_str(),width-x,height-y);
|
||||
}
|
||||
|
||||
|
||||
void button::setbuttonBorder(COLORREF Border)
|
||||
{
|
||||
buttonBorderColor = Border;
|
||||
}
|
||||
|
||||
void button::setbuttonText(const char* text)
|
||||
{
|
||||
this->text = std::string(text);
|
||||
this->text_width = textwidth(LPCTSTR(this->text.c_str()));
|
||||
this->text_height = textheight(LPCTSTR(this->text.c_str()));
|
||||
}
|
||||
|
||||
void button::setbuttonText(std::string text)
|
||||
{
|
||||
this->text = text;
|
||||
this->text_width = textwidth(LPCTSTR(this->text.c_str()));
|
||||
this->text_height = textheight(LPCTSTR(this->text.c_str()));
|
||||
this->dirty = true; // 标记需要重绘
|
||||
}
|
||||
|
||||
void button::setbuttonShape(StellarX::controlShape shape)
|
||||
{
|
||||
this->shape = shape;
|
||||
}
|
||||
|
||||
|
||||
std::string button::getbuttonText() const
|
||||
{
|
||||
return this->text;
|
||||
}
|
||||
|
||||
const char* button::getbuttonText_c() const
|
||||
{
|
||||
return this->text.c_str();
|
||||
}
|
||||
|
||||
StellarX::buttonMode button::getbuttonMode() const
|
||||
{
|
||||
return this->mode;
|
||||
}
|
||||
|
||||
StellarX::controlShape button::getbuttonShape() const
|
||||
{
|
||||
return this->shape;
|
||||
}
|
||||
|
||||
int button::getFillMode() const
|
||||
{
|
||||
return this->buttonFillMode;
|
||||
}
|
||||
|
||||
StellarX::fillStyle button::getFillIma() const
|
||||
{
|
||||
return this->buttonFillIma;
|
||||
}
|
||||
|
||||
IMAGE* button::getFillImaImage() const
|
||||
{
|
||||
return this->buttonFileIMAGE;
|
||||
}
|
||||
|
||||
COLORREF button::getbuttonBorder() const
|
||||
{
|
||||
return this->buttonBorderColor;
|
||||
}
|
||||
|
||||
COLORREF button::getbuttonTxtColor() const
|
||||
{
|
||||
return this->textStyle.color;
|
||||
}
|
||||
|
||||
StellarX::controlText button::getbuttonTextStyle() const
|
||||
{
|
||||
return this->textStyle;
|
||||
}
|
||||
|
||||
|
||||
bool button::isMouseInCircle(int mouseX, int mouseY, int x, int y, int radius)
|
||||
{
|
||||
double dis = sqrt(pow(mouseX - x, 2) + pow(mouseY - y, 2));
|
||||
if (dis <= radius)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool button::isMouseInEllipse(int mouseX, int mouseY, int x, int y, int width, int height)
|
||||
{
|
||||
int centerX = (x + width) / 2;
|
||||
int centerY = (y + height) / 2;
|
||||
int majorAxis = (width - x) / 2;
|
||||
int minorAxis = (height - y) / 2;
|
||||
double dx = mouseX - centerX;
|
||||
double dy = mouseY - centerY;
|
||||
double normalizedDistance = (dx * dx) / (majorAxis * majorAxis) + (dy * dy) / (minorAxis * minorAxis);
|
||||
|
||||
// 判断鼠标是否在椭圆内
|
||||
if (normalizedDistance <= 1.0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
95
src/Canvas.cpp
Normal file
95
src/Canvas.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "Canvas.h"
|
||||
|
||||
Canvas::Canvas(int x, int y, int width, int height)
|
||||
:Control(x, y, width, height) {}
|
||||
|
||||
void Canvas::draw()
|
||||
{
|
||||
saveStyle();
|
||||
|
||||
setlinecolor(canvasBorderClor);//设置线色
|
||||
setfillcolor(canvasBkClor);//设置填充色
|
||||
setfillstyle((int)canvasFillMode);//设置填充模式
|
||||
setlinestyle((int)canvasLineStyle, canvaslinewidth);
|
||||
|
||||
//根据画布形状绘制
|
||||
switch (shape)
|
||||
{
|
||||
case StellarX::controlShape::RECTANGLE:
|
||||
fillrectangle(x, y, width, height);//有边框填充矩形
|
||||
break;
|
||||
case StellarX::controlShape::B_RECTANGLE:
|
||||
solidrectangle(x, y, width, height);//无边框填充矩形
|
||||
break;
|
||||
case StellarX::controlShape::ROUND_RECTANGLE:
|
||||
fillroundrect(x, y, width, height, 20, 20);//有边框填充圆角矩形
|
||||
break;
|
||||
case StellarX::controlShape::B_ROUND_RECTANGLE:
|
||||
solidroundrect(x, y, width, height, 20, 20);//无边框填充圆角矩形
|
||||
break;
|
||||
}
|
||||
// 绘制所有子控件
|
||||
for (auto& control : controls)
|
||||
control->draw();
|
||||
|
||||
|
||||
restoreStyle();
|
||||
}
|
||||
|
||||
void Canvas::handleEvent(const ExMessage& msg)
|
||||
{
|
||||
for (auto& control : controls) {
|
||||
control->handleEvent(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::addControl(std::unique_ptr<Control> control)
|
||||
{
|
||||
controls.push_back(std::move(control));
|
||||
}
|
||||
|
||||
void Canvas::setShape(StellarX::controlShape shape)
|
||||
{
|
||||
switch (shape)
|
||||
{
|
||||
case StellarX::controlShape::RECTANGLE:
|
||||
case StellarX::controlShape::B_RECTANGLE:
|
||||
case StellarX::controlShape::ROUND_RECTANGLE:
|
||||
case StellarX::controlShape::B_ROUND_RECTANGLE:
|
||||
this->shape = shape;
|
||||
break;
|
||||
case StellarX::controlShape::CIRCLE:
|
||||
case StellarX::controlShape::B_CIRCLE:
|
||||
case StellarX::controlShape::ELLIPSE:
|
||||
case StellarX::controlShape::B_ELLIPSE:
|
||||
this->shape = StellarX::controlShape::RECTANGLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::setcanvasfillMode(StellarX::fillMode mode)
|
||||
{
|
||||
this->canvasFillMode = mode;
|
||||
}
|
||||
|
||||
void Canvas::setBorderColor(COLORREF color)
|
||||
{
|
||||
this->canvasBorderClor = color;
|
||||
}
|
||||
|
||||
void Canvas::setCanvasBkColor(COLORREF color)
|
||||
{
|
||||
this->canvasBkClor = color;
|
||||
}
|
||||
|
||||
void Canvas::setcanvasLineStyle(StellarX::lineStyle style)
|
||||
{
|
||||
this->canvasLineStyle = style;
|
||||
}
|
||||
|
||||
|
||||
void Canvas::setlinewidth(int width)
|
||||
{
|
||||
this->canvaslinewidth = width;
|
||||
}
|
||||
|
||||
64
src/Control.cpp
Normal file
64
src/Control.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "Control.h"
|
||||
|
||||
StellarX::controlText& StellarX::controlText::operator=(const controlText& text)
|
||||
{
|
||||
{
|
||||
nHeight = text.nHeight;
|
||||
nWidth = text.nWidth;
|
||||
lpszFace = text.lpszFace;
|
||||
color = text.color;
|
||||
nEscapement = text.nEscapement;
|
||||
nOrientation = text.nOrientation;
|
||||
nWeight = text.nWeight;
|
||||
bItalic = text.bItalic;
|
||||
bUnderline = text.bUnderline;
|
||||
bStrikeOut = text.bStrikeOut;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
bool StellarX::controlText::operator!=(const controlText& text)
|
||||
{
|
||||
if(nHeight != text.nHeight)
|
||||
return true;
|
||||
else if (nWidth != text.nWidth)
|
||||
return true;
|
||||
else if (lpszFace != text.lpszFace)
|
||||
return true;
|
||||
else if (color != text.color)
|
||||
return true;
|
||||
else if (nEscapement != text.nEscapement)
|
||||
return true;
|
||||
else if (nOrientation != text.nOrientation)
|
||||
return true;
|
||||
else if (nWeight != text.nWeight)
|
||||
return true;
|
||||
else if (bItalic != text.bItalic)
|
||||
return true;
|
||||
else if (bUnderline != text.bUnderline)
|
||||
return true;
|
||||
else if (bStrikeOut != text.bStrikeOut)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
// 保存当前的绘图状态(字体、颜色、线型等)
|
||||
// 在控件绘制前调用,确保不会影响全局绘图状态
|
||||
void Control::saveStyle()
|
||||
{
|
||||
gettextstyle(¤tFont); // 获取当前字体样式
|
||||
currentColor = gettextcolor(); // 获取当前字体颜色
|
||||
currentBorderColor = getlinecolor(); //保存当前边框颜色
|
||||
getlinestyle(currentLineStyle); //保存当前线型
|
||||
currentBkColor = getfillcolor(); //保存当前填充色
|
||||
}
|
||||
// 恢复之前保存的绘图状态
|
||||
// 在控件绘制完成后调用,恢复全局绘图状态
|
||||
void Control::restoreStyle()
|
||||
{
|
||||
settextstyle(¤tFont); // 恢复默认字体样式
|
||||
settextcolor(currentColor); // 恢复默认字体颜色
|
||||
setfillcolor(currentBkColor);
|
||||
setlinestyle(currentLineStyle);
|
||||
setlinecolor(currentBorderColor);
|
||||
setfillstyle(BS_SOLID);//恢复填充
|
||||
}
|
||||
55
src/label.cpp
Normal file
55
src/label.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "label.h"
|
||||
|
||||
label::label()
|
||||
:Control(0, 0, 0, 0)
|
||||
{
|
||||
this->text = "默认标签";
|
||||
textColor = RGB(0,0,0);
|
||||
textBkColor = RGB(255, 255, 255);; //默认白色背景
|
||||
}
|
||||
|
||||
label::label(int x, int y, std::string text, COLORREF textcolor, COLORREF bkColor)
|
||||
:Control(x, y, 0, 0)
|
||||
{
|
||||
this->text = text;
|
||||
textColor = textcolor;
|
||||
textBkColor = bkColor; //默认白色背景
|
||||
}
|
||||
|
||||
void label::draw()
|
||||
{
|
||||
saveStyle();
|
||||
if (textBkDisap)
|
||||
setbkmode(TRANSPARENT); //设置背景透明
|
||||
else
|
||||
{
|
||||
setbkmode(OPAQUE); //设置背景不透明
|
||||
setbkcolor(textBkColor); //设置背景颜色
|
||||
}
|
||||
settextcolor(textColor);
|
||||
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
|
||||
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
|
||||
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut); //设置字体样式
|
||||
outtextxy(x,y, LPCTSTR(text.c_str()));
|
||||
restoreStyle();
|
||||
}
|
||||
|
||||
void label::setTxtdisap(bool key)
|
||||
{
|
||||
textBkDisap = key;
|
||||
}
|
||||
|
||||
void label::setTxtColor(COLORREF color)
|
||||
{
|
||||
textColor = color;
|
||||
}
|
||||
|
||||
void label::setTxtBkColor(COLORREF color)
|
||||
{
|
||||
textBkColor = color;
|
||||
}
|
||||
|
||||
void label::setText(std::string text)
|
||||
{
|
||||
this->text = text;
|
||||
}
|
||||
403
src/table.cpp
Normal file
403
src/table.cpp
Normal file
@@ -0,0 +1,403 @@
|
||||
#include "table.h"
|
||||
// 绘制表格的当前页
|
||||
// 使用双循环绘制行和列,考虑分页偏移
|
||||
void table::drawTable()
|
||||
{
|
||||
dX = x;
|
||||
dY = uY;
|
||||
uY = dY + lineHeights.at(0) + 10;
|
||||
|
||||
for (int i = (currentPage * rowsPerPage - rowsPerPage); i < (currentPage*rowsPerPage) && i < data.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < data[i].size(); j++)
|
||||
{
|
||||
uX = dX + colWidths.at(j) + 20;
|
||||
fillrectangle(dX, dY, uX, uY);
|
||||
outtextxy(dX + 10, dY + 5, LPCTSTR(data[i][j].c_str()));
|
||||
dX += this->colWidths.at(j) + 20;
|
||||
}
|
||||
dX = x;
|
||||
dY = uY;
|
||||
uY = dY + lineHeights.at(0) + 10;
|
||||
|
||||
}
|
||||
uY = y + lineHeights.at(0) + 10;
|
||||
}
|
||||
|
||||
void table::drawHeader()
|
||||
{
|
||||
|
||||
uY = dY + lineHeights.at(0) + 10;
|
||||
for(int i = 0; i < headers.size(); i++)
|
||||
{
|
||||
uX = dX + colWidths.at(i) + 20;
|
||||
fillrectangle(dX, dY, uX, uY);
|
||||
outtextxy(dX + 10, dY + 5, LPCTSTR(headers[i].c_str()));
|
||||
dX += this->colWidths.at(i) + 20;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
// 初始化文本宽度和高度计算
|
||||
// 遍历所有数据和表头,计算每列的最大宽度和行高
|
||||
// 此方法在数据变更时自动调用
|
||||
void table::initTextWaH()
|
||||
{
|
||||
this->colWidths.resize(this->headers.size());
|
||||
this->lineHeights.resize(this->headers.size());
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
//计算数据尺寸
|
||||
for (int i = 0; i < data.size(); i++)
|
||||
{
|
||||
for (int j = 0; j < data[i].size(); j++)
|
||||
{
|
||||
width = textwidth(LPCTSTR(data[i][j].c_str()));
|
||||
height = textheight(LPCTSTR(data[i][j].c_str()));
|
||||
if (width > this->colWidths.at(j))
|
||||
this->colWidths.at(j) = width;
|
||||
if (height > this->lineHeights[j])
|
||||
this->lineHeights.at(j) = height;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < this->headers.size(); i++)
|
||||
{
|
||||
width = textwidth(LPCTSTR(headers[i].c_str()));
|
||||
height = textheight(LPCTSTR(headers[i].c_str()));
|
||||
if (width > this->colWidths.at(i))
|
||||
this->colWidths.at(i) = width;
|
||||
if (height > this->lineHeights[i])
|
||||
this->lineHeights.at(i) = height;
|
||||
}
|
||||
|
||||
// 计算表格总宽度和高度
|
||||
this->width = 0;
|
||||
for (int i = 0; i < colWidths.size(); i++)
|
||||
this->width += colWidths.at(i) + 20;
|
||||
LINESTYLE currentStyle;
|
||||
|
||||
this->width += tableBorderWidth;
|
||||
|
||||
this->height = lineHeights.at(0) * (rowsPerPage + 1) + rowsPerPage * 10+20 ; // 表头+数据行+页码区域
|
||||
|
||||
// 如果背景图像不存在或尺寸不匹配,创建或重新创建
|
||||
if (saveBkImage == nullptr) {
|
||||
saveBkImage = new IMAGE(width, height);
|
||||
}
|
||||
else if (saveBkImage->getwidth() != width || saveBkImage->getheight() != height) {
|
||||
delete saveBkImage;
|
||||
saveBkImage = new IMAGE(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void table::initButton()
|
||||
{
|
||||
int x1, x2;
|
||||
int y1, y2;
|
||||
x1 = pX - 70;
|
||||
x2 = pX + textwidth(LPCTSTR(pageNumtext.c_str())) + 10;
|
||||
y1 = y2 = pY;
|
||||
this->prevButton = new button(x1, y1, 60, textheight(LPCTSTR(pageNumtext.c_str())), "上一页", RGB(0, 0, 0), RGB(255, 255, 255));
|
||||
this->nextButton = new button(x2, y2, 60, textheight(LPCTSTR(pageNumtext.c_str())), "下一页", RGB(0, 0, 0), RGB(255, 255, 255));
|
||||
prevButton->setOnClickListener([this]()
|
||||
{if (this->currentPage > 1)
|
||||
{
|
||||
this->currentPage--;
|
||||
this->dirty = true;
|
||||
this->draw();
|
||||
} });
|
||||
|
||||
nextButton->setOnClickListener([this]()
|
||||
{if (this->currentPage < (this->totalPages))
|
||||
{
|
||||
this->currentPage++;
|
||||
this->dirty = true;
|
||||
this->draw();
|
||||
}});
|
||||
}
|
||||
|
||||
void table::initPageNum()
|
||||
{
|
||||
if (0 == pY)
|
||||
pY = uY + lineHeights.at(0) * rowsPerPage + rowsPerPage * 10+10;
|
||||
for (int i = 0; i < colWidths.size(); i++)
|
||||
this->pX += colWidths.at(i) + 20;
|
||||
this->pX -= textwidth(LPCTSTR(pageNumtext.c_str()));
|
||||
this->pX /= 2;
|
||||
this->pX += x;
|
||||
this->pageNum = new label(this->pX, pY, pageNumtext);
|
||||
//pageNum->setTxtdisap(true);
|
||||
pageNum->textStyle = this->textStyle;
|
||||
}
|
||||
|
||||
void table::drawPageNum()
|
||||
{
|
||||
if (nullptr == pageNum)
|
||||
initPageNum();
|
||||
pageNumtext = std::to_string(currentPage);
|
||||
pageNumtext += "页/第";
|
||||
pageNumtext += std::to_string(totalPages);
|
||||
pageNumtext += "页";
|
||||
pageNum->setText(pageNumtext);
|
||||
pageNum->draw();
|
||||
|
||||
}
|
||||
|
||||
void table::drawButton()
|
||||
{
|
||||
if (nullptr == prevButton || nullptr == nextButton)
|
||||
initButton();
|
||||
prevButton->draw();
|
||||
nextButton->draw();
|
||||
|
||||
}
|
||||
|
||||
table::table(int x, int y)
|
||||
:Control(x, y, 0,0)
|
||||
{
|
||||
//this->saveBkImage = new IMAGE(this->width,this->height);
|
||||
}
|
||||
|
||||
table::~table()
|
||||
{
|
||||
if (this->prevButton)
|
||||
delete this->prevButton;
|
||||
if (this->nextButton)
|
||||
delete this->nextButton;
|
||||
if (this->pageNum)
|
||||
delete this->pageNum;
|
||||
if (this->saveBkImage)
|
||||
delete this->saveBkImage;
|
||||
this->prevButton = nullptr;
|
||||
this->nextButton = nullptr;
|
||||
this->pageNum = nullptr;
|
||||
this->saveBkImage = nullptr;
|
||||
}
|
||||
|
||||
void table::draw()
|
||||
{
|
||||
if (this->dirty)
|
||||
{
|
||||
// 先保存当前绘图状态
|
||||
saveStyle();
|
||||
|
||||
// 设置表格样式
|
||||
setfillcolor(tableBkClor);
|
||||
setlinecolor(tableBorderClor);
|
||||
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
|
||||
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
|
||||
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
|
||||
settextcolor(textStyle.color);
|
||||
setlinestyle((int)tableLineStyle, tableBorderWidth);
|
||||
setfillstyle((int)tableFillMode);
|
||||
setbkmode(TRANSPARENT);
|
||||
|
||||
// 是否需要计算单元格尺寸
|
||||
if (isNeedCellSize)
|
||||
{
|
||||
initTextWaH();
|
||||
isNeedCellSize = false;
|
||||
}
|
||||
|
||||
// 在绘制表格之前捕获背景
|
||||
// 只有在第一次绘制或者尺寸变化时才需要重新捕获背景
|
||||
static bool firstDraw = true;
|
||||
if (firstDraw || isNeedDrawHeaders) {
|
||||
// 确保在绘制任何表格内容之前捕获背景
|
||||
if (saveBkImage) {
|
||||
// 临时恢复样式,确保捕获正确的背景
|
||||
restoreStyle();
|
||||
if(tableBorderWidth>1)
|
||||
getimage(saveBkImage, this->x- tableBorderWidth, this->y- tableBorderWidth, this->width+ tableBorderWidth, this->height+ tableBorderWidth);
|
||||
else
|
||||
getimage(saveBkImage, this->x, this->y, this->width, this->height);
|
||||
saveStyle(); // 重新保存样式
|
||||
|
||||
// 重新设置表格样式
|
||||
setfillcolor(tableBkClor);
|
||||
setlinecolor(tableBorderClor);
|
||||
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
|
||||
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
|
||||
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
|
||||
settextcolor(textStyle.color);
|
||||
setlinestyle((int)tableLineStyle, tableBorderWidth);
|
||||
setfillstyle((int)tableFillMode);
|
||||
setbkmode(TRANSPARENT);
|
||||
}
|
||||
firstDraw = false;
|
||||
}
|
||||
|
||||
// 恢复背景(清除旧内容)
|
||||
if (saveBkImage) {
|
||||
if (tableBorderWidth > 1)
|
||||
putimage(this->x - tableBorderWidth, this->y - tableBorderWidth, saveBkImage);
|
||||
else
|
||||
putimage(this->x,this->y,this->saveBkImage);
|
||||
}
|
||||
|
||||
// 绘制表头
|
||||
|
||||
dX = x;
|
||||
dY = y;
|
||||
drawHeader();
|
||||
this->isNeedDrawHeaders = false;
|
||||
|
||||
|
||||
// 绘制当前页
|
||||
drawTable();
|
||||
|
||||
// 绘制页码标签
|
||||
drawPageNum();
|
||||
|
||||
// 绘制翻页按钮
|
||||
if (this->isShowPageButton)
|
||||
drawButton();
|
||||
|
||||
// 恢复绘图状态
|
||||
restoreStyle();
|
||||
dirty = false; // 标记不需要重绘
|
||||
}
|
||||
}
|
||||
|
||||
void table::handleEvent(const ExMessage& msg)
|
||||
{
|
||||
if(!this->isShowPageButton)
|
||||
return;
|
||||
else
|
||||
{
|
||||
prevButton->handleEvent(msg);
|
||||
nextButton->handleEvent(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void table::setHeaders(std::initializer_list<std::string> headers)
|
||||
{
|
||||
this->headers.clear();
|
||||
for (auto lis : headers)
|
||||
this->headers.push_back(lis);
|
||||
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
|
||||
isNeedDrawHeaders = true; // 标记需要重新绘制表头
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void table::setData(const std::vector<std::string>& data)
|
||||
{
|
||||
this->data.push_back(data);
|
||||
totalPages = (this->data.size() + rowsPerPage - 1) / rowsPerPage;
|
||||
if (totalPages < 1)
|
||||
totalPages = 1;
|
||||
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void table::setData(const std::initializer_list<std::vector<std::string>>& data)
|
||||
{
|
||||
for (auto lis : data)
|
||||
this->data.push_back(lis);
|
||||
totalPages = (this->data.size() + rowsPerPage - 1) / rowsPerPage;
|
||||
if (totalPages < 1)
|
||||
totalPages = 1;
|
||||
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void table::setRowsPerPage(int rows)
|
||||
{
|
||||
this->rowsPerPage = rows;
|
||||
totalPages = (data.size() + rowsPerPage - 1) / rowsPerPage;
|
||||
if (totalPages < 1)
|
||||
totalPages = 1;
|
||||
isNeedCellSize = true; // 标记需要重新计算单元格尺寸
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void table::showPageButton(bool isShow)
|
||||
{
|
||||
this->isShowPageButton = isShow;
|
||||
}
|
||||
|
||||
void table::settableBorder(COLORREF color)
|
||||
{
|
||||
this->tableBorderClor = color;
|
||||
}
|
||||
|
||||
void table::settableBk(COLORREF color)
|
||||
{
|
||||
this->tableBkClor = color;
|
||||
}
|
||||
|
||||
void table::settableFillMode(StellarX::fillMode mode)
|
||||
{
|
||||
if (StellarX::fillMode::Solid == mode || StellarX::fillMode::Null == mode)
|
||||
this->tableFillMode = mode;
|
||||
else
|
||||
this->tableFillMode = StellarX::fillMode::Solid;
|
||||
}
|
||||
|
||||
void table::settableLineStyle(StellarX::lineStyle style)
|
||||
{
|
||||
this->tableLineStyle = style;
|
||||
}
|
||||
|
||||
void table::settableBorderWidth(int width)
|
||||
{
|
||||
this->tableBorderWidth = width;
|
||||
}
|
||||
|
||||
int table::getCurrentPage() const
|
||||
{
|
||||
return this->currentPage;
|
||||
}
|
||||
|
||||
int table::getTotalPages() const
|
||||
{
|
||||
return this->totalPages;;
|
||||
}
|
||||
|
||||
int table::getRowsPerPage() const
|
||||
{
|
||||
return this->rowsPerPage;
|
||||
}
|
||||
|
||||
bool table::getShowPageButton() const
|
||||
{
|
||||
return this->isShowPageButton;
|
||||
}
|
||||
|
||||
COLORREF table::gettableBorder() const
|
||||
{
|
||||
return this->tableBorderClor;
|
||||
}
|
||||
|
||||
COLORREF table::gettableBk() const
|
||||
{
|
||||
return this->tableBkClor;
|
||||
}
|
||||
|
||||
StellarX::fillMode table::gettableFillMode() const
|
||||
{
|
||||
return this->tableFillMode;
|
||||
}
|
||||
|
||||
StellarX::lineStyle table::gettableLineStyle() const
|
||||
{
|
||||
return this->tableLineStyle;
|
||||
}
|
||||
|
||||
std::vector<std::string> table::getHeaders() const
|
||||
{
|
||||
return this->headers;
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>> table::getData() const
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
|
||||
int table::gettableBorderWidth() const
|
||||
{
|
||||
return this->tableBorderWidth;
|
||||
}
|
||||
|
||||
|
||||
135
src/textBox.cpp
Normal file
135
src/textBox.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
// TxtBox.cpp
|
||||
#include "textBox.h"
|
||||
|
||||
|
||||
textBox::textBox(int x, int y, int width, int height, std::string text, StellarX::textBoxmode mode, StellarX::controlShape shape)
|
||||
:Control(x,y,width,height),text(text), mode(mode), shape(shape)
|
||||
{
|
||||
}
|
||||
|
||||
void textBox::draw()
|
||||
{
|
||||
if(dirty)
|
||||
{
|
||||
saveStyle();
|
||||
setfillcolor(textBoxBkClor);
|
||||
setlinecolor(textBoxBorderClor);
|
||||
if (textStyle.nHeight > height - y)
|
||||
textStyle.nHeight = height;
|
||||
if (textStyle.nWidth > width - x)
|
||||
textStyle.nWidth = width;
|
||||
settextstyle(textStyle.nHeight, textStyle.nWidth, textStyle.lpszFace,
|
||||
textStyle.nEscapement, textStyle.nOrientation, textStyle.nWeight,
|
||||
textStyle.bItalic, textStyle.bUnderline, textStyle.bStrikeOut);
|
||||
|
||||
settextcolor(textStyle.color);
|
||||
setbkmode(TRANSPARENT);
|
||||
int text_width = textwidth(LPCTSTR(text.c_str()));
|
||||
int text_height = textheight(LPCTSTR(text.c_str()));
|
||||
|
||||
|
||||
//根据形状绘制
|
||||
switch (shape)
|
||||
{
|
||||
case StellarX::controlShape::RECTANGLE:
|
||||
fillrectangle(x, y, width, height);//有边框填充矩形
|
||||
outtextxy(x + 10, (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::B_RECTANGLE:
|
||||
solidrectangle(x, y, width, height);//无边框填充矩形
|
||||
outtextxy(x + 10, (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::ROUND_RECTANGLE:
|
||||
fillroundrect(x, y, width, height, 20, 20);//有边框填充圆角矩形
|
||||
outtextxy(x + 10, (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
case StellarX::controlShape::B_ROUND_RECTANGLE:
|
||||
solidroundrect(x, y, width, height, 20, 20);//无边框填充圆角矩形
|
||||
outtextxy(x + 10, (y + (height - y - text_height) / 2), LPCTSTR(text.c_str()));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
restoreStyle();
|
||||
dirty = false; //标记不需要重绘
|
||||
}
|
||||
|
||||
void textBox::handleEvent(const ExMessage& msg)
|
||||
{
|
||||
bool hover = false;
|
||||
bool oldClick = click;
|
||||
|
||||
switch (shape)
|
||||
{
|
||||
case StellarX::controlShape::RECTANGLE:
|
||||
case StellarX::controlShape::B_RECTANGLE:
|
||||
case StellarX::controlShape::ROUND_RECTANGLE:
|
||||
case StellarX::controlShape::B_ROUND_RECTANGLE:
|
||||
hover = (msg.x > x && msg.x < width && msg.y > y && msg.y < height);//判断鼠标是否在矩形按钮内
|
||||
break;
|
||||
}
|
||||
if (hover && msg.message == WM_LBUTTONUP)
|
||||
{
|
||||
click = true;
|
||||
if(StellarX::textBoxmode::INPUT_MODE == mode)
|
||||
dirty = InputBox(LPTSTR(text.c_str()), maxCharLen,"输入框",NULL,text.c_str(), NULL ,NULL,false);
|
||||
else if (StellarX::textBoxmode::READONLY_MODE == mode)
|
||||
{
|
||||
dirty = false;
|
||||
InputBox(NULL, maxCharLen, "输出框(输入无效!)", NULL, text.c_str(), NULL, NULL, false);
|
||||
}
|
||||
flushmessage(EX_MOUSE | EX_KEY);
|
||||
}
|
||||
if (dirty)
|
||||
draw();
|
||||
|
||||
if (click)
|
||||
click = false;
|
||||
}
|
||||
|
||||
void textBox::setMode(StellarX::textBoxmode mode)
|
||||
{
|
||||
this->mode = mode;
|
||||
}
|
||||
|
||||
void textBox::setmaxCharLen(int len)
|
||||
{
|
||||
if (len > 0)
|
||||
maxCharLen = len;
|
||||
}
|
||||
|
||||
void textBox::settextBoxshape(StellarX::controlShape shape)
|
||||
{
|
||||
switch (shape)
|
||||
{
|
||||
case StellarX::controlShape::RECTANGLE:
|
||||
case StellarX::controlShape::B_RECTANGLE:
|
||||
case StellarX::controlShape::ROUND_RECTANGLE:
|
||||
case StellarX::controlShape::B_ROUND_RECTANGLE:
|
||||
this->shape = shape;
|
||||
break;
|
||||
case StellarX::controlShape::CIRCLE:
|
||||
case StellarX::controlShape::B_CIRCLE:
|
||||
case StellarX::controlShape::ELLIPSE:
|
||||
case StellarX::controlShape::B_ELLIPSE:
|
||||
this->shape = StellarX::controlShape::RECTANGLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void textBox::settextBoxBorder(COLORREF color)
|
||||
{
|
||||
textBoxBorderClor = color;
|
||||
}
|
||||
|
||||
void textBox::settextBoxBk(COLORREF color)
|
||||
{
|
||||
textBoxBkClor = color;
|
||||
}
|
||||
|
||||
std::string textBox::gettext()
|
||||
{
|
||||
return this->text;
|
||||
}
|
||||
|
||||
|
||||
114
src/window.cpp
Normal file
114
src/window.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include "window.h"
|
||||
|
||||
window::window(int width, int height, int mode)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->windowMode = mode;
|
||||
}
|
||||
|
||||
window::window(int width, int height, int mode, COLORREF bkcloc)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->windowMode = mode;
|
||||
this->wBkcolor = bkcloc;
|
||||
}
|
||||
|
||||
window::window(int width, int height, int mode, COLORREF bkcloc, std::string headline)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->windowMode = mode;
|
||||
this->wBkcolor = bkcloc;
|
||||
this->headline = headline;
|
||||
}
|
||||
|
||||
window::~window()
|
||||
{
|
||||
if (background)
|
||||
delete background;
|
||||
background = nullptr;
|
||||
closegraph(); // 确保关闭图形上下文
|
||||
}
|
||||
|
||||
void window::draw()
|
||||
{
|
||||
hWnd = initgraph(width, height, windowMode);
|
||||
SetWindowText(hWnd,headline.c_str());
|
||||
setbkcolor(wBkcolor);
|
||||
cleardevice();
|
||||
BeginBatchDraw(); // 开始批量绘制
|
||||
// 绘制所有子控件
|
||||
for (auto& control : controls)
|
||||
control->draw();
|
||||
EndBatchDraw(); // 结束批量绘制
|
||||
}
|
||||
// 使用背景图片绘制窗口
|
||||
// @参数 pImgFile: 图片文件路径,支持常见图片格式
|
||||
// @备注: 会拉伸图片以适应窗口尺寸
|
||||
void window::draw(std::string pImgFile)
|
||||
{
|
||||
this->background = new IMAGE;
|
||||
hWnd = initgraph(width, height, windowMode);
|
||||
SetWindowText(hWnd, headline.c_str());
|
||||
loadimage(background, pImgFile.c_str(), width, height, true);
|
||||
putimage(0,0, background);
|
||||
|
||||
// 绘制所有子控件
|
||||
BeginBatchDraw(); // 开始批量绘制
|
||||
for (auto& control : controls)
|
||||
control->draw();
|
||||
EndBatchDraw(); // 结束批量绘制
|
||||
|
||||
}
|
||||
// 运行主事件循环,处理用户输入和窗口消息
|
||||
// 此方法会阻塞直到窗口关闭
|
||||
void window::runEventLoop()
|
||||
{
|
||||
ExMessage msg;
|
||||
bool running = true;
|
||||
while (running) {
|
||||
msg = getmessage(EX_MOUSE | EX_KEY);
|
||||
if (msg.message == WM_CLOSE) {
|
||||
running = false;
|
||||
continue;
|
||||
}
|
||||
for (auto& c : controls)
|
||||
c->handleEvent(msg);
|
||||
flushmessage(EX_MOUSE |EX_KEY |EX_CHAR|EX_WINDOW);
|
||||
Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
void window::setBkImage(std::string pImgFile)
|
||||
{
|
||||
if(nullptr == background)
|
||||
this->background = new IMAGE;
|
||||
else
|
||||
delete background;
|
||||
this->background = new IMAGE;
|
||||
loadimage(background, pImgFile.c_str(), width, height, true);
|
||||
putimage(0, 0, background);
|
||||
}
|
||||
|
||||
void window::setBkcolor(COLORREF c)
|
||||
{
|
||||
wBkcolor = c;
|
||||
}
|
||||
|
||||
void window::setHeadline(std::string headline)
|
||||
{
|
||||
this->headline = headline;
|
||||
SetWindowText(this->hWnd, headline.c_str());
|
||||
}
|
||||
|
||||
void window::addControl(std::unique_ptr<Control> control)
|
||||
{
|
||||
this->controls.push_back(std::move(control));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user