优化编辑框控件的多行编辑和显示;

优化表格控件单元格的多行编辑和显示效果
This commit is contained in:
睿 安
2026-01-28 22:27:21 +08:00
parent 4fe4749826
commit 814f42120c
18 changed files with 78 additions and 43 deletions

View File

@@ -235,8 +235,8 @@ namespace ezui {
std::wstring wBuf;
bool bRet = ezui::GetClipboardData(&wBuf, Hwnd());
UIString u8Str(wBuf);
if (!m_multiLine) {
//行编辑框不允许有换行符
if (!m_allowManualLineBreak) {
//不允许手动换行时不允许有换行符
ui_text::Replace(&u8Str, "\r", "");
ui_text::Replace(&u8Str, "\n", "");
}
@@ -263,8 +263,8 @@ namespace ezui {
WPARAM wParam = arg.wParam;
LPARAM lParam = arg.lParam;
//判断是否按下shift+enter
if (IsMultiLine() && (GetKeyState(VK_SHIFT) & 0x8000) && wParam == VK_RETURN) {
//判断是否按下shift+enter(仅当允许手动换行时)
if (m_allowManualLineBreak && (GetKeyState(VK_SHIFT) & 0x8000) && wParam == VK_RETURN) {
InsertUnicode(L"\n");//插入换行符
Analysis();//分析字符串
Invalidate();//刷新
@@ -374,7 +374,7 @@ namespace ezui {
int innerW = std::max(0, Width() - (m_padLeft + m_padRight));
int innerH = std::max(0, Height() - (m_padTop + m_padBottom));
if (!m_multiLine) {//单行编辑框
if (!m_autoWrap && !m_allowManualLineBreak) {//单行编辑框(两者都不允许)
m_font->Get()->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
bool bAlignLeft = (int(this->TextAlign) & int(HAlign::Left));
float width = bAlignLeft ? EZUI_FLOAT_MAX : (float)innerW;
@@ -394,8 +394,13 @@ namespace ezui {
m_scrollX = innerW - m_fontBox.Width;
}
}
else {//多行编辑框
m_font->Get()->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);
else {//多行编辑框(至少允许一种换行方式)
// 根据 m_autoWrap 决定是否启用自动换行
if (m_autoWrap) {
m_font->Get()->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);
} else {
m_font->Get()->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
}
m_textLayout = new TextLayout(*drawText, *m_font, SizeF{ (float)innerW, EZUI_FLOAT_MAX }, TextAlign::TopLeft);
m_fontBox = m_textLayout->GetFontBox();
}
@@ -403,13 +408,13 @@ namespace ezui {
delete drawText;
}
// 内容尺寸:多行时加入 padding 以保证最后一行不被裁掉,单行保持原逻辑
if (m_multiLine) {
if (m_autoWrap || m_allowManualLineBreak) {
this->SetContentSize({ m_fontBox.Width + m_padLeft + m_padRight, m_fontBox.Height + m_padTop + m_padBottom });
}
else {
this->SetContentSize({ m_fontBox.Width , m_fontBox.Height });
}
if (m_multiLine) {
if (m_autoWrap || m_allowManualLineBreak) {
this->GetScrollBar()->RefreshScroll();
}
BuildCare();
@@ -431,7 +436,7 @@ namespace ezui {
m_careRect.Height = m_textLayout->GetFontHeight();
m_careRect.Width = 1 * this->GetScale();
if (!m_multiLine) {
if (!m_autoWrap && !m_allowManualLineBreak) {
// 使光标保持在可视内区(考虑 padding
int innerW = std::max(0, Width() - (m_padLeft + m_padRight));
int caretDrawX = m_careRect.X + m_scrollX; // 布局坐标 + 滚动
@@ -487,7 +492,7 @@ namespace ezui {
void TextBox::OnMouseWheel(const MouseEventArgs& arg)
{
__super::OnMouseWheel(arg);
if (!m_multiLine) {//单行
if (!m_autoWrap && !m_allowManualLineBreak) {//单行
int innerW = std::max(0, Width() - (m_padLeft + m_padRight));
int textWidth = m_fontBox.Width;
if (arg.ZDelta > 0 && textWidth > innerW) {
@@ -522,15 +527,15 @@ namespace ezui {
m_scrollX = 0;
m_scrollY = 0;
m_selectRects.clear();
if (!m_multiLine && Height() != m_lastHeight) {
if ((!m_autoWrap && !m_allowManualLineBreak) && Height() != m_lastHeight) {
m_lastHeight = Height();
Analysis();
}
if (m_multiLine && Width() != m_lastWidth) {
if ((m_autoWrap || m_allowManualLineBreak) && Width() != m_lastWidth) {
m_lastWidth = Width();
Analysis();
}
this->SetContentSize({ m_fontBox.Width ,m_multiLine ? m_fontBox.Height : Height() });
this->SetContentSize({ m_fontBox.Width ,(m_autoWrap || m_allowManualLineBreak) ? m_fontBox.Height : Height() });
this->GetScrollBar()->RefreshScroll();
this->EndLayout();
}
@@ -555,7 +560,7 @@ namespace ezui {
BuildSelectedRect();
if (!m_multiLine) {//单行
if (!m_autoWrap && !m_allowManualLineBreak) {//单行
// 计算去掉左 padding 的鼠标相对文本区域坐标
int innerW = std::max(0, Width() - (m_padLeft + m_padRight));
int textWidth = m_fontBox.Width;
@@ -620,12 +625,13 @@ namespace ezui {
}
bool TextBox::IsMultiLine()
{
return m_multiLine;
return m_autoWrap || m_allowManualLineBreak;
}
void TextBox::SetMultiLine(bool multiLine)
void TextBox::SetMultiLine(bool autoWrap, bool allowManualLineBreak)
{
if (this->m_multiLine != multiLine) {
this->m_multiLine = multiLine;
if (this->m_autoWrap != autoWrap || this->m_allowManualLineBreak != allowManualLineBreak) {
this->m_autoWrap = autoWrap;
this->m_allowManualLineBreak = allowManualLineBreak;
Analysis();
}
}
@@ -751,11 +757,14 @@ namespace ezui {
}
if (key == "multiline") {
if (value == "true") {
this->m_multiLine = true;
// 兼容旧版:multiline=true 表示自动换行+手动换行
this->m_autoWrap = true;
this->m_allowManualLineBreak = true;
break;
}
if (value == "false") {
this->m_multiLine = false;
this->m_autoWrap = false;
this->m_allowManualLineBreak = false;
break;
}
}
@@ -786,7 +795,9 @@ namespace ezui {
placeholderColor.SetA(fontColor.GetA() * 0.6);
e.Graphics.SetColor(placeholderColor);
RectF ph((float)m_padLeft, (float)m_padTop, (float)Width() - (float)(m_padLeft + m_padRight), (float)Height() - (float)(m_padTop + m_padBottom));
e.Graphics.DrawString(m_placeholder, ph, m_multiLine ? TextAlign::TopLeft : this->TextAlign);
Font phFont(fontFamily, fontSize);
e.Graphics.SetFont(phFont);
e.Graphics.DrawString(m_placeholder, ph, (m_autoWrap || m_allowManualLineBreak) ? TextAlign::TopLeft : this->TextAlign);
}
}