diff --git a/.gitignore b/.gitignore index 76dc72e..4973801 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ _bin/ temp/ bin/ .vs/ -demo/* +demo/ *.lib \ No newline at end of file diff --git a/demo/Adminstor/Adminstor/mainForm.cpp b/demo/Adminstor/Adminstor/mainForm.cpp index b575d74..480593a 100644 --- a/demo/Adminstor/Adminstor/mainForm.cpp +++ b/demo/Adminstor/Adminstor/mainForm.cpp @@ -76,7 +76,7 @@ void mainForm::OnNotify(Control* sender, EventArgs& args) int rowCount = tableView->GetRowCount(); //总行数 // 表格增加一行数据 tableView->InsertRow(rowCount); - tableView->SetRowData(rowCount, { L"uid" + std::to_wstring(rowCount), L"192.168.200.131" , L"默认"}); + tableView->SetRowData(rowCount, { L"uid" + std::to_wstring(rowCount), L"192.168.200.131\n127.0.0" , L"", L"2026-02-25"}); // 获取表格指定位置数据 } @@ -123,6 +123,7 @@ mainForm::mainForm() :LayeredWindow(1000, 750) freopen_s(&fp, "CONOUT$", "w", stdout); freopen_s(&fp, "CONOUT$", "w", stderr); + // 初始化设置表格各项属性 TableView* tableView = (TableView*)FindControl("tableViewAdmin"); //获取表格控件 if (tableView) { @@ -130,12 +131,14 @@ mainForm::mainForm() :LayeredWindow(1000, 750) tableView->SetColumnType(5, ezui::CellType::CheckBox); tableView->SetColumnType(2, ezui::CellType::ComboBox); tableView->SetColumnComboItems(2, { L"默认", L"禁止" , L"验机" }); + //设置列宽 - //std::vector withs = {80, 100}; + std::vector withs = {60, 120, 50, 90, 85, 85, 100, 70, 70, 80, 80, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90}; + for(auto i=0;i< withs.size();i++) + tableView->SetColumnWidth(i, withs[i]); - - // 鼠标右键单击的回调 + // 鼠标右键单击的回调 tableView->RightClick = [tableView](int row, int col) { int pRow = tableView->GetHoverRow(); //当前行号 int pCol = tableView->GetHoverCol(); //当前列号 @@ -143,6 +146,7 @@ mainForm::mainForm() :LayeredWindow(1000, 750) //std::cout << "单元格内容: " << celContent.ansi() << std::endl; std::cout << "当前列宽: " << tableView->GetColumnWidth(pCol) << std::endl; }; + // 单元格编辑完成(编辑结束时触发,提供旧值与新值) tableView->CellEditFinished = [](int row, int col, const UIString& oldValue, const UIString& newValue) { std::cout << "单元格内容: " << newValue.ansi() << ", " << oldValue.ansi() << std::endl; diff --git a/demo/Adminstor/ThirdParty/EzUI/include/EzUI/TextBox.h b/demo/Adminstor/ThirdParty/EzUI/include/EzUI/TextBox.h index 4803c56..fe427ce 100644 --- a/demo/Adminstor/ThirdParty/EzUI/include/EzUI/TextBox.h +++ b/demo/Adminstor/ThirdParty/EzUI/include/EzUI/TextBox.h @@ -11,7 +11,8 @@ namespace ezui { VScrollBar m_vScrollbar; int m_lastWidth = 0; int m_lastHeight = 0; - bool m_multiLine = false; + bool m_autoWrap = false; // 是否允许文字超宽时自动换行 + bool m_allowManualLineBreak = false; // 是否允许用户按Shift+Enter手动换行 std::wstring m_text;//文字 Size m_fontBox; bool m_down = false;//是否具有焦点中 @@ -98,10 +99,12 @@ namespace ezui { virtual ScrollBar* GetScrollBar()override; //设置文字 void SetText(const UIString& text); - //是否多行显示 + //是否多行显示(兼容旧版:仅调用autoWrap参数) bool IsMultiLine(); //设置是否多行显示 - void SetMultiLine(bool multiLine); + // autoWrap: 文字超宽时是否自动换行 + // allowManualLineBreak: 是否允许用户按Shift+Enter手动换行 + void SetMultiLine(bool autoWrap, bool allowManualLineBreak = false); //设置为是否只读 void SetReadOnly(bool bReadOnly); //是否为只读 diff --git a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_Win32.lib b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_Win32.lib index 69b09f5..76a9f9a 100644 Binary files a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_Win32.lib and b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_Win32.lib differ diff --git a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_Win32.pdb b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_Win32.pdb index 71c1d2c..f69d8cc 100644 Binary files a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_Win32.pdb and b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_Win32.pdb differ diff --git a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_x64.lib b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_x64.lib index b5384e0..83db7c0 100644 Binary files a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_x64.lib and b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_x64.lib differ diff --git a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_x64.pdb b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_x64.pdb index 2545cbf..f16d58e 100644 Binary files a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_x64.pdb and b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Debug_x64.pdb differ diff --git a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Release_Win32.lib b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Release_Win32.lib index ca2568b..376e304 100644 Binary files a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Release_Win32.lib and b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Release_Win32.lib differ diff --git a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Release_x64.lib b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Release_x64.lib index ad0c05d..86b5d01 100644 Binary files a/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Release_x64.lib and b/demo/Adminstor/ThirdParty/EzUI/lib/EzUI_Release_x64.lib differ diff --git a/include/EzUI/TextBox.h b/include/EzUI/TextBox.h index 4803c56..fe427ce 100644 --- a/include/EzUI/TextBox.h +++ b/include/EzUI/TextBox.h @@ -11,7 +11,8 @@ namespace ezui { VScrollBar m_vScrollbar; int m_lastWidth = 0; int m_lastHeight = 0; - bool m_multiLine = false; + bool m_autoWrap = false; // 是否允许文字超宽时自动换行 + bool m_allowManualLineBreak = false; // 是否允许用户按Shift+Enter手动换行 std::wstring m_text;//文字 Size m_fontBox; bool m_down = false;//是否具有焦点中 @@ -98,10 +99,12 @@ namespace ezui { virtual ScrollBar* GetScrollBar()override; //设置文字 void SetText(const UIString& text); - //是否多行显示 + //是否多行显示(兼容旧版:仅调用autoWrap参数) bool IsMultiLine(); //设置是否多行显示 - void SetMultiLine(bool multiLine); + // autoWrap: 文字超宽时是否自动换行 + // allowManualLineBreak: 是否允许用户按Shift+Enter手动换行 + void SetMultiLine(bool autoWrap, bool allowManualLineBreak = false); //设置为是否只读 void SetReadOnly(bool bReadOnly); //是否为只读 diff --git a/lib/EzUI_Debug_Win32.lib b/lib/EzUI_Debug_Win32.lib index 69b09f5..76a9f9a 100644 Binary files a/lib/EzUI_Debug_Win32.lib and b/lib/EzUI_Debug_Win32.lib differ diff --git a/lib/EzUI_Debug_Win32.pdb b/lib/EzUI_Debug_Win32.pdb index 71c1d2c..f69d8cc 100644 Binary files a/lib/EzUI_Debug_Win32.pdb and b/lib/EzUI_Debug_Win32.pdb differ diff --git a/lib/EzUI_Debug_x64.lib b/lib/EzUI_Debug_x64.lib index b5384e0..83db7c0 100644 Binary files a/lib/EzUI_Debug_x64.lib and b/lib/EzUI_Debug_x64.lib differ diff --git a/lib/EzUI_Debug_x64.pdb b/lib/EzUI_Debug_x64.pdb index 2545cbf..f16d58e 100644 Binary files a/lib/EzUI_Debug_x64.pdb and b/lib/EzUI_Debug_x64.pdb differ diff --git a/lib/EzUI_Release_Win32.lib b/lib/EzUI_Release_Win32.lib index ca2568b..376e304 100644 Binary files a/lib/EzUI_Release_Win32.lib and b/lib/EzUI_Release_Win32.lib differ diff --git a/lib/EzUI_Release_x64.lib b/lib/EzUI_Release_x64.lib index ad0c05d..86b5d01 100644 Binary files a/lib/EzUI_Release_x64.lib and b/lib/EzUI_Release_x64.lib differ diff --git a/sources/TableView.cpp b/sources/TableView.cpp index 72637b4..21e98c0 100644 --- a/sources/TableView.cpp +++ b/sources/TableView.cpp @@ -33,7 +33,8 @@ namespace ezui { // 创建编辑控件(初始隐藏) m_editBox = new TextBox(); m_editBox->SetVisible(false); - m_editBox->SetMultiLine(true); + // 设置为:不自动换行,但允许手动换行(Shift+Enter) + m_editBox->SetMultiLine(false, true); // 为编辑框设置默认字体样式 m_editBox->Style.FontSize = m_cellFontSize; m_editBox->Style.FontFamily = L"Microsoft YaHei"; @@ -45,6 +46,16 @@ namespace ezui { if (m_editRow < (int)m_data.size() && m_editCol < (int)m_data[m_editRow].size()) { m_data[m_editRow][m_editCol].Text = text; UpdateRowHeight(m_editRow); + + // 同步更新编辑框的高度以匹配新的行高 + if (m_editCol < (int)m_columns.size() && m_editRow < (int)m_rowHeights.size()) { + int x = GetColumnX(m_editCol); + int y = GetRowY(m_editRow); + int width = m_columns[m_editCol].Width; + int height = m_rowHeights[m_editRow]; // 使用更新后的行高 + m_editBox->SetRect(Rect(x, y, width, height)); + } + if (CellValueChanged) { CellValueChanged(m_editRow, m_editCol, text); } @@ -415,9 +426,10 @@ namespace ezui { switch (colInfo.Type) { case CellType::TextBox: case CellType::ReadOnly: { - // 绘制文本 + // 绘制文本(禁用自动换行,只根据实际换行符换行) + font.Get()->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); TextLayout layout(cellData.Text.unicode(), font, - SizeF(cellRect.Width - 4, cellRect.Height - 2), TextAlign::MiddleLeft); + SizeF(cellRect.Width - 4, EZUI_FLOAT_MAX), TextAlign::TopLeft); g.DrawTextLayout(layout, PointF(cellRect.X + 2, cellRect.Y + 1)); break; } @@ -644,13 +656,15 @@ namespace ezui { return 1; } - Font font(m_cellFontFamily, m_cellFontSize); - TextLayout layout(text.unicode(), font, SizeF(width, EZUI_FLOAT_MAX)); - Size box = layout.GetFontBox(); - - int fontHeight = m_cellFontSize + 4; - int lines = (box.Height + fontHeight - 1) / fontHeight; - return (std::max)(1, lines); + // 由于单元格设置为不自动换行,只根据实际换行符计算行数 + std::wstring wtext = text.unicode(); + int lines = 1; + for (wchar_t c : wtext) { + if (c == L'\n') { + lines++; + } + } + return lines; } void TableView::RefreshScrollBars() { diff --git a/sources/TextBox.cpp b/sources/TextBox.cpp index 7a5b614..ff098bd 100644 --- a/sources/TextBox.cpp +++ b/sources/TextBox.cpp @@ -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); } }