抽离场景打开逻辑、添加编辑界面的左右拖动功能

This commit is contained in:
2026-07-16 11:04:12 +08:00
parent 570f359339
commit 808a38628e
10 changed files with 330 additions and 27 deletions
+6 -2
View File
@@ -16,6 +16,7 @@
#include"myinclude.h" #include"myinclude.h"
#include<iostream> #include<iostream>
#include<string> #include<string>
#include "scene/PicSceneLoader.h"
DialogFileOperation::DialogFileOperation(QWidget *parent) : DialogFileOperation::DialogFileOperation(QWidget *parent) :
QDialog(parent), QDialog(parent),
@@ -78,8 +79,11 @@ void DialogFileOperation::on_listViewFile_entered(const QModelIndex &index)
} }
else if(filePath.endsWith(".xml")) else if(filePath.endsWith(".xml"))
{ {
emit createSceneImage(filePath); QImage previewImg = PicSceneLoader::previewSceneFromFile(filePath);
ui->textEditView->setHtml(QString("<img src='%1'/>").arg("./printSceneView.png")); ui->textEditView->clear();
auto cursor = ui->textEditView->textCursor();
cursor.insertImage(previewImg);
ui->textEditView->setTextCursor(cursor);
} }
else { else {
QFile file(filePath); QFile file(filePath);
+9 -9
View File
@@ -1008,8 +1008,15 @@ void InkJetPrinter::timerHandler(void){
} }
// byons: 时间类型图元更新 @2026年4月11日 // byons: 时间类型图元更新 @2026年4月11日
auto updateArea = m_MainWidget->variableItemsUpdate(); // byons: 变量类图元现在优化为局部更新,避免每次都要把整个打印内容发送给FPGA,现在只发送被更新的列区间 2026年7月16日
if (!updateArea.isNull()) { 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 QElapsedTimer bnsTimer;
// static int toogleCount = 0; // static int toogleCount = 0;
@@ -1019,15 +1026,8 @@ void InkJetPrinter::timerHandler(void){
// qDebug() << (QString("timeHandler avg elapsed: %1 s").arg(elapsed / qreal(toogleCount) / 1000.0)); // qDebug() << (QString("timeHandler avg elapsed: %1 s").arg(elapsed / qreal(toogleCount) / 1000.0));
// toogleCount = 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) { // if (modbus->getModbusStatus() == 1) {
// refreshModbusStatus(); // refreshModbusStatus();
+1 -1
View File
@@ -649,7 +649,7 @@ void PrintSetting::applyPrintSettingsToSysPara(bool showTip)
if(res != -1 && showTip) { if(res != -1 && showTip) {
QMessageBox box(QMessageBox::Icon::Information, tr("提示"), tr("应用成功"), QMessageBox::Ok, nullptr); QMessageBox box(QMessageBox::Icon::Information, tr("提示"), tr("应用成功"), QMessageBox::Ok, nullptr);
auto btn = box.button(QMessageBox::Ok); auto btn = box.button(QMessageBox::Ok);
// btn->setFixedSize(80, 40); btn->setFixedSize(80, 40);
box.exec(); box.exec();
} }
+2
View File
@@ -123,6 +123,7 @@ HEADERS += Public.h \
scene/pictextitem.h \ scene/pictextitem.h \
scene/picscene.h \ scene/picscene.h \
scene/myview.h \ scene/myview.h \
scene/PicSceneLoader.h \
scene/ItemGeneralSettings.h \ scene/ItemGeneralSettings.h \
scene/DateReplaceEditor.h \ scene/DateReplaceEditor.h \
DialogSaveFile.h \ DialogSaveFile.h \
@@ -277,6 +278,7 @@ SOURCES +=\
scene/pictextitem.cpp \ scene/pictextitem.cpp \
scene/picscene.cpp \ scene/picscene.cpp \
scene/myview.cpp \ scene/myview.cpp \
scene/PicSceneLoader.cpp \
scene/ItemGeneralSettings.cpp \ scene/ItemGeneralSettings.cpp \
scene/ScheduleShiftsEditor.cpp \ scene/ScheduleShiftsEditor.cpp \
scene/PicScheduleShiftItem.cpp \ scene/PicScheduleShiftItem.cpp \
+37 -10
View File
@@ -10,6 +10,7 @@
#include <QRgb> #include <QRgb>
#include <QDebug> #include <QDebug>
#include <QScrollBar> #include <QScrollBar>
#include <algorithm>
#include <QFontMetrics> #include <QFontMetrics>
#include <QChar> #include <QChar>
#include <stdlib.h> #include <stdlib.h>
@@ -507,10 +508,10 @@ void MainWidget::generateCharRamData()
} }
QRect MainWidget::variableItemsUpdate() QList<QRect> MainWidget::variableItemsUpdate()
{ {
if(!pPicScene) { if(!pPicScene) {
return QRect(); return QList<QRect>();
} }
int totalOfProcessedDots = 0; int totalOfProcessedDots = 0;
@@ -518,7 +519,7 @@ QRect MainWidget::variableItemsUpdate()
int nbInvaliedDatetimePreview = 0; int nbInvaliedDatetimePreview = 0;
int nbClipDatetimePreview = 0; int nbClipDatetimePreview = 0;
QRect updateArea = {0, 0, 0, 0}; QList<QRect> updateAreas;
auto items = pPicScene->items(); auto items = pPicScene->items();
for(auto i : items) { for(auto i : items) {
@@ -594,10 +595,36 @@ QRect MainWidget::variableItemsUpdate()
totalOfProcessedDots += imageToPrintData(img, (int)itemRect.left(), (int)itemRect.top()); 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<QRect> 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) 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; unsigned char c = 0;
int hStart = startY; 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++) for(int k = 0; k < height; k++)
{ {
@@ -634,14 +661,14 @@ int MainWidget::imageToPrintData(QImage &image, int startX, int startY)
} }
if(hStart % 8 == 7) { if(hStart % 8 == 7) {
dat[(wStart)*5 + (hStart)/8] = c; dat[wStart * MAX_PRINT_ROW_BYTE_NUM + (hStart) / 8] = c;
c = dat[(wStart)*5 + (hStart + 1)/8]; c = dat[wStart * MAX_PRINT_ROW_BYTE_NUM + (hStart + 1) / 8];
++totalOfProcessedDots; ++totalOfProcessedDots;
} }
hStart++; hStart++;
} }
dat[(wStart)*5 + (hStart)/8] = c; dat[wStart * MAX_PRINT_ROW_BYTE_NUM + (hStart) / 8] = c;
wStart++; wStart++;
totalOfProcessedDots++; totalOfProcessedDots++;
} }
@@ -1348,7 +1375,7 @@ void MainWidget::slt_setNum()
void MainWidget::slt_clearCnt() void MainWidget::slt_clearCnt()
{ {
if (sysPara) { if (sysPara) {
sysPara->devOp->clearProductCnt(3 | 0x10);// 重新计米 sysPara->devOp->clearProductCnt(1);//当前产品计数器立即清零
ui.labelProductCnt->setText("0"); ui.labelProductCnt->setText("0");
// SendPrintDataToFpga(0); // SendPrintDataToFpga(0);
} }
+1 -1
View File
@@ -59,7 +59,7 @@ public:
* @return 返回需要更新的区域 * @return 返回需要更新的区域
* @remark 判断返回值用于决定是否SendPrintDataToFpga * @remark 判断返回值用于决定是否SendPrintDataToFpga
*/ */
QRect variableItemsUpdate(); QList<QRect> variableItemsUpdate();
/** /**
* @brief 向FPGA print 数据缓冲区写入image * @brief 向FPGA print 数据缓冲区写入image
+188
View File
@@ -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 <QFile>
#include <QXmlStreamReader>
#include <QXmlStreamAttributes>
#include <QDebug>
#include <QImage>
#include <QPainter>
#include <QScopedPointer>
#include <cmath>
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<SourceType>(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<PicScene> 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<int>(1, int(std::ceil(contentRect.width()))),
qMax<int>(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
+17
View File
@@ -0,0 +1,17 @@
#ifndef PICSCENELOADER_H
#define PICSCENELOADER_H
#include <QImage>
#include <QString>
class PicScene;
namespace PicSceneLoader {
PicScene* createSceneFromFile(const QString& xmlFilename);
QImage previewSceneFromFile(const QString& xmlFilename);
} // namespace PicSceneLoader
#endif // PICSCENELOADER_H
+59
View File
@@ -1,5 +1,7 @@
#include "myview.h" #include "myview.h"
#include <QWheelEvent> #include <QWheelEvent>
#include <QMouseEvent>
#include <QScrollBar>
#include "picscene.h" #include "picscene.h"
#include <QDebug> #include <QDebug>
MyView::MyView(QWidget *parent) : MyView::MyView(QWidget *parent) :
@@ -44,6 +46,63 @@ void MyView::ZoomIn(void)
//// rotate(90); //视图旋转顺时针90度 //// 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) void MyView::keyPressEvent(QKeyEvent *event)
{ {
//event->accept(); //event->accept();
+9 -3
View File
@@ -14,15 +14,21 @@ public:
//char getzoomRatio(){return zoomRatio;} //char getzoomRatio(){return zoomRatio;}
private: private:
char zoomRatio; char zoomRatio;
bool m_isPanning = false;
bool m_isPressing = false;
bool m_pressOnItem = false;
QPoint m_lastPanPoint;
static constexpr int PanStartDistance = 8;
signals: signals:
public slots: public slots:
protected : protected :
// void wheelEvent(QWheelEvent *event); void mousePressEvent(QMouseEvent *event) override;
// void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event) override;
void keyPressEvent(QKeyEvent *event); void mouseReleaseEvent(QMouseEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
}; };