From 808a38628e3feb2c42fc1f2fab6bffd4d8cf20ce Mon Sep 17 00:00:00 2001 From: Byons Date: Thu, 16 Jul 2026 11:04:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=BD=E7=A6=BB=E5=9C=BA=E6=99=AF=E6=89=93?= =?UTF-8?q?=E5=BC=80=E9=80=BB=E8=BE=91=E3=80=81=E6=B7=BB=E5=8A=A0=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E7=95=8C=E9=9D=A2=E7=9A=84=E5=B7=A6=E5=8F=B3=E6=8B=96?= =?UTF-8?q?=E5=8A=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DialogFileOperation.cpp | 8 +- InkJetPrinter.cpp | 20 ++--- Printsetting.cpp | 2 +- QtUI.pro | 2 + mainwidget.cpp | 47 +++++++--- mainwidget.h | 2 +- scene/PicSceneLoader.cpp | 188 +++++++++++++++++++++++++++++++++++++++ scene/PicSceneLoader.h | 17 ++++ scene/myview.cpp | 59 ++++++++++++ scene/myview.h | 12 ++- 10 files changed, 330 insertions(+), 27 deletions(-) create mode 100644 scene/PicSceneLoader.cpp create mode 100644 scene/PicSceneLoader.h diff --git a/DialogFileOperation.cpp b/DialogFileOperation.cpp index 3ed662c..8567acf 100644 --- a/DialogFileOperation.cpp +++ b/DialogFileOperation.cpp @@ -16,6 +16,7 @@ #include"myinclude.h" #include #include +#include "scene/PicSceneLoader.h" DialogFileOperation::DialogFileOperation(QWidget *parent) : QDialog(parent), @@ -78,8 +79,11 @@ void DialogFileOperation::on_listViewFile_entered(const QModelIndex &index) } else if(filePath.endsWith(".xml")) { - emit createSceneImage(filePath); - ui->textEditView->setHtml(QString("").arg("./printSceneView.png")); + QImage previewImg = PicSceneLoader::previewSceneFromFile(filePath); + ui->textEditView->clear(); + auto cursor = ui->textEditView->textCursor(); + cursor.insertImage(previewImg); + ui->textEditView->setTextCursor(cursor); } else { QFile file(filePath); diff --git a/InkJetPrinter.cpp b/InkJetPrinter.cpp index a40c432..b57bce5 100644 --- a/InkJetPrinter.cpp +++ b/InkJetPrinter.cpp @@ -1008,8 +1008,15 @@ void InkJetPrinter::timerHandler(void){ } // byons: 时间类型图元更新 @2026年4月11日 - auto updateArea = m_MainWidget->variableItemsUpdate(); - if (!updateArea.isNull()) { + // byons: 变量类图元现在优化为局部更新,避免每次都要把整个打印内容发送给FPGA,现在只发送被更新的列区间 2026年7月16日 + auto updateAreas = m_MainWidget->variableItemsUpdate(); + if(sysPara->status.isPrinting && !updateAreas.isEmpty()){ + for(const auto& area : updateAreas) { + m_MainWidget->SendPrintDataToFpga(0, area.left(), area.width()); + } + } + + if (!updateAreas.isEmpty() && m_StackedWidget->currentWidget() == m_MainWidget) { // // 统计追踪更新频率 // static QElapsedTimer bnsTimer; // static int toogleCount = 0; @@ -1019,14 +1026,7 @@ void InkJetPrinter::timerHandler(void){ // qDebug() << (QString("timeHandler avg elapsed: %1 s").arg(elapsed / qreal(toogleCount) / 1000.0)); // toogleCount = 0; // } - - if(sysPara->status.isPrinting) { - m_MainWidget->SendPrintDataToFpga(0, updateArea.left(), updateArea.width()); - } - - if(m_StackedWidget->currentWidget() == m_MainWidget) { - m_MainWidget->updatePrintDisplayLabel(); - } + m_MainWidget->updatePrintDisplayLabel(); } // if (modbus->getModbusStatus() == 1) { diff --git a/Printsetting.cpp b/Printsetting.cpp index 75f6eb4..0440951 100644 --- a/Printsetting.cpp +++ b/Printsetting.cpp @@ -649,7 +649,7 @@ void PrintSetting::applyPrintSettingsToSysPara(bool showTip) if(res != -1 && showTip) { QMessageBox box(QMessageBox::Icon::Information, tr("提示"), tr("应用成功"), QMessageBox::Ok, nullptr); auto btn = box.button(QMessageBox::Ok); - // btn->setFixedSize(80, 40); + btn->setFixedSize(80, 40); box.exec(); } diff --git a/QtUI.pro b/QtUI.pro index 10e99ac..1c9f069 100644 --- a/QtUI.pro +++ b/QtUI.pro @@ -123,6 +123,7 @@ HEADERS += Public.h \ scene/pictextitem.h \ scene/picscene.h \ scene/myview.h \ + scene/PicSceneLoader.h \ scene/ItemGeneralSettings.h \ scene/DateReplaceEditor.h \ DialogSaveFile.h \ @@ -277,6 +278,7 @@ SOURCES +=\ scene/pictextitem.cpp \ scene/picscene.cpp \ scene/myview.cpp \ + scene/PicSceneLoader.cpp \ scene/ItemGeneralSettings.cpp \ scene/ScheduleShiftsEditor.cpp \ scene/PicScheduleShiftItem.cpp \ diff --git a/mainwidget.cpp b/mainwidget.cpp index 7ea559e..4d8dfb4 100644 --- a/mainwidget.cpp +++ b/mainwidget.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -507,10 +508,10 @@ void MainWidget::generateCharRamData() } -QRect MainWidget::variableItemsUpdate() +QList MainWidget::variableItemsUpdate() { if(!pPicScene) { - return QRect(); + return QList(); } int totalOfProcessedDots = 0; @@ -518,7 +519,7 @@ QRect MainWidget::variableItemsUpdate() int nbInvaliedDatetimePreview = 0; int nbClipDatetimePreview = 0; - QRect updateArea = {0, 0, 0, 0}; + QList updateAreas; auto items = pPicScene->items(); for(auto i : items) { @@ -594,10 +595,36 @@ QRect MainWidget::variableItemsUpdate() totalOfProcessedDots += imageToPrintData(img, (int)itemRect.left(), (int)itemRect.top()); - updateArea = updateArea.united(itemRect); + updateAreas.append(itemRect); } - return updateArea; + if(updateAreas.isEmpty()) + return updateAreas; + + // 把 updateAreas 里 x 轴相交或相连的矩形合并,避免某些区域重复更新而导致的串口资源浪费 + std::sort(updateAreas.begin(), updateAreas.end(), [](const QRect &a, const QRect &b) { + if (a.left() != b.left()) + return a.left() < b.left(); + return a.right() < b.right(); + }); + + QList mergedAreas; + mergedAreas.append(updateAreas.first()); + for (int i = 1; i < updateAreas.size(); ++i) { + QRect current = updateAreas.at(i); + QRect &last = mergedAreas.last(); + if (last.right() + 1 >= current.left()) { + int left = qMin(last.left(), current.left()); + int right = qMax(last.right(), current.right()); + int top = qMin(last.top(), current.top()); + int bottom = qMax(last.bottom(), current.bottom()); + last = QRect(QPoint(left, top), QPoint(right, bottom)); + } else { + mergedAreas.append(current); + } + } + + return mergedAreas; } int MainWidget::imageToPrintData(QImage &image, int startX, int startY) @@ -619,7 +646,7 @@ int MainWidget::imageToPrintData(QImage &image, int startX, int startY) unsigned char c = 0; int hStart = startY; - c = dat[(wStart)*5 + (hStart)/8]; + c = dat[wStart * MAX_PRINT_ROW_BYTE_NUM + (hStart) / 8]; for(int k = 0; k < height; k++) { @@ -634,14 +661,14 @@ int MainWidget::imageToPrintData(QImage &image, int startX, int startY) } if(hStart % 8 == 7) { - dat[(wStart)*5 + (hStart)/8] = c; - c = dat[(wStart)*5 + (hStart + 1)/8]; + dat[wStart * MAX_PRINT_ROW_BYTE_NUM + (hStart) / 8] = c; + c = dat[wStart * MAX_PRINT_ROW_BYTE_NUM + (hStart + 1) / 8]; ++totalOfProcessedDots; } hStart++; } - dat[(wStart)*5 + (hStart)/8] = c; + dat[wStart * MAX_PRINT_ROW_BYTE_NUM + (hStart) / 8] = c; wStart++; totalOfProcessedDots++; } @@ -1348,7 +1375,7 @@ void MainWidget::slt_setNum() void MainWidget::slt_clearCnt() { if (sysPara) { - sysPara->devOp->clearProductCnt(3 | 0x10);// 重新计米 + sysPara->devOp->clearProductCnt(1);//当前产品计数器立即清零 ui.labelProductCnt->setText("0"); // SendPrintDataToFpga(0); } diff --git a/mainwidget.h b/mainwidget.h index 47316ea..6ab7b43 100644 --- a/mainwidget.h +++ b/mainwidget.h @@ -59,7 +59,7 @@ public: * @return 返回需要更新的区域 * @remark 判断返回值用于决定是否SendPrintDataToFpga */ - QRect variableItemsUpdate(); + QList variableItemsUpdate(); /** * @brief 向FPGA print 数据缓冲区写入image diff --git a/scene/PicSceneLoader.cpp b/scene/PicSceneLoader.cpp new file mode 100644 index 0000000..fdb865b --- /dev/null +++ b/scene/PicSceneLoader.cpp @@ -0,0 +1,188 @@ +#include "PicSceneLoader.h" +#include "picscene.h" +#include "pictextitem.h" +#include "PicImageItem.h" +#include "PicDateItem.h" +#include "PicScheduleShiftItem.h" +#include "piccodeitem.h" +#include "PicCounterItem.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +PicTextItem* createSceneItem(SourceType sourceType) +{ + switch (sourceType) { + case IMAGE: + return new PicImageItem(); + case DATETIME: + return new PicDateItem(); + case SCHEDULE_SHIFT: + return new PicScheduleShiftItem(); + case CODE: + return new PicCodeItem(); + case COUNTER: + return new PicCounterItem(); + case TEXT: + case UNKNOWN: + default: + return new PicTextItem(nullptr, nullptr, sourceType); + } +} + +SourceType sourceTypeFromAttrs(const QXmlStreamAttributes& attrs) +{ + if (!attrs.hasAttribute("sourceType")) { + return SourceType::UNKNOWN; + } + + bool ok = false; + int value = attrs.value("sourceType").toInt(&ok); + if (!ok) { + return SourceType::UNKNOWN; + } + + if (value < SourceType::UNKNOWN || value > SourceType::COUNTER) { + return SourceType::UNKNOWN; + } + + return static_cast(value); +} + +bool parseVbFileElement(QXmlStreamReader& reader, PicScene* scene) +{ + float posX = 0.0f; + float posY = 0.0f; + bool condition = false; + int catchStartValue = -1; + int catchValue = -1; + QXmlStreamAttributes itemAttrs; + QString htmlCData; + + while (!reader.atEnd()) { + QXmlStreamReader::TokenType token = reader.readNext(); + if (token == QXmlStreamReader::StartElement) { + const QString elementName = reader.name().toString(); + if (elementName == "pointer_x") { + posX = reader.readElementText().toDouble(); + } else if (elementName == "pointer_y") { + posY = reader.readElementText().toDouble(); + } else if (elementName == "Condition") { + condition = reader.readElementText().toInt() != 0; + } else if (elementName == "CatchStartValue") { + catchStartValue = reader.readElementText().toInt(); + } else if (elementName == "CatchValue") { + catchValue = reader.readElementText().toInt(); + } else if (elementName == "itemAttrs") { + itemAttrs = reader.attributes(); + reader.skipCurrentElement(); + } else if (elementName == "html_src") { + reader.skipCurrentElement(); + } else { + reader.skipCurrentElement(); + } + } else if (reader.isCDATA()) { + htmlCData += reader.text().toString(); + } else if (token == QXmlStreamReader::EndElement && reader.name() == "VBfile") { + break; + } + } + + SourceType sourceType = sourceTypeFromAttrs(itemAttrs); + PicTextItem* item = createSceneItem(sourceType); + if (!item) { + qWarning() << "PicSceneLoader: skip invalid VBfile item"; + return true; + } + + item->setAttrs(itemAttrs); + item->setPos(posX, posY); + item->SpecialConditions = condition; + item->CatchCnt1StartValue = catchStartValue; + item->CatchCnt1CurrValue = catchValue; + + if (!htmlCData.isEmpty()) { + item->setHtml(htmlCData); + } + + scene->addItem(item); + return true; +} + +} // namespace + +namespace PicSceneLoader { + +PicScene* createSceneFromFile(const QString& xmlFilename) +{ + QFile file(xmlFilename); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "PicSceneLoader: failed to open" << xmlFilename << file.errorString(); + return nullptr; + } + + QXmlStreamReader reader(&file); + PicScene* scene = new PicScene(); + + while (!reader.atEnd()) { + reader.readNext(); + if (reader.isStartElement() && reader.name() == "VBfiles") { + while (reader.readNextStartElement()) { + if (reader.name() == "VBfile") { + if (!parseVbFileElement(reader, scene)) { + delete scene; + return nullptr; + } + } else { + reader.skipCurrentElement(); + } + } + } + } + + if (reader.hasError()) { + qWarning() << "PicSceneLoader: XML parse error" << reader.errorString() + << "at" << reader.lineNumber() << ":" << reader.columnNumber(); + delete scene; + return nullptr; + } + + return scene; +} + +QImage previewSceneFromFile(const QString &xmlFilename) +{ + QScopedPointer scene(createSceneFromFile(xmlFilename)); + if (!scene) { + return QImage(); + } + + QRectF contentRect = scene->itemsBoundingRect(); + if (!contentRect.isValid() || contentRect.isEmpty()) { + return QImage(1, 1, QImage::Format_ARGB32_Premultiplied); + } + + QSize imageSize(qMax(1, int(std::ceil(contentRect.width()))), + qMax(1, int(std::ceil(contentRect.height())))); + QImage image(imageSize, QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::transparent); + + QPainter painter(&image); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setRenderHint(QPainter::SmoothPixmapTransform, true); + + scene->render(&painter, QRectF(QPointF(0, 0), imageSize), contentRect); + painter.end(); + + return image; +} + +} // namespace PicSceneLoader diff --git a/scene/PicSceneLoader.h b/scene/PicSceneLoader.h new file mode 100644 index 0000000..8f5b6a3 --- /dev/null +++ b/scene/PicSceneLoader.h @@ -0,0 +1,17 @@ +#ifndef PICSCENELOADER_H +#define PICSCENELOADER_H + +#include +#include + +class PicScene; + +namespace PicSceneLoader { + +PicScene* createSceneFromFile(const QString& xmlFilename); + +QImage previewSceneFromFile(const QString& xmlFilename); + +} // namespace PicSceneLoader + +#endif // PICSCENELOADER_H diff --git a/scene/myview.cpp b/scene/myview.cpp index 685e3a7..0e7efa4 100644 --- a/scene/myview.cpp +++ b/scene/myview.cpp @@ -1,5 +1,7 @@ #include "myview.h" #include +#include +#include #include "picscene.h" #include MyView::MyView(QWidget *parent) : @@ -44,6 +46,63 @@ void MyView::ZoomIn(void) //// rotate(90); //视图旋转顺时针90度 //} +void MyView::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) { + m_isPressing = true; + const QPointF scenePos = mapToScene(event->pos()); + const bool hasSelectedItem = scene() && !scene()->selectedItems().isEmpty(); + m_pressOnItem = hasSelectedItem || (scene() && scene()->itemAt(scenePos, transform()) != nullptr); + m_lastPanPoint = event->pos(); + } + + QGraphicsView::mousePressEvent(event); +} + +void MyView::mouseMoveEvent(QMouseEvent *event) +{ + if (m_isPressing && !m_pressOnItem && !m_isPanning) { + const bool noSelectedItems = scene() && scene()->selectedItems().isEmpty(); + if (noSelectedItems) { + QPoint delta = event->pos() - m_lastPanPoint; + if (std::abs(delta.x()) >= MyView::PanStartDistance && std::abs(delta.x()) > std::abs(delta.y())) { + m_isPanning = true; + setCursor(Qt::ClosedHandCursor); + } + } + } + + if (m_isPanning) { + int deltaX = event->pos().x() - m_lastPanPoint.x(); + if (deltaX != 0) { + horizontalScrollBar()->setValue(horizontalScrollBar()->value() - deltaX); + m_lastPanPoint = event->pos(); + } + event->accept(); + return; + } + + QGraphicsView::mouseMoveEvent(event); +} + +void MyView::mouseReleaseEvent(QMouseEvent *event) +{ + if (m_isPanning && event->button() == Qt::LeftButton) { + m_isPanning = false; + m_isPressing = false; + setCursor(Qt::ArrowCursor); + event->accept(); + return; + } + + if (event->button() == Qt::LeftButton) { + m_isPressing = false; + m_pressOnItem = false; + } + + QGraphicsView::mouseReleaseEvent(event); +} + void MyView::keyPressEvent(QKeyEvent *event) { //event->accept(); diff --git a/scene/myview.h b/scene/myview.h index 35f6be0..eb4d65f 100644 --- a/scene/myview.h +++ b/scene/myview.h @@ -14,15 +14,21 @@ public: //char getzoomRatio(){return zoomRatio;} private: char zoomRatio; + bool m_isPanning = false; + bool m_isPressing = false; + bool m_pressOnItem = false; + QPoint m_lastPanPoint; + static constexpr int PanStartDistance = 8; signals: public slots: protected : -// void wheelEvent(QWheelEvent *event); -// void mousePressEvent(QMouseEvent *event); - void keyPressEvent(QKeyEvent *event); + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; };