fix: v0.10.5 —— 导出前先定页面尺寸,并给导出过程加日志

- 之前是先渲染文档、后设置页面尺寸;表格用的是百分比宽度,
  页面宽度为 0 时插入表格,某些 Qt 构建会在打印排版阶段死循环
- 改成先建 QPdfWriter、量出页面宽高、设好 document 的 pageSize,再开始渲染
- 增加排版结果健全性检查(NaN / 高度 <= 0 直接中止并提示)
- 新增导出日志:%APPDATA%/VoiletMark/VoiletMark/export.log(Linux 在
  ~/.local/share/...),逐步记录 对话框关闭 / 渲染开始 / 渲染结束 / 写入完成
- 版本 0.10.5
This commit is contained in:
2026-10-22 18:54:45 +08:00
parent 8aca7ade42
commit fc6b52cd32
4 changed files with 57 additions and 16 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
一个轻量的跨平台 Markdown 编辑器,基于 **Qt 5 / C++17** 构建。 一个轻量的跨平台 Markdown 编辑器,基于 **Qt 5 / C++17** 构建。
当前版本 **0.10.4**。 当前版本 **0.10.5**。
## 界面 ## 界面
+1 -1
View File
@@ -1,6 +1,6 @@
TEMPLATE = app TEMPLATE = app
TARGET = VoiletMark TARGET = VoiletMark
VERSION = 0.10.4 VERSION = 0.10.5
QT += core gui widgets QT += core gui widgets
+47 -7
View File
@@ -10,6 +10,7 @@
#include <QActionGroup> #include <QActionGroup>
#include <QApplication> #include <QApplication>
#include <QCloseEvent> #include <QCloseEvent>
#include <QDateTime>
#include <QDir> #include <QDir>
#include <QDirIterator> #include <QDirIterator>
#include <QDockWidget> #include <QDockWidget>
@@ -688,6 +689,20 @@ bool MainWindow::saveFileAs()
return writeToFile(path); return writeToFile(path);
} }
void MainWindow::logExport(const QString &message)
{
const QString directory = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
if (directory.isEmpty())
return;
QDir().mkpath(directory);
QFile file(QDir(directory).filePath(QStringLiteral("export.log")));
if (!file.open(QIODevice::Append | QIODevice::Text))
return;
QTextStream stream(&file);
stream << QDateTime::currentDateTime().toString(Qt::ISODate) << " " << message << "\n";
}
void MainWindow::exportPdf() void MainWindow::exportPdf()
{ {
QString suggested = m_currentPath.isEmpty() ? tr("未命名") QString suggested = m_currentPath.isEmpty() ? tr("未命名")
@@ -702,12 +717,10 @@ void MainWindow::exportPdf()
if (!target.endsWith(QStringLiteral(".pdf"), Qt::CaseInsensitive)) if (!target.endsWith(QStringLiteral(".pdf"), Qt::CaseInsensitive))
target += QStringLiteral(".pdf"); target += QStringLiteral(".pdf");
logExport(QStringLiteral("dialog closed, target=%1").arg(target));
statusBar()->showMessage(tr("正在导出 PDF…")); statusBar()->showMessage(tr("正在导出 PDF…"));
QApplication::processEvents();
QTextDocument document;
MarkdownRenderer::render(m_editor->toPlainText(), &document);
{
// 用 QPdfWriter 直接写 PDF,不碰任何平台的打印子系统: // 用 QPdfWriter 直接写 PDF,不碰任何平台的打印子系统:
// Windows 的打印后台、Linux 的 CUPS 在没有打印机或服务异常时都可能卡住。 // Windows 的打印后台、Linux 的 CUPS 在没有打印机或服务异常时都可能卡住。
QPdfWriter writer(target); QPdfWriter writer(target);
@@ -715,14 +728,41 @@ void MainWindow::exportPdf()
writer.setPageMargins(QMarginsF(16, 16, 16, 16), QPageLayout::Millimeter); writer.setPageMargins(QMarginsF(16, 16, 16, 16), QPageLayout::Millimeter);
writer.setTitle(QFileInfo(target).completeBaseName()); writer.setTitle(QFileInfo(target).completeBaseName());
// 先把页面尺寸定下来再渲染:表格用的是百分比宽度,
// 页面宽度为 0 时插入表格会让某些平台的排版循环算不出结果。
QSizeF pageSize(672.76, 1001.57);
const QRectF paintRect = writer.pageLayout().paintRectPixels(writer.resolution()); const QRectF paintRect = writer.pageLayout().paintRectPixels(writer.resolution());
const qreal scale = 96.0 / writer.resolution(); const qreal resolution = qMax(1, writer.resolution());
document.setPageSize(QSizeF(paintRect.width() * scale, paintRect.height() * scale)); if (paintRect.width() > 100 && paintRect.height() > 100) {
const qreal scale = 96.0 / resolution;
pageSize = QSizeF(paintRect.width() * scale, paintRect.height() * scale);
}
QTextDocument document;
document.setPageSize(pageSize);
logExport(QStringLiteral("rendering, page size=%1x%2").arg(pageSize.width()).arg(pageSize.height()));
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::WaitCursor);
MarkdownRenderer::render(m_editor->toPlainText(), &document);
const QSizeF documentSize = document.size();
logExport(QStringLiteral("rendered, blocks=%1 height=%2")
.arg(document.blockCount())
.arg(documentSize.height()));
if (!qIsFinite(documentSize.width()) || !qIsFinite(documentSize.height())
|| documentSize.height() <= 0) {
QApplication::restoreOverrideCursor();
logExport(QStringLiteral("aborted: bad document size %1x%2")
.arg(documentSize.width())
.arg(documentSize.height()));
QMessageBox::warning(this, tr("导出失败"), tr("文档排版结果异常,已中止导出。"));
return;
}
document.print(&writer); document.print(&writer);
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
}
logExport(QStringLiteral("printed, size=%1").arg(QFileInfo(target).size()));
if (!QFileInfo::exists(target) || QFileInfo(target).size() <= 0) { if (!QFileInfo::exists(target) || QFileInfo(target).size() <= 0) {
QMessageBox::warning(this, tr("导出失败"), QMessageBox::warning(this, tr("导出失败"),
+1
View File
@@ -60,6 +60,7 @@ private:
QStringList scanFolder() const; QStringList scanFolder() const;
void setSourceModeEnabled(bool enabled); void setSourceModeEnabled(bool enabled);
void exportPdf(); void exportPdf();
void logExport(const QString &message);
// ---- Git ---- // ---- Git ----
void updateGitState(); void updateGitState();