活动介绍

setSceneRect

时间: 2025-06-29 10:25:39 浏览: 127
### 如何正确使用 `setSceneRect` 函数 在 Qt 图形视图框架中,`QGraphicsView` 和 `QGraphicsScene` 是两个核心组件。为了更好地管理和显示图形项,合理设置场景矩形非常重要。 #### 设置场景矩形的作用 通过调用 `setSceneRect()` 方法可以限定场景的逻辑坐标范围[^1]。这不仅有助于提高渲染效率,还能确保当试图移动超出此边界时不会无限扩展场景尺寸。具体来说: - 场景中的所有操作都将被限制在这个矩形范围内; - 视图自动调整其可视区域以适应这个矩形; - 如果不显式设定,则默认值可能无法满足特定应用需求; #### 使用示例 下面是一个简单的例子来展示如何配置并利用 `setSceneRect`: ```cpp #include <QApplication> #include <QGraphicsView> #include <QGraphicsScene> int main(int argc, char *argv[]) { QApplication app(argc, argv); // 创建一个新的图形场景对象 QGraphicsScene scene; // 定义场景矩形,并将其应用于场景 QRectF rect(-50,-50,100,100); scene.setSceneRect(rect); // 添加一个矩形到场景中作为测试项目 scene.addRect(rect,QPen(Qt::black), QBrush(Qt::yellow)); // 初始化视图并将场景关联起来 QGraphicsView view(&scene); // 显示窗口 view.show(); return app.exec(); } ``` 上述代码片段展示了如何创建一个带有固定大小矩形区域的场景,并将该矩形添加至场景内以便可视化验证效果[^4]。 #### 关键点说明 - **参数传递**: `setSceneRect(const QRectF &rect)` 接受一个浮点型矩形 (`QRectF`) 参数,允许更精确地控制位置和大小。 - **性能优化**: 设定合理的 `sceneRect` 可防止不必要的计算资源浪费,特别是在处理大量图形元素的应用程序里尤为重要[^3].
阅读全文

相关推荐

#include "AutoCuttingWidget.h" #include "AutoCuttingAlarmTable.h" #include "Component/LightLabel/lightLabel.h" #include "Component/QFlightInstruments/LayoutSquare.hpp" #include "Component/LineRuler/LineRuler.h" #include "Component/LineRuler/RulerWidget.h" #include "AutoCuttingActionDBManager.h" #include "CircuitBaseScene.h" #include "GraphicElementManage.h" #include <QDebug> #include <SystemSetting.h> AutoCuttingWidget::AutoCuttingWidget(QWidget* parent) : QWidget(parent) , ui(new Ui::AutoCuttingWidgetClass()) { ui->setupUi(this); initLineRuler(); initAmpHistoryLineCharts(); initAlarmMessageTable(); initRemotePanel(); initPFDParameter(); initRemoteConnectParam(); initCutMonitor(); initDrawCutPathViewer(); m_autoCutXmlFilePath = QCoreApplication::applicationDirPath() + "/autoCutXML/"; } AutoCuttingWidget::~AutoCuttingWidget() { if (m_updateCutMonitorTimer) { m_updateCutMonitorTimer->stop(); //delete m_updateCutMonitorTimer; m_updateCutMonitorTimer = nullptr; } delete ui; } void AutoCuttingWidget::on_pushButton_drawPath_clicked() { ui->stackedWidget_autocut->setCurrentWidget(ui->page_cutPath); m_curView->enbaleDrawLine(true); } void AutoCuttingWidget::on_pushButton_clearCutPath_clicked() { QList<QGraphicsItem*> itemList = m_curView->items(); for (QGraphicsItem* item : itemList) { m_curView->scene()->removeItem(item); } } void AutoCuttingWidget::on_pushButton_startAuto_clicked() { m_updateCutMonitorTimer->stop(); resetAutoCuttingDataList(); m_updateCutMonitorTimer->start(hxcommon::SystemSetting::autoCutRefreshInterval); ui->stackedWidget_autocut->setCurrentWidget(ui->page_cutMonitor); } void AutoCuttingWidget::on_pushButton_stopAuto_clicked() { m_updateCutMonitorTimer->stop(); } void AutoCuttingWidget::on_pushButton_systemVoltage_clicked() { qDebug() << "on_pushButton_systemVoltage_clicked"; ui->stackedWidget->setCurrentIndex(0); } void AutoCuttingWidget::on_pushButton_pumpCurrent_clicked() { qDebug() << "on_pushButton_pumpCurrent_clicked"; ui->stackedWidget->setCurrentIndex(1); } void AutoCuttingWidget::on_pushButton_cutLowCurrent_clicked() { qDebug() << "on_pushButton_cutLowCurrent_clicked"; ui->stackedWidget->setCurrentIndex(2); } void AutoCuttingWidget::on_pushButton_cutHighCurrent_clicked() { qDebug() << "on_pushButton_cutHighCurrent_clicked"; ui->stackedWidget->setCurrentIndex(3); } void AutoCuttingWidget::on_pushButton_memoryStart_clicked() { QDateTime time = QDateTime::currentDateTime(); QString dateTime = time.toString("MM-dd-hh-mm"); QString pathname = m_autoCutXmlFilePath + QStringLiteral("自动截割路径_%1.xml").arg(dateTime); m_autoCutFileSavePath = QFileDialog::getSaveFileName(this, QStringLiteral("保存自动截割路径"), pathname, "Xml(*.xml)"); } void AutoCuttingWidget::on_pushButton_memoryStop_clicked() { QString savePath = m_autoCutFileSavePath; if (savePath.isEmpty()) { QDateTime time = QDateTime::currentDateTime(); QString dateTime = time.toString("MM-dd-hh-mm"); savePath = m_autoCutXmlFilePath + QStringLiteral("自动截割路径_%1.xml").arg(dateTime); } if (m_graphicElementManager.saveCurrentPage(savePath)) { emit showResponseMessage(hxcommon::NotifyType::Notify_Type_Success,QStringLiteral("自动截割路径保存成功!")); } else { emit showResponseMessage(hxcommon::NotifyType::Notify_Type_Error, QStringLiteral("保存失败!")); } } void AutoCuttingWidget::on_pushButton_memoryModel_clicked() { QString fileName = QFileDialog::getOpenFileName(this, QStringLiteral("请打开自动截割路径文件"), m_autoCutFileSavePath, "Xml(*.xml)"); QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { qDebug() << "Open failed"; return; } m_graphicElementManager.openPage(file); } void AutoCuttingWidget::initAlarmMessageTable() { m_alarmMessageTable = new AutoCuttingAlarmTable(ui->widget_abnormalInfo); QLayout* alarmMessageTableLayout = ui->widget_abnormalInfo->layout(); if (alarmMessageTableLayout) { // 如果 layout 是 QVBoxLayout 类型,添加控件 QVBoxLayout* vboxLayout = qobject_cast<QVBoxLayout*>(alarmMessageTableLayout); if (vboxLayout) { vboxLayout->addWidget(m_alarmMessageTable); } } } void AutoCuttingWidget::initRemotePanel() { // 创建 4x4 的网格布局 m_remotePanelLayout = new QGridLayout(ui->widget_remotePanel); ui->widget_remotePanel->setLayout(m_remotePanelLayout); // 定义 4x4 的内容 QStringList labels = { QStringLiteral("截割头伸"), QStringLiteral("铲板升"), QStringLiteral("一运正转"), QStringLiteral("左后退"), QStringLiteral("截割头缩"), QStringLiteral("铲板降"), QStringLiteral("一运反转"), QStringLiteral("右后退"), QStringLiteral("左前进"), QStringLiteral("后支撑升"), QStringLiteral("截割左"), QStringLiteral("星轮正转"), QStringLiteral("右前进"), QStringLiteral("后支撑降"), QStringLiteral("截割右"), QStringLiteral("星轮反转") }; // 创建并添加 lightLabel 到布局 int index = 0; for (int row = 0; row < 4; ++row) { for (int col = 0; col < 4; ++col) { lightLabel* label = new lightLabel(ui->widget_remotePanel); label->setLabelText(labels[index++]); // 设置内容 label->setLightPointStep(0); m_remotePanelLayout->addWidget(label, row, col); // 添加到网格布局 } } } void AutoCuttingWidget::initPFDParameter() { LayoutSquare* m_layoutSq = new LayoutSquare(this); m_layoutSq->setContentsMargins(0, 0, 0, 0); m_layoutSq->addWidget(ui->framePFD); } void AutoCuttingWidget::initRemoteConnectParam() { //m_remoteConnectLayout = new QGridLayout(ui->widget_remoteConnectInfo); //ui->widget_remoteConnectInfo->setLayout(m_remoteConnectLayout); //QStringList labels = { // QStringLiteral("遥控在线"), QStringLiteral("油泵启动"), QStringLiteral("截割启动"), QStringLiteral("一运启动"), // QStringLiteral("二运启动"), QStringLiteral("皮带启动"), QStringLiteral("星轮启动"), QStringLiteral("人员误入") //}; //int index = 0; //for (int row = 0; row < 2; ++row) { // for (int col = 0; col < 4; ++col) { // lightLabel* label = new lightLabel(ui->widget_remoteConnectInfo); // label->setLabelText(labels[index++]); // 设置内容 // label->setLightPointStep(0); // m_remoteConnectLayout->addWidget(label, row, col); // 添加到网格布局 // } //} // 创建 4x4 的网格布局 //m_remoteConnectLayout = new QGridLayout(ui->widget_remoteConnectInfo); //ui->widget_remoteConnectInfo->setLayout(m_remoteConnectLayout); //// 定义 4x4 的内容 //QStringList labels = { // QStringLiteral("截割头伸"), QStringLiteral("铲板升"), QStringLiteral("一运正转"), QStringLiteral("左后退"), // QStringLiteral("截割头缩"), QStringLiteral("铲板降"), QStringLiteral("一运反转"), QStringLiteral("右后退"), // QStringLiteral("左前进"), QStringLiteral("后支撑升"), QStringLiteral("截割左"), QStringLiteral("星轮正转"), // QStringLiteral("右前进"), QStringLiteral("后支撑降"), QStringLiteral("截割右"), QStringLiteral("星轮反转") //}; //// 创建并添加 lightLabel 到布局 //int index = 0; //for (int row = 0; row < 4; ++row) { // for (int col = 0; col < 4; ++col) { // lightLabel* label = new lightLabel(ui->widget_remoteConnectInfo); // label->setLabelText(labels[index++]); // 设置内容 // label->setLightPointStep(0); // m_remoteConnectLayout->addWidget(label, row, col); // 添加到网格布局 // } //} } void AutoCuttingWidget::initLineRuler() { // 创建 RulerWidget 实例,方向为垂直 RulerWidget* verticalRuler = new RulerWidget(Qt::Vertical, this); // 检查 widget_verticalRuler 是否已有布局 QLayout* verticallayout = ui->widget_verticalRuler->layout(); if (!verticallayout) { // 如果没有布局,创建一个 QVBoxLayout verticallayout = new QVBoxLayout(ui->widget_verticalRuler); ui->widget_verticalRuler->setLayout(verticallayout); } // 设置布局的间隔和边距为 0 verticallayout->setSpacing(0); verticallayout->setContentsMargins(0, 0, 0, 0); // 将 RulerWidget 添加到布局中 verticallayout->addWidget(verticalRuler); // 创建 RulerWidget 实例,方向为垂直 RulerWidget* horizontalRuler = new RulerWidget(Qt::Horizontal, this); // 检查 widget_verticalRuler 是否已有布局 QLayout* horizontalLayout = ui->widget_horizontalRuler->layout(); if (!horizontalLayout) { // 如果没有布局,创建一个 QVBoxLayout horizontalLayout = new QVBoxLayout(ui->widget_horizontalRuler); ui->widget_verticalRuler->setLayout(horizontalLayout); } // 设置布局的间隔和边距为 0 horizontalLayout->setSpacing(0); horizontalLayout->setContentsMargins(0, 0, 0, 0); // 将 RulerWidget 添加到布局中 horizontalLayout->addWidget(horizontalRuler); } void AutoCuttingWidget::initAmpHistoryLineCharts() { m_lineChartSystemVoltage = new AmpHistoryLineChart(ui->page_systemVoltage); m_lineChartPumpAmp = new AmpHistoryLineChart(ui->page_pumpCurrent); m_lineChartLowCutAmp = new AmpHistoryLineChart(ui->page_cutLowCurrent); m_lineChartHighCutAmp = new AmpHistoryLineChart(ui->page_cutHighCurrent); // 获取 ui 中的布局,并确保布局充满空间 QLayout* layoutSystemVoltage = ui->page_systemVoltage->layout(); if (layoutSystemVoltage) { // 如果 layout 是 QVBoxLayout 类型,添加控件 QVBoxLayout* vboxLayoutSystemVoltage = qobject_cast<QVBoxLayout*>(layoutSystemVoltage); if (vboxLayoutSystemVoltage) { vboxLayoutSystemVoltage->addWidget(m_lineChartSystemVoltage); } } QLayout* layoutPump = ui->page_pumpCurrent->layout(); if (layoutPump) { QVBoxLayout* vboxLayoutPump = qobject_cast<QVBoxLayout*>(layoutPump); if (vboxLayoutPump) { vboxLayoutPump->addWidget(m_lineChartPumpAmp); } } QLayout* layoutLowCut = ui->page_cutLowCurrent->layout(); if (layoutLowCut) { QVBoxLayout* vboxLayoutLowCut = qobject_cast<QVBoxLayout*>(layoutLowCut); if (vboxLayoutLowCut) { vboxLayoutLowCut->addWidget(m_lineChartLowCutAmp); } } QLayout* layoutHighCut = ui->page_cutHighCurrent->layout(); if (layoutHighCut) { QVBoxLayout* vboxLayoutHighCut = qobject_cast<QVBoxLayout*>(layoutHighCut); if (vboxLayoutHighCut) { vboxLayoutHighCut->addWidget(m_lineChartHighCutAmp); } } m_lineChartPumpAmp->setYAxisRange(0, 100); m_lineChartLowCutAmp->setYAxisRange(0, 100); m_lineChartHighCutAmp->setYAxisRange(0, 100); // TODO:假设数据点,替换为实时数据 QList<QPointF> list; QDateTime currentTime = QDateTime::currentDateTime(); for (int i = 0; i < 120; ++i) { // 120个数据点,代表最近两个小时 list.append(QPointF(currentTime.addSecs(-i * 60).toMSecsSinceEpoch(), QRandomGenerator::global()->bounded(10, 14))); } m_lineChartPumpAmp->setLineData(list); m_lineChartLowCutAmp->setLineData(list); m_lineChartHighCutAmp->setLineData(list); } void AutoCuttingWidget::initCutMonitor() { m_autoCuttingProcessor = new AutoCuttingProcessor(this); hxDataBaseManager::AutoCuttingActionDBManager dbManager; QList<hxcommon::AutoCuttingAction*> list = dbManager.getActionList(); m_autoCuttingProcessor->setActionList(list); m_autoCuttingProcessor->doWork(); m_updateCutMonitorTimer = new QTimer(); connect(m_updateCutMonitorTimer, &QTimer::timeout, this, &AutoCuttingWidget::testDrawCutterMonitor); m_cutter = new QGraphicsPixmapItem(QPixmap(":/mainwindow/Resource/AutoCutting/cutter.png").scaled(60, 60, Qt::KeepAspectRatio)); } void AutoCuttingWidget::resetAutoCuttingDataList() { if (m_updateCutMonitorTimer) { m_updateCutMonitorTimer->stop();//先停止可能正在进行的 } // 重置GraphicsScene int width = ui->widget_cutterMonitorPainter->width(); int height = ui->widget_cutterMonitorPainter->height(); int rowPointCount = hxcommon::SystemSetting::autoCutRowTakeTime / hxcommon::SystemSetting::autoCutRefreshInterval;//一行多少点 int columnPointCount = hxcommon::SystemSetting::autoCutColumnTakeTime / hxcommon::SystemSetting::autoCutRefreshInterval;//一列多少点 int columnSplitPointCount = columnPointCount / hxcommon::SystemSetting::autoCutColumnSplit;//向上的每段多少点 double wItem = 540.0 / rowPointCount;//SceneRect尺寸600 - 截割头60 double hItem = 360.0 / columnPointCount;//SceneRect尺寸420 - 截割头60 ui->graphicsViewCutterMonitor->setGeometry(width / 2 - 310, height / 2 - 220, 620, 440);//居中,因为带20边框 QGraphicsScene* scene = ui->graphicsViewCutterMonitor->scene(); if (!scene) { scene = new QGraphicsScene(this); ui->graphicsViewCutterMonitor->setScene(scene); } scene->setSceneRect(0, 0, 600, 420); // 禁用滚动条 ui->graphicsViewCutterMonitor->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->graphicsViewCutterMonitor->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // 禁用鼠标拖拽滚动 ui->graphicsViewCutterMonitor->setDragMode(QGraphicsView::NoDrag); // 禁用鼠标滚轮滚动 ui->graphicsViewCutterMonitor->setTransformationAnchor(QGraphicsView::NoAnchor); // 禁用索引提高性能 scene->setItemIndexMethod(QGraphicsScene::NoIndex); //清空画布 scene->clear(); //清空指令列表 m_autoCuttingDataList.clear(); //不管分多少段,最底下从左到右都是一样的 for (int x = 0; x < rowPointCount; x++) { int y = QRandomGenerator::global()->bounded(columnPointCount - 2, columnPointCount); //int y = columnPointCount - 1; AutoCuttingPoint point(x, y, hxcommon::HeadingCutterCmdEnum::JoystickArm, 128, 128 - hxcommon::SystemSetting::autoCutHorizontalSpeed); m_autoCuttingDataList.append(point);//从左到右 } for (int i = 0; i < hxcommon::SystemSetting::autoCutColumnSplit; i++) { if (i % 2 == 0) { //顺着右侧向上 int yStart = columnPointCount - columnSplitPointCount * i - 1; int yEnd = columnPointCount - columnSplitPointCount * (i + 1); for (int y = yStart; y >= yEnd; y--) { int x = QRandomGenerator::global()->bounded(rowPointCount - 2, rowPointCount); //int x = rowPointCount - 1; AutoCuttingPoint point(x, y, hxcommon::HeadingCutterCmdEnum::JoystickArm, 128 - hxcommon::SystemSetting::autoCutHorizontalSpeed, 128); m_autoCuttingDataList.append(point);//右边向上 } for (int x = rowPointCount - 1; x >= 0; x--) { int y = QRandomGenerator::global()->bounded(yEnd - 2, yEnd); //int y = yEnd - 1; AutoCuttingPoint point(x, y, hxcommon::HeadingCutterCmdEnum::JoystickArm, 128, 128 + hxcommon::SystemSetting::autoCutHorizontalSpeed); m_autoCuttingDataList.append(point);//从右到左 } } else { //顺着左侧向上 int yStart = columnPointCount - columnSplitPointCount * i - 1; int yEnd = columnPointCount - columnSplitPointCount * (i + 1); for (int y = yStart; y >= yEnd; y--) { int x = QRandomGenerator::global()->bounded(-1, 1); //int x = 0; AutoCuttingPoint point(x, y, hxcommon::HeadingCutterCmdEnum::JoystickArm, 128 - hxcommon::SystemSetting::autoCutHorizontalSpeed, 128); m_autoCuttingDataList.append(point);//左边向上 } for (int x = 0; x < rowPointCount; x++) { int y = QRandomGenerator::global()->bounded(yEnd - 2, yEnd); //int y = yEnd - 1; AutoCuttingPoint point(x, y, hxcommon::HeadingCutterCmdEnum::JoystickArm, 128, 128 - hxcommon::SystemSetting::autoCutHorizontalSpeed); m_autoCuttingDataList.append(point);//从左到右 } } } //结束时添加停止命令 if (hxcommon::SystemSetting::autoCutColumnSplit % 2 == 0) { AutoCuttingPoint point1(rowPointCount - 1, 0, hxcommon::HeadingCutterCmdEnum::JoystickArm, 128, 128); m_autoCuttingDataList.append(point1); AutoCuttingPoint point2(rowPointCount - 1, 0, hxcommon::HeadingCutterCmdEnum::JoystickArm, 128, 128); m_autoCuttingDataList.append(point2); } else { AutoCuttingPoint point1(0, 0, hxcommon::HeadingCutterCmdEnum::JoystickArm, 128, 128); m_autoCuttingDataList.append(point1); AutoCuttingPoint point2(0, 0, hxcommon::HeadingCutterCmdEnum::JoystickArm, 128, 128); m_autoCuttingDataList.append(point2); } } void AutoCuttingWidget::initDrawCutPathViewer() { // 创建管理器 hxdraw2dlib::GraphicElementManage manager; // 创建场景 hxdraw2dlib::CircuitBaseScene* pScene = new hxdraw2dlib::CircuitBaseScene(this); //pScene->setSceneRect(-297 * 3 / 2, -210 * 3 / 2, 297 * 3, 210 * 3); pScene->setScalePerGrid(10.0); QTimer::singleShot(0, this, [=]() { QSize widgetSize = ui->widget_drawCutPathView->size(); pScene->setSceneRect(0, 0, widgetSize.width(), widgetSize.height()); }); // 创建视图(不要设置 parent) hxdraw2dlib::CircuitBaseView* view = new hxdraw2dlib::CircuitBaseView(pScene); m_curView = view; view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 获取或创建布局 QLayout* layout = ui->widget_drawCutPathView->layout(); if (layout) { // 如果 layout 是 QVBoxLayout 类型,添加控件 QVBoxLayout* vboxLayout = qobject_cast<QVBoxLayout*>(layout); vboxLayout->setContentsMargins(0, 0, 0, 0); // 去除边距 vboxLayout->setSpacing(0); // 去除间隔 if (vboxLayout) { //QTimer::singleShot(0, this, [=]() { //vboxLayout->addWidget(m_curView); //}); } } m_graphicElementManager.setCurView(m_curView); } void AutoCuttingWidget::testDrawCutterMonitor() { //获取本次要绘制的点 if (m_autoCuttingDataList.size() == 0) { return; } AutoCuttingPoint point = m_autoCuttingDataList.takeFirst(); emit sendAutoCuttingCmd(point.cmd, point.b0, point.b1); m_cutterRotation -= 13; if (m_cutterRotation <= -360) { m_cutterRotation = 0; } int width = ui->widget_cutterMonitorPainter->width(); int height = ui->widget_cutterMonitorPainter->height(); int rowPointCount = hxcommon::SystemSetting::autoCutRowTakeTime / hxcommon::SystemSetting::autoCutRefreshInterval;//一行多少点 int columnPointCount = hxcommon::SystemSetting::autoCutColumnTakeTime / hxcommon::SystemSetting::autoCutRefreshInterval;//一列多少点 double wItem = 540.0 / rowPointCount;//SceneRect尺寸600 - 截割头60 double hItem = 360.0 / columnPointCount;//SceneRect尺寸420 - 截割头60 //qDebug() << "width" << width << "height" << height; ui->graphicsViewCutterMonitor->setGeometry(width / 2 - 310, height / 2 - 220, 620, 440);//居中,因为带20边框 QGraphicsScene* scene = ui->graphicsViewCutterMonitor->scene(); if (!scene) { scene = new QGraphicsScene(this); ui->graphicsViewCutterMonitor->setScene(scene); } scene->setSceneRect(0, 0, 600, 420); // 禁用滚动条 ui->graphicsViewCutterMonitor->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->graphicsViewCutterMonitor->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // 禁用鼠标拖拽滚动 ui->graphicsViewCutterMonitor->setDragMode(QGraphicsView::NoDrag); // 禁用鼠标滚轮滚动 ui->graphicsViewCutterMonitor->setTransformationAnchor(QGraphicsView::NoAnchor); // 禁用索引提高性能 scene->setItemIndexMethod(QGraphicsScene::NoIndex); // 先移除画上去的截割头 scene->removeItem(m_cutter); //画很粗的圆组成切割图形 QGraphicsEllipseItem* circle = new QGraphicsEllipseItem(); circle->setRect(0, 0, 60, 60); // x, y, width, height (width=height时为圆形) circle->setPos(point.x * wItem, point.y * hItem); // 设置位置 circle->setBrush(QColor(26, 155, 114)); // 设置填充颜色 circle->setPen(QPen(QColor(26, 155, 114), 1)); // 设置边框 scene->addItem(circle);//添加到场景 //画小点连成轨迹 QGraphicsEllipseItem* linePoint = new QGraphicsEllipseItem(); linePoint->setRect(0, 0, 1, 1); // x, y, width, height (width=height时为圆形) linePoint->setPos(point.x * wItem + 30, point.y * hItem + 30); // 设置位置 linePoint->setBrush(Qt::green); // 设置填充颜色 linePoint->setPen(QPen(Qt::green, 1)); // 设置边框 scene->addItem(linePoint);//添加到场景 //画截割头和截割头旋转 scene->addItem(m_cutter); m_cutter->setPos(point.x * wItem, point.y * hItem); m_cutter->setTransformOriginPoint(QPointF(30, 30)); m_cutter->setRotation(m_cutterRotation); //联动左边姿态 float pitch = (columnPointCount / 2 - point.y) / columnPointCount * 80.0; float heading = (point.x - rowPointCount / 2) / rowPointCount * 80.0; ui->graphicsPFD->setPitch(pitch); ui->graphicsPFD->setHeading(heading); ui->graphicsPFD->update(); // ui->label_cutX->setText(QString::number(point.x)); ui->label_cutY->setText(QString::number(point.y)); }

如下Qt代码显示图像没有铺满控件,请改进 void MainWindow::recvShowPicSignal(QImage image) { ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QPixmap ConvertPixmap = QPixmap::fromImage(image);//The QPixmap class is an off-screen image representation that can be used as a paint device QGraphicsScene *qgraphicsScene = new QGraphicsScene;//要用QGraphicsView就必须要有QGraphicsScene搭配着用 m_Image = new ImageWidget(&ConvertPixmap);//实例化类ImageWidget的对象m_Image,该类继承自QGraphicsItem,是自己写的类 int nwith = ui->graphicsView->width();//获取界面控件Graphics View的宽度 int nheight = ui->graphicsView->height();//获取界面控件Graphics View的高度 m_Image->setQGraphicsViewWH(nwith,nheight);//将界面控件Graphics View的width和height传进类m_Image中 qgraphicsScene->addItem(m_Image);//将QGraphicsItem类对象放进QGraphicsScene中 ui->graphicsView->setSceneRect(QRectF(-(nwith/2),-(nheight/2),nwith,nheight));//使视窗的大小固定在原始大小,不会随图片的放大而放大(默认状态下图片放大的时候视窗两边会自动出现滚动条,并且视窗内的视野会变大),防止图片放大后重新缩小的时候视窗太大而不方便观察图片 ui->graphicsView->fitInView(ui->graphicsView->sceneRect(), Qt::KeepAspectRatio); ui->graphicsView->setScene(qgraphicsScene);//Sets the current scene to scene. If scene is already being viewed, this function does nothing. ui->graphicsView->setFocus();//将界面的焦点设置到当前Graphics View控件 }

#include <QtWidgets>class MyItem : public QGraphicsObject{public: MyItem(int pinCount, QColor color, QSizeF size, QGraphicsItem* parent = nullptr) : QGraphicsObject(parent) , m_pinCount(pinCount) , m_color(color) , m_size(size) {} QRectF boundingRect() const override { return QRectF(QPointF(0, 0), m_size); } QPainterPath shape() const override { QPainterPath path; path.addRect(QRectF(QPointF(0, 0), m_size)); return path; } void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override { Q_UNUSED(option) Q_UNUSED(widget) painter->setPen(Qt::NoPen); painter->setBrush(m_color); painter->drawRect(boundingRect()); painter->setPen(Qt::black); painter->setFont(QFont("Arial", 10)); painter->drawText(boundingRect(), Qt::AlignCenter, QString("%1 pins").arg(m_pinCount)); } void mousePressEvent(QGraphicsSceneMouseEvent* event) override { if (event->button() == Qt::LeftButton) { setCursor(Qt::ClosedHandCursor); m_lastPos = event->scenePos(); } } void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override { if (QLineF(event->screenPos(), m_lastPos).length() < QApplication::startDragDistance()) return; QGraphicsObject::mouseMoveEvent(event); setPos(pos() + event->scenePos() - m_lastPos); m_lastPos = event->scenePos(); } void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override { if (event->button() == Qt::LeftButton) { setCursor(Qt::ArrowCursor); } }private: int m_pinCount; QColor m_color; QSizeF m_size; QPointF m_lastPos;};int main(int argc, char* argv[]){ QApplication app(argc, argv); QGraphicsScene scene; scene.setSceneRect(0, 0, 800, 600); MyItem* item1 = new MyItem(8, Qt::red, QSizeF(80, 60)); item1->setPos(100, 100); scene.addItem(item1); MyItem* item2 = new MyItem(16, Qt::green, QSizeF(120, 80)); item2->setPos(300, 200); scene.addItem(item2); QGraphicsView view(&scene); view.setRenderHint(QPainter::Antialiasing); view.setDragMode(QGraphicsView::RubberBandDrag); view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate); view.show(); return app.exec();}在这个代码中,如何使用TextOut去给矩形框中添加文本

# main_window.py(主窗口逻辑) import numpy as np from PySide6.QtWidgets import QMainWindow, QFileDialog, QGraphicsScene, QGraphicsView, QMessageBox, QGraphicsPathItem from PySide6.QtGui import QPainterPath, QPen, QBrush, QAction, QTransform, QImage, QPixmap, QColor from PySide6.QtCore import Qt, QRectF, QPointF from osgeo import ogr, gdal from PySide6.QtWidgets import QInputDialog # 新增输入对话框 class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("GIS软件") self.setGeometry(100, 100, 800, 600) ogr.UseExceptions() self.init_ui() self.scene = QGraphicsScene(self) self.graphicsView.setScene(self.scene) # 新增:存储所有几何边界 self.total_bounds = QRectF() def init_ui(self): self.toolBar = self.addToolBar("工具") self.actionOpen_Vector_Data = QAction("打开矢量数据", self) self.toolBar.addAction(self.actionOpen_Vector_Data) # 新增栅格动作 self.actionOpen_Raster_Data = QAction("打开栅格数据", self) self.toolBar.addAction(self.actionOpen_Raster_Data) # 添加到工具栏 self.graphicsView = QGraphicsView() self.setCentralWidget(self.graphicsView) self.actionOpen_Vector_Data.triggered.connect(self.open_vector_data) self.actionOpen_Raster_Data.triggered.connect(self.open_raster_data) # 新增连接 def open_vector_data(self): file_path, _ = QFileDialog.getOpenFileName( self, "打开矢量文件", "", "Shapefile (*.shp);;GeoJSON (*.geojson);;All Files (*)" ) if file_path: self.load_vector_data(file_path) # 新增:自动缩放视图 self.auto_zoom() def load_vector_data(self, file_path): self.scene.clear() self.total_bounds = QRectF() # 重置边界 try: data_source = ogr.Open(file_path, 0) layer = data_source.GetLayer(0) for feature in layer: geom = feature.GetGeometryRef() path = self.geometry_to_qpainterpath(geom) # 更新总边界 if path.boundingRect().isValid(): self.total_bounds = self.total_bounds.united(path.boundingRect()) pen = QPen(Qt.blue, 1) brush = QBrush(Qt.cyan) self.scene.addPath(path, pen, brush) data_source = None except Exception as e: print(f"加载失败: {str(e)}") self.current_vector_path = file_path # 新增这一行 data_source = None def geometry_to_qpainterpath(self, geom): path = QPainterPath() if geom.GetGeometryType() == ogr.wkbPolygon: for ring in range(geom.GetGeometryCount()): linear_ring = geom.GetGeometryRef(ring) points = linear_ring.GetPoints() if points: path.moveTo(points[0][0], points[0][1]) for p in points[1:]: path.lineTo(p[0], p[1]) path.closeSubpath() elif geom.GetGeometryType() == ogr.wkbLineString: points = geom.GetPoints() if points: path.moveTo(points[0][0], points[0][1]) for p in points[1:]: path.lineTo(p[0], p[1]) elif geom.GetGeometryType() == ogr.wkbPoint: x, y = geom.GetX(), geom.GetY() path.addEllipse(x - 2, y - 2, 4, 4) return path def auto_zoom(self): """自动缩放视图到数据范围并放大2倍""" if not self.total_bounds.isValid(): return # 设置场景边界 self.scene.setSceneRect(self.total_bounds) # 获取视图可视区域 view_rect = self.graphicsView.viewport().rect() # 计算缩放比例(自动适应 + 2倍放大) transform = QTransform() transform.scale(2, 2) # 先放大2倍 # 应用缩放并居中 self.graphicsView.setTransform(transform) self.graphicsView.fitInView(self.total_bounds, Qt.KeepAspectRatio) def open_raster_data(self): """打开栅格数据文件""" file_path, _ = QFileDialog.getOpenFileName( self, "打开栅格文件", "", "GeoTIFF (*.tif);;JPEG (*.jpg *.jpeg);;PNG (*.png);;All Files (*)" ) if file_path: try: self.load_raster_data(file_path) self.auto_zoom() except Exception as e: QMessageBox.critical(self, "错误", f"加载栅格失败: {str(e)}") def load_raster_data(self, file_path): """加载栅格数据到视图""" # 打开栅格文件(需要用户修改路径的部分) dataset = gdal.Open(file_path) # 相对路径示例:"./data/raster.tif" # 读取第一个波段 band = dataset.GetRasterBand(1) width = dataset.RasterXSize height = dataset.RasterYSize # 转换为numpy数组 data = band.ReadAsArray() # 创建QImage(注意数据类型转换) if data.dtype == np.uint8: format = QImage.Format.Format_Grayscale8 else: format = QImage.Format.Format_ARGB32 q_img = QImage(data.tobytes(), width, height, format) # 创建像素图项 pixmap = QPixmap.fromImage(q_img) raster_item = self.scene.addPixmap(pixmap) # 处理地理坐标(如果存在) geotransform = dataset.GetGeoTransform() if geotransform: # 计算四个角的坐标 x_origin = geotransform[0] y_origin = geotransform[3] pixel_width = geotransform[1] pixel_height = geotransform[5] # 更新场景边界 x_min = x_origin x_max = x_origin + pixel_width * width y_min = y_origin + pixel_height * height y_max = y_origin self.total_bounds = QRectF( QPointF(x_min, y_min), QPointF(x_max, y_max) ) dataset = None # 关闭数据集 这是我的完整代码,里面以及实现了打开矢量数据和打开栅格数据的功能,请你在打开矢量数据的基础上增加一个缓冲区分析的功能,直接在我这个代码的基础上增加代码就行,原有的代码不要改,然后把增加完缓冲区分析这一功能的完整代码发给我就行

zip
资源下载链接为: https://pan.quark.cn/s/f989b9092fc5 今天给大家分享一个关于C#自定义字符串替换方法的实例,希望能对大家有所帮助。具体介绍如下: 之前我遇到了一个算法题,题目要求将一个字符串中的某些片段替换为指定的新字符串片段。例如,对于源字符串“abcdeabcdfbcdefg”,需要将其中的“cde”替换为“12345”,最终得到的结果字符串是“ab12345abcdfb12345fg”,即从“abcdeabcdfbcdefg”变为“ab12345abcdfb12345fg”。 经过分析,我发现不能直接使用C#自带的string.Replace方法来实现这个功能。于是,我决定自定义一个方法来完成这个任务。这个方法的参数包括:原始字符串originalString、需要被替换的字符串片段strToBeReplaced以及用于替换的新字符串片段newString。 在实现过程中,我首先遍历原始字符串,查找需要被替换的字符串片段strToBeReplaced出现的位置。找到后,就将其替换为新字符串片段newString。需要注意的是,在替换过程中,要确保替换操作不会影响后续的查找和替换,避免遗漏或重复替换的情况发生。 以下是实现代码的大概逻辑: 初始化一个空的字符串result,用于存储最终替换后的结果。 使用IndexOf方法在原始字符串中查找strToBeReplaced的位置。 如果找到了,就将originalString中从开头到strToBeReplaced出现位置之前的部分,以及newString拼接到result中,然后将originalString的查找范围更新为strToBeReplaced之后的部分。 如果没有找到,就直接将剩余的originalString拼接到result中。 重复上述步骤,直到originalStr

大家在看

recommend-type

pb调用支付宝接口的例子

pb11调用支付宝接口的例子程序,适用于CS系统调用支付宝接口参考
recommend-type

mkcert-v1.4.3-windows-amd64.rar

mkcert-v1.4.3-windows-amd64.rar
recommend-type

Labview以太网络MC协议实现三菱FX系列PLC通讯控制,Labview三菱FX系列以太网MC协议通讯实现方案,labview 编写的三菱fx系列,以太网MC协议通讯 ,核心关键词:LabVIEW

Labview以太网络MC协议实现三菱FX系列PLC通讯控制,Labview三菱FX系列以太网MC协议通讯实现方案,labview 编写的三菱fx系列,以太网MC协议通讯 ,核心关键词:LabVIEW; 三菱FX系列; 以太网MC协议通讯; 编程通讯,基于LabVIEW的三菱FX系列以太网MC协议通讯实现
recommend-type

服务质量管理-NGBOSS能力架构

服务质量管理 二级能力名称 服务质量管理 二级能力编号 CMCM.5.4 概述 监测、分析和控制客户感知的服务表现 相关子能力描述 能够主动的将网络性能数据通告给前端客服人员; 能够根据按照客户价值来划分的客户群来制定特殊的SLA指标; 能够为最有价值的核心客户群进行网络优化; 对于常规的维护问题,QoS能够由网元设备自动完成,比如,对于网络故障的自恢复能力和优先客户的使用权; 能够把潜在的网络问题与客户进行主动的沟通; 能够分析所有的服务使用的质量指标; 能够根据关键的服务质量指标检测与实际的差距,提出改进建议; Service request 服务请求---请求管理。 客户的分析和报告:对关闭的请求、用户联系和相关的报告进行分析。 Marketing collateral的散发和marketing Collateral 的散发后的线索跟踪
recommend-type

HANA ODBC驱动32位windows安装包

SAP HANA CLIENT windows安装包 用于HANA ODBC 32位驱动的安装

最新推荐

recommend-type

C#实现自定义字符串替换方法示例

资源下载链接为: https://pan.quark.cn/s/f989b9092fc5 今天给大家分享一个关于C#自定义字符串替换方法的实例,希望能对大家有所帮助。具体介绍如下: 之前我遇到了一个算法题,题目要求将一个字符串中的某些片段替换为指定的新字符串片段。例如,对于源字符串“abcdeabcdfbcdefg”,需要将其中的“cde”替换为“12345”,最终得到的结果字符串是“ab12345abcdfb12345fg”,即从“abcdeabcdfbcdefg”变为“ab12345abcdfb12345fg”。 经过分析,我发现不能直接使用C#自带的string.Replace方法来实现这个功能。于是,我决定自定义一个方法来完成这个任务。这个方法的参数包括:原始字符串originalString、需要被替换的字符串片段strToBeReplaced以及用于替换的新字符串片段newString。 在实现过程中,我首先遍历原始字符串,查找需要被替换的字符串片段strToBeReplaced出现的位置。找到后,就将其替换为新字符串片段newString。需要注意的是,在替换过程中,要确保替换操作不会影响后续的查找和替换,避免遗漏或重复替换的情况发生。 以下是实现代码的大概逻辑: 初始化一个空的字符串result,用于存储最终替换后的结果。 使用IndexOf方法在原始字符串中查找strToBeReplaced的位置。 如果找到了,就将originalString中从开头到strToBeReplaced出现位置之前的部分,以及newString拼接到result中,然后将originalString的查找范围更新为strToBeReplaced之后的部分。 如果没有找到,就直接将剩余的originalString拼接到result中。 重复上述步骤,直到originalStr
recommend-type

bouncycastle文件

bouncycastle文件
recommend-type

上海交大ARM培训教材ARM嵌入式软件开发(1).ppt

上海交大ARM培训教材ARM嵌入式软件开发(1).ppt
recommend-type

计算机等级考试(20220104080129)------(1).pdf

计算机等级考试(20220104080129)------(1).pdf
recommend-type

解决Python "Permission Denied" 错误的完整指南

解决Python "Permission Denied" 错误的完整指南
recommend-type

获取本机IP地址的程序源码分析

从给定文件信息中我们可以提取出的关键知识点是“取本机IP”的实现方法以及与之相关的编程技术和源代码。在当今的信息技术领域中,获取本机IP地址是一项基本技能,广泛应用于网络通信类的软件开发中,下面将详细介绍这一知识点。 首先,获取本机IP地址通常需要依赖于编程语言和操作系统的API。不同的操作系统提供了不同的方法来获取IP地址。在Windows操作系统中,可以通过调用Windows API中的GetAdaptersInfo()或GetAdaptersAddresses()函数来获取网络适配器信息,进而得到IP地址。在类Unix操作系统中,可以通过读取/proc/net或是使用系统命令ifconfig、ip等来获取网络接口信息。 在程序设计过程中,获取本机IP地址的源程序通常会用到网络编程的知识,比如套接字编程(Socket Programming)。网络编程允许程序之间进行通信,套接字则是在网络通信过程中用于发送和接收数据的接口。在许多高级语言中,如Python、Java、C#等,都提供了内置的网络库和类来简化网络编程的工作。 在网络通信类中,IP地址是区分不同网络节点的重要标识,它是由IP协议规定的,用于在网络中唯一标识一个网络接口。IP地址可以是IPv4,也可以是较新的IPv6。IPv4地址由32位二进制数表示,通常分为四部分,每部分由8位构成,并以点分隔,如192.168.1.1。IPv6地址则由128位二进制数表示,其表示方法与IPv4有所不同,以冒号分隔的8组16进制数表示,如2001:0db8:85a3:0000:0000:8a2e:0370:7334。 当编写源代码以获取本机IP地址时,通常涉及到以下几个步骤: 1. 选择合适的编程语言和相关库。 2. 根据目标操作系统的API或系统命令获取网络接口信息。 3. 分析网络接口信息,提取出IP地址。 4. 将提取的IP地址转换成适合程序内部使用的格式。 5. 在程序中提供相应功能,如显示IP地址或用于网络通信。 例如,在Python中,可以使用内置的socket库来获取本机IP地址。一个简单的示例代码如下: ```python import socket # 获取主机名 hostname = socket.gethostname() # 获取本机IP local_ip = socket.gethostbyname(hostname) print("本机IP地址是:", local_ip) ``` 在实际应用中,获取本机IP地址通常是为了实现网络通信功能,例如建立客户端与服务器的连接,或者是在开发涉及到IP地址的其他功能时使用。 关于文件名称“getIP”,这是一个自解释的文件名,明显表示该文件或程序的作用是获取本机的IP地址。从标签“控件 源码 网络通信类 资源”中我们可以看出,这个文件很可能是一个可以嵌入其他软件中的代码片段,用以实现网络通信功能的一部分,具有较高的灵活性和重用性。 综上所述,获取本机IP地址是一个涉及到操作系统API、网络编程以及特定编程语言知识的技能。它不仅需要对编程语言提供的库函数有深入的理解,还要对操作系统的网络配置和IP协议有足够的认识。通过阅读和分析相关的源代码,如“getIP”,可以加深对网络编程实现细节的理解,并能够在实际开发中快速地应用这一技术。
recommend-type

【权威指南】:Win11笔记本上RTX4080驱动的安装与调试秘籍

# 1. Win11笔记本与RTX4080显卡介绍 随着技术的不断发展,笔记本电脑已不再是仅仅满足办公需求的移动设备,而是逐渐成为可以胜任复杂图形处理和游戏任务的强大工具。微软推出的Windows 11操作系统,以其全新的用户界面和改进的系统性能,为用户提供了更为流畅的操作体验。而在硬件方面,NVIDIA的RTX 4080显卡以其卓越的图形处理能力和AI支持,为笔记本电脑带来了前所未有的性能提升。本章节将带您初步了解Windows 11笔记本与NVIDIA RTX 4080显卡的基础信息,为进一步深入探讨它们的优化和调试技巧奠定基础。 ## 1.1 Win11笔记本的优势 Windows
recommend-type

windows环境举例

<think>好的,用户现在想在Windows环境下创建C函数库,需要具体的方法和示例代码。我需要结合之前的回答和用户提供的引用内容来给出合适的指导。 首先回顾之前的回答,用户已经了解了在Linux下创建静态库和动态库的方法,现在需要切换到Windows环境。根据引用[2],Windows下的C标准库和动态链接库的处理与Linux不同,比如使用dlfcn.h在Linux,而Windows可能需要其他方式。另外,引用[1]提到了在Windows下配置gcc环境(MinGW-w64),这可能是一个关键点,因为用户可能需要使用MinGW来编译库。 用户提供的引用[3]提到了使用MSVC编译器,这
recommend-type

QQ自动发送/回复系统源代码开放

根据提供的文件信息,我们可以了解到以下几点关键的知识点: ### 标题:“qqhelp” 1. **项目类型**: 标题“qqhelp”暗示这是一个与QQ相关的帮助工具或项目。QQ是中国流行的即时通讯软件,因此这个标题表明项目可能提供了对QQ客户端功能的辅助或扩展。 2. **用途**: “help”表明此项目的主要目的是提供帮助或解决问题。由于它提到了QQ,并且涉及“autosend/reply”功能,我们可以推测该项目可能用于自动化发送消息回复,或提供某种形式的自动回复机制。 ### 描述:“I put it to my web, but nobody sendmessage to got the source, now I public it. it supply qq,ticq autosend/reply ,full sourcecode use it as you like” 1. **发布情况**: 描述提到该项目原先被放置在某人的网站上,并且没有收到请求源代码的消息。这可能意味着项目不够知名或者需求不高。现在作者决定公开发布,这可能是因为希望项目能够被更多人了解和使用,或是出于开源共享的精神。 2. **功能特性**: 提到的“autosend/reply”表明该项目能够实现自动发送和回复消息。这种功能对于需要进行批量或定时消息沟通的应用场景非常有用,例如客户服务、自动化的营销通知等。 3. **代码可用性**: 作者指出提供了“full sourcecode”,意味着源代码完全开放,用户可以自由使用,无论是查看、学习还是修改,用户都有很大的灵活性。这对于希望学习编程或者有特定需求的开发者来说是一个很大的优势。 ### 标签:“综合系统类” 1. **项目分类**: 标签“综合系统类”表明这个项目可能是一个多功能的集成系统,它可能不仅限于QQ相关的功能,还可能包含了其他类型的综合服务或特性。 2. **技术范畴**: 这个标签可能表明该项目的技术实现比较全面,可能涉及到了多个技术栈或者系统集成的知识点,例如消息处理、网络编程、自动化处理等。 ### 压缩包子文件的文件名称列表: 1. **Unit1.dfm**: 这是一个Delphi或Object Pascal语言的窗体定义文件,用于定义应用程序中的用户界面布局。DFM文件通常用于存储组件的属性和位置信息,使得开发者可以快速地进行用户界面的设计和调整。 2. **qqhelp.dpr**: DPR是Delphi项目文件的扩展名,包含了Delphi项目的核心设置,如程序入口、使用的单元(Units)等。这个文件是编译和构建Delphi项目的起点,它能够帮助开发者了解项目的组织结构和编译指令。 3. **Unit1.pas**: PAS是Delphi或Object Pascal语言的源代码文件。这个文件可能包含了与QQ帮助工具相关的核心逻辑代码,例如处理自动发送和回复消息的算法等。 4. **readme.txt**: 这是一个常见的文本文件,包含项目的基本说明和使用指导,帮助用户了解如何获取、安装、运行和定制该项目。README文件通常是用户与项目首次交互时首先阅读的文件,因此它对于一个开源项目的用户友好度有着重要影响。 通过以上分析,我们可以看出“qqhelp”项目是一个针对QQ通讯工具的自动化消息发送与回复的辅助工具。项目包含完整的源代码,用户可以根据自己的需要进行查看、修改和使用。它可能包含Delphi语言编写的窗体界面和后端逻辑代码,具有一定的综合系统特性。项目作者出于某种原因将其开源,希望能够得到更广泛的使用和反馈。
recommend-type

【7步打造Win11深度学习利器】:Tensorflow-GPU与RTX4080终极优化指南

# 1. 深度学习与Windows 11的融合 在人工智能时代,深度学习已渗透到生活的方方面面,而Windows 11作为最新一代的操作系统,为深度学习提供了一个高效的工作平台。本章节将探讨深度学习技术如何与Windows 11系统融合,以及这一