2 Commits

Author SHA1 Message Date
a6b58cab6f add
添加马达配置界面;
2026-10-09 09:10:19 +08:00
2747d5f967 add
mapcavas添加功能:镜像和旋转,并保存配置
2026-09-21 17:29:57 +08:00
23 changed files with 1462 additions and 240 deletions

View File

@ -12,6 +12,9 @@ const double AppSettings::kDefaultScanSpeed = 1.0;
const double AppSettings::kDefaultReturnSpeed = 5.0; const double AppSettings::kDefaultReturnSpeed = 5.0;
const int AppSettings::kDefaultGonggaShanRecordPort = 666; const int AppSettings::kDefaultGonggaShanRecordPort = 666;
const AppSettings::HyperimgDisplayMode AppSettings::kDefaultHyperimgDisplayMode = HyperimgDisplayMode::Waterfall; const AppSettings::HyperimgDisplayMode AppSettings::kDefaultHyperimgDisplayMode = HyperimgDisplayMode::Waterfall;
const bool AppSettings::kDefaultImageHorizontalMirror = true;
const bool AppSettings::kDefaultImageVerticalMirror = true;
const int AppSettings::kDefaultImageRotation = 0;
AppSettings::AppSettings() AppSettings::AppSettings()
: m_settings(QSettings::IniFormat, QSettings::UserScope, : m_settings(QSettings::IniFormat, QSettings::UserScope,
@ -216,3 +219,33 @@ void AppSettings::setHyperimgDisplayMode(HyperimgDisplayMode mode)
{ {
m_settings.setValue("Display/HyperimgDisplayMode", static_cast<int>(mode)); m_settings.setValue("Display/HyperimgDisplayMode", static_cast<int>(mode));
} }
bool AppSettings::imageHorizontalMirror() const
{
return m_settings.value("Display/ImageHorizontalMirror", kDefaultImageHorizontalMirror).toBool();
}
void AppSettings::setImageHorizontalMirror(bool value)
{
m_settings.setValue("Display/ImageHorizontalMirror", value);
}
bool AppSettings::imageVerticalMirror() const
{
return m_settings.value("Display/ImageVerticalMirror", kDefaultImageVerticalMirror).toBool();
}
void AppSettings::setImageVerticalMirror(bool value)
{
m_settings.setValue("Display/ImageVerticalMirror", value);
}
int AppSettings::imageRotation() const
{
return m_settings.value("Display/ImageRotation", kDefaultImageRotation).toInt();
}
void AppSettings::setImageRotation(int value)
{
m_settings.setValue("Display/ImageRotation", ((value % 360) + 360) % 360);
}

View File

@ -73,6 +73,18 @@ public:
// 图像显示模式 // 图像显示模式
HyperimgDisplayMode hyperimgDisplayMode() const; HyperimgDisplayMode hyperimgDisplayMode() const;
void setHyperimgDisplayMode(HyperimgDisplayMode mode); void setHyperimgDisplayMode(HyperimgDisplayMode mode);
// 图像显示变换(左右镜像/上下镜像/旋转),全局生效
bool imageHorizontalMirror() const;
void setImageHorizontalMirror(bool value);
bool imageVerticalMirror() const;
void setImageVerticalMirror(bool value);
// 旋转角度,取值 0、90、180、270
int imageRotation() const;
void setImageRotation(int value);
// 在此处添加更多参数的 getter/setter ... // 在此处添加更多参数的 getter/setter ...
private: private:
@ -94,4 +106,7 @@ private:
static const double kDefaultReturnSpeed; static const double kDefaultReturnSpeed;
static const int kDefaultGonggaShanRecordPort; static const int kDefaultGonggaShanRecordPort;
static const HyperimgDisplayMode kDefaultHyperimgDisplayMode; static const HyperimgDisplayMode kDefaultHyperimgDisplayMode;
static const bool kDefaultImageHorizontalMirror;
static const bool kDefaultImageVerticalMirror;
static const int kDefaultImageRotation;
}; };

View File

@ -374,7 +374,20 @@ QRadioButton
</widget> </widget>
</widget> </widget>
</item> </item>
<item row="2" column="0" colspan="2"> <item row="2" column="0">
<widget class="QPushButton" name="config_pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>配置</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="connectMotor_btn"> <widget class="QPushButton" name="connectMotor_btn">
<property name="text"> <property name="text">
<string>连接</string> <string>连接</string>

View File

@ -959,6 +959,9 @@ void HPPA::initMenubarToolbar()
ui.mActionPan->setIcon(QIcon(":/svg/resources/icons/svg/pan.svg")); ui.mActionPan->setIcon(QIcon(":/svg/resources/icons/svg/pan.svg"));
ui.mActionSpectral->setIcon(QIcon(":/svg/resources/icons/svg/spectral.svg")); ui.mActionSpectral->setIcon(QIcon(":/svg/resources/icons/svg/spectral.svg"));
ui.mActionRotation90->setIcon(QIcon(":/svg/resources/icons/svg/rotate90.svg"));
ui.mActionVerticalMirror->setIcon(QIcon(":/svg/resources/icons/svg/VerticalMirror.svg"));
ui.mActionHorizontalMirror->setIcon(QIcon(":/svg/resources/icons/svg/HorizontalMirror.svg"));
connect(ui.mActionPan, &QAction::toggled, this, [=](bool checked) { connect(ui.mActionPan, &QAction::toggled, this, [=](bool checked) {
if (checked) if (checked)
@ -974,6 +977,34 @@ void HPPA::initMenubarToolbar()
ui.mActionSpectral->setIcon(QIcon(":/svg/resources/icons/svg/spectral.svg")); ui.mActionSpectral->setIcon(QIcon(":/svg/resources/icons/svg/spectral.svg"));
}); });
connect(ui.mActionRotation90, &QAction::triggered, this, [=](bool) {
QWidget* currentWidget = m_imageViewerTabWidget->currentWidget();
if (!currentWidget) return;
QList<Mapcavas*> canvases = currentWidget->findChildren<Mapcavas*>();
if (canvases.isEmpty()) return;
canvases[0]->rotateImage90();
});
connect(ui.mActionVerticalMirror, &QAction::triggered, this, [=](bool) {
QWidget* currentWidget = m_imageViewerTabWidget->currentWidget();
if (!currentWidget) return;
QList<Mapcavas*> canvases = currentWidget->findChildren<Mapcavas*>();
if (canvases.isEmpty()) return;
canvases[0]->toggleVerticalMirror();
});
connect(ui.mActionHorizontalMirror, &QAction::triggered, this, [=](bool) {
QWidget* currentWidget = m_imageViewerTabWidget->currentWidget();
if (!currentWidget) return;
QList<Mapcavas*> canvases = currentWidget->findChildren<Mapcavas*>();
if (canvases.isEmpty()) return;
canvases[0]->toggleHorizontalMirror();
});
// 使用样式表设置透明背景 // 使用样式表设置透明背景
toolBar->setStyleSheet(R"( toolBar->setStyleSheet(R"(
QToolBar { QToolBar {

View File

@ -32,6 +32,9 @@
<file>resources/icons/svg/tree_tri_down.svg</file> <file>resources/icons/svg/tree_tri_down.svg</file>
<file>resources/icons/svg/tree_tri_right.svg</file> <file>resources/icons/svg/tree_tri_right.svg</file>
<file>resources/icons/svg/mIconRaster.svg</file> <file>resources/icons/svg/mIconRaster.svg</file>
<file>resources/icons/svg/HorizontalMirror.svg</file>
<file>resources/icons/svg/rotate90.svg</file>
<file>resources/icons/svg/VerticalMirror.svg</file>
</qresource> </qresource>
<qresource prefix="/png"> <qresource prefix="/png">
<file>resources/icons/png/Spectral_Insight_27.png</file> <file>resources/icons/png/Spectral_Insight_27.png</file>

View File

@ -203,6 +203,9 @@ QToolBar QToolButton:hover {
<addaction name="actionOpenDirectory"/> <addaction name="actionOpenDirectory"/>
<addaction name="mActionPan"/> <addaction name="mActionPan"/>
<addaction name="mActionSpectral"/> <addaction name="mActionSpectral"/>
<addaction name="mActionVerticalMirror"/>
<addaction name="mActionHorizontalMirror"/>
<addaction name="mActionRotation90"/>
</widget> </widget>
<widget class="QStatusBar" name="statusBar"> <widget class="QStatusBar" name="statusBar">
<property name="styleSheet"> <property name="styleSheet">
@ -758,6 +761,27 @@ QPushButton:pressed
<string>贡嘎山旋转平台</string> <string>贡嘎山旋转平台</string>
</property> </property>
</action> </action>
<action name="mActionVerticalMirror">
<property name="text">
<string>上下镜像</string>
</property>
</action>
<action name="mActionHorizontalMirror">
<property name="text">
<string>左右镜像</string>
</property>
<property name="toolTip">
<string>左右镜像</string>
</property>
</action>
<action name="mActionRotation90">
<property name="text">
<string>旋转90度</string>
</property>
<property name="toolTip">
<string>旋转90度</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

View File

@ -174,6 +174,7 @@
<ClCompile Include="TaskTreeModel.cpp" /> <ClCompile Include="TaskTreeModel.cpp" />
<ClCompile Include="TimedDataCollection.cpp" /> <ClCompile Include="TimedDataCollection.cpp" />
<ClCompile Include="TimedDataCollectionDataStructures.cpp" /> <ClCompile Include="TimedDataCollectionDataStructures.cpp" />
<ClCompile Include="MotorConfigDialog.cpp" />
<ClCompile Include="TwoMotorControl.cpp" /> <ClCompile Include="TwoMotorControl.cpp" />
<ClCompile Include="utility_tc.cpp" /> <ClCompile Include="utility_tc.cpp" />
<ClCompile Include="View3D.cpp" /> <ClCompile Include="View3D.cpp" />
@ -200,6 +201,7 @@
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
<QtUic Include="hyperImagerControl.ui" /> <QtUic Include="hyperImagerControl.ui" />
<QtUic Include="imgControl.ui" /> <QtUic Include="imgControl.ui" />
<QtUic Include="MotorConfigDialog.ui" />
<QtUic Include="oneMotorControl.ui" /> <QtUic Include="oneMotorControl.ui" />
<QtUic Include="PathPlan.ui" /> <QtUic Include="PathPlan.ui" />
<QtUic Include="PowerControl.ui" /> <QtUic Include="PowerControl.ui" />
@ -265,6 +267,7 @@
<QtMoc Include="MapToolPan.h" /> <QtMoc Include="MapToolPan.h" />
<QtMoc Include="MapToolSpectral.h" /> <QtMoc Include="MapToolSpectral.h" />
<QtMoc Include="MapTools.h" /> <QtMoc Include="MapTools.h" />
<QtMoc Include="MotorConfigDialog.h" />
<ClInclude Include="MotorWindowBase.h" /> <ClInclude Include="MotorWindowBase.h" />
<QtMoc Include="PowerControl3D.h" /> <QtMoc Include="PowerControl3D.h" />
<ClInclude Include="PathLine.h" /> <ClInclude Include="PathLine.h" />

View File

@ -133,6 +133,9 @@
<ClCompile Include="TwoMotorControl.cpp"> <ClCompile Include="TwoMotorControl.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="MotorConfigDialog.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="CustomDockWidgetBase.cpp"> <ClCompile Include="CustomDockWidgetBase.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -336,6 +339,9 @@
<QtMoc Include="TwoMotorControl.h"> <QtMoc Include="TwoMotorControl.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</QtMoc> </QtMoc>
<QtMoc Include="MotorConfigDialog.h">
<Filter>Header Files</Filter>
</QtMoc>
<QtMoc Include="CaptureCoordinator.h"> <QtMoc Include="CaptureCoordinator.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</QtMoc> </QtMoc>
@ -553,6 +559,9 @@
<QtUic Include="twoMotorControl.ui"> <QtUic Include="twoMotorControl.ui">
<Filter>Form Files</Filter> <Filter>Form Files</Filter>
</QtUic> </QtUic>
<QtUic Include="MotorConfigDialog.ui">
<Filter>Form Files</Filter>
</QtUic>
<QtUic Include="imgControl.ui"> <QtUic Include="imgControl.ui">
<Filter>Form Files</Filter> <Filter>Form Files</Filter>
</QtUic> </QtUic>

View File

@ -49,7 +49,8 @@ Mapcavas::Mapcavas(QWidget* pParent) :QGraphicsView(pParent)
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setFrameShape(QFrame::NoFrame); setFrameShape(QFrame::NoFrame);
m_displayMode = AppSettings::instance().hyperimgDisplayMode(); loadSettings();
//addSceneCoordinateSystem();
} }
Mapcavas::~Mapcavas() Mapcavas::~Mapcavas()
@ -57,6 +58,94 @@ Mapcavas::~Mapcavas()
} }
void Mapcavas::loadSettings()
{
updateDisplayMode();
//更新控制图像变换的变量m_imageTransformState
AppSettings& settings = AppSettings::instance();
m_imageTransformState.horizontalMirror = settings.imageHorizontalMirror();
m_imageTransformState.verticalMirror = settings.imageVerticalMirror();
m_imageTransformState.rotation = settings.imageRotation();
}
void Mapcavas::applyImageTransform()
{
if (m_GraphicsPixmapItemHandle == nullptr)
return;
const double sx = m_imageTransformState.horizontalMirror ? -1.0 : 1.0;
const double sy = m_imageTransformState.verticalMirror ? -1.0 : 1.0;
const QPointF center = m_GraphicsPixmapItemHandle->boundingRect().center();
QTransform transform_all;
transform_all.translate(center.x(), center.y());// 围绕图片中心变换
transform_all.scale(sx, sy);
transform_all.rotate(m_imageTransformState.rotation);
transform_all.translate(-center.x(), -center.y());
// setTransform 是替换而非叠加,因此可对已显示的图像重复调用
m_GraphicsPixmapItemHandle->setTransform(transform_all);
//QPointF itemOrigin(0, 0);
//QPointF sceneOrigin = m_GraphicsPixmapItemHandle->mapToScene(itemOrigin);
//QPointF sceneOrigin2 = m_GraphicsPixmapItemHandle->scenePos();
// 变换后重新定位十字叉,使其始终跟随同一个图像像素
repositionCrosshair();
}
void Mapcavas::repositionCrosshair()
{
if (!m_hLine || !m_vLine || !m_GraphicsPixmapItemHandle)
return;
const QPointF scenePt = m_GraphicsPixmapItemHandle->mapToScene(m_crosshairItemPos);
m_hLine->setPos(scenePt);
m_vLine->setPos(scenePt);
}
void Mapcavas::refreshImageTransform()
{
if (!HasImage())
return;
applyImageTransform();
if (m_displayMode == AppSettings::HyperimgDisplayMode::Full)
{
ensureSceneVisible();
}
else if (m_displayMode == AppSettings::HyperimgDisplayMode::Waterfall)
{
ensureWaterfallVisible();
}
}
void Mapcavas::rotateImage90()
{
AppSettings& settings = AppSettings::instance();
settings.setImageRotation(settings.imageRotation() + 90);
loadSettings();
refreshImageTransform();
}
void Mapcavas::toggleHorizontalMirror()
{
AppSettings& settings = AppSettings::instance();
settings.setImageHorizontalMirror(!settings.imageHorizontalMirror());
loadSettings();
refreshImageTransform();
}
void Mapcavas::toggleVerticalMirror()
{
AppSettings& settings = AppSettings::instance();
settings.setImageVerticalMirror(!settings.imageVerticalMirror());
loadSettings();
refreshImageTransform();
}
void Mapcavas::updateDisplayMode() void Mapcavas::updateDisplayMode()
{ {
m_displayMode = AppSettings::instance().hyperimgDisplayMode(); m_displayMode = AppSettings::instance().hyperimgDisplayMode();
@ -79,14 +168,12 @@ void Mapcavas::SetImage(QPixmap *image)
m_GraphicsPixmapItemHandle->setPixmap(*image); m_GraphicsPixmapItemHandle->setPixmap(*image);
} }
if (m_displayMode == AppSettings::HyperimgDisplayMode::Full) refreshImageTransform();
{ }
ensureSceneVisible();
} QGraphicsPixmapItem* Mapcavas::pixmapItemHandle()
else if (m_displayMode == AppSettings::HyperimgDisplayMode::Waterfall) {
{ return m_GraphicsPixmapItemHandle;
ensureWaterfallVisible();
}
} }
void Mapcavas::ensureSceneVisible() void Mapcavas::ensureSceneVisible()
@ -108,40 +195,88 @@ void Mapcavas::ensureSceneVisible()
void Mapcavas::ensureWaterfallVisible() void Mapcavas::ensureWaterfallVisible()
{ {
resetTransform(); if (!HasImage())
auto items = this->scene()->items();
if (items.isEmpty())
return; return;
auto scene_rect = this->scene()->itemsBoundingRect(); resetTransform();
QGraphicsPixmapItem* item = m_GraphicsPixmapItemHandle;
const QRectF item_rect = item->boundingRect();
if (item_rect.isEmpty())
return;
// 图像已经应用了 m_imageTransformState 的镜像/旋转,这里以场景中的实际位置为准
const QRectF scene_rect = item->sceneBoundingRect();
qreal view_width = viewport()->rect().width(); qreal view_width = viewport()->rect().width();
qreal view_height = viewport()->rect().height(); qreal view_height = viewport()->rect().height();
if (view_width <= 0.0 || view_height <= 0.0)
return;
if (scene_rect.width() <= 0.0 || scene_rect.height() <= 0.0)
return;
double x_scale = view_width / scene_rect.width(); // 图像坐标中:x 为扫描线空间轴(固定),y 为采集帧数(不断增长),最新一帧位于 y 最大处。
double y_scale = view_height / scene_rect.height(); // 经过镜像/旋转后,增长轴可能竖直(0°/180°)或水平(90°/270°)。
const QPointF growth_dir = item->mapToScene(QPointF(0.0, 1.0))
- item->mapToScene(QPointF(0.0, 0.0));
const bool growth_vertical = qAbs(growth_dir.y()) >= qAbs(growth_dir.x());
double scale_factor = qMin(x_scale, y_scale) * 0.9; // 最新一帧(图像底边中心)在场景中的位置,用于判断应该贴哪条边
const QPointF newest_scene = item->mapToScene(
QPointF(item_rect.width() / 2.0, item_rect.height()));
scale(x_scale, x_scale); if (growth_vertical)
m_scale *= x_scale;
// 计算缩放后的图片可见高度
qreal scaled_height = scene_rect.height() * x_scale;
// 根据图片高度决定 Y 坐标
qreal center_y;
if (scaled_height <= view_height)
{ {
center_y = scene_rect.center().y(); // 竖直瀑布:空间轴横向铺满视图宽度,最新一帧固定在上/下边缘
const double x_scale = view_width / scene_rect.width();
scale(x_scale, x_scale);
m_scale *= x_scale;
// 计算缩放后的图片可见高度
qreal scaled_height = scene_rect.height() * x_scale;
qreal center_y;
if (scaled_height <= view_height)
{
center_y = scene_rect.center().y();
}
else
{
qreal half_view_height = view_height / 2.0 / x_scale;
if (newest_scene.y() >= scene_rect.center().y())
center_y = scene_rect.bottom() - half_view_height; // 最新帧在下方,贴底
else
center_y = scene_rect.top() + half_view_height; // 最新帧在上方,贴顶
}
centerOn(scene_rect.center().x(), center_y);
} }
else else
{ {
qreal half_view_height = view_height / 2.0 / x_scale; // 水平瀑布:空间轴竖向铺满视图高度,最新一帧固定在左/右边缘
center_y = scene_rect.bottom() - half_view_height; const double y_scale = view_height / scene_rect.height();
} scale(y_scale, y_scale);
m_scale *= y_scale;
centerOn(scene_rect.center().x(), center_y); // 计算缩放后的图片可见宽度
qreal scaled_width = scene_rect.width() * y_scale;
qreal center_x;
if (scaled_width <= view_width)
{
center_x = scene_rect.center().x();
}
else
{
qreal half_view_width = view_width / 2.0 / y_scale;
if (newest_scene.x() >= scene_rect.center().x())
center_x = scene_rect.right() - half_view_width; // 最新帧在右侧,贴右
else
center_x = scene_rect.left() + half_view_width; // 最新帧在左侧,贴左
}
centerOn(center_x, scene_rect.center().y());
}
} }
bool Mapcavas::HasImage() bool Mapcavas::HasImage()
@ -164,21 +299,32 @@ void Mapcavas::updateCrosshair(double sceneX, double sceneY)
if (!m_hLine) if (!m_hLine)
{ {
m_hLine = m_qtGraphicsScene->addLine(0, 0, 0, 0, pen); m_hLine = m_qtGraphicsScene->addLine(0, 0, 0, 0, pen);
m_hLine->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
m_hLine->setZValue(1e9); m_hLine->setZValue(1e9);
} }
if (!m_vLine) if (!m_vLine)
{ {
m_vLine = m_qtGraphicsScene->addLine(0, 0, 0, 0, pen); m_vLine = m_qtGraphicsScene->addLine(0, 0, 0, 0, pen);
m_vLine->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
m_vLine->setZValue(1e9); m_vLine->setZValue(1e9);
} }
m_hLine->setPen(pen); m_hLine->setPen(pen);
m_vLine->setPen(pen); m_vLine->setPen(pen);
m_hLine->setLine(sceneX - m_CrosshairHalfLen, sceneY, // 设置 ItemIgnoresTransformations 后,图元的原点依旧按场景坐标定位,
sceneX + m_CrosshairHalfLen, sceneY); // 但局部坐标不再受视图缩放影响(1 单位 = 1 屏幕像素)。
m_vLine->setLine(sceneX, sceneY - m_CrosshairHalfLen, // 这里把锚点记录在图像(图元)坐标系中,再据此定位十字叉:
sceneX, sceneY + m_CrosshairHalfLen); // 这样点击某个像素后,无论滚轮缩放还是镜像/旋转图像,十字叉都锚定在该像素上。
const QPointF scenePt(sceneX + 0.5, sceneY + 0.5);
m_crosshairItemPos = m_GraphicsPixmapItemHandle->mapFromScene(scenePt);
repositionCrosshair();
m_hLine->setLine(-m_CrosshairHalfLen, 0.0,
m_CrosshairHalfLen, 0.0);
m_vLine->setLine(0.0, -m_CrosshairHalfLen,
0.0, m_CrosshairHalfLen);
} }
void Mapcavas::removeCrosshair() void Mapcavas::removeCrosshair()
@ -197,6 +343,7 @@ void Mapcavas::removeCrosshair()
delete m_vLine; delete m_vLine;
m_vLine = nullptr; m_vLine = nullptr;
} }
m_crosshairItemPos = QPointF();
} }
@ -376,3 +523,91 @@ MapTool* Mapcavas::mapTool() const
{ {
return m_mapTool; return m_mapTool;
} }
void Mapcavas::addSceneCoordinateSystem()
{
const double length = 200.0;
const double arrowSize = 10.0;
// 坐标系作为参考叠加层,需要始终绘制在图像和其他图元之上;
// 十字叉使用更大的 Z 值(1e9),因此这里取一个略小的值。
const double zOrder = 1e8;
// X 轴
QPen xPen(Qt::red);
xPen.setWidth(2);
QGraphicsLineItem* xAxis = m_qtGraphicsScene->addLine(
0, 0,
length, 0,
xPen
);
xAxis->setZValue(zOrder);
// X 箭头
QPolygonF xArrow;
xArrow << QPointF(length, 0)
<< QPointF(length - arrowSize, -arrowSize / 2)
<< QPointF(length - arrowSize, arrowSize / 2);
QGraphicsPolygonItem* xArrowItem = m_qtGraphicsScene->addPolygon(
xArrow,
xPen,
QBrush(Qt::red)
);
xArrowItem->setZValue(zOrder);
// Y 轴
QPen yPen(Qt::green);
yPen.setWidth(2);
QGraphicsLineItem* yAxis = m_qtGraphicsScene->addLine(
0, 0,
0, length,
yPen
);
yAxis->setZValue(zOrder);
// Y 箭头
QPolygonF yArrow;
yArrow << QPointF(0, length)
<< QPointF(-arrowSize / 2, length - arrowSize)
<< QPointF(arrowSize / 2, length - arrowSize);
QGraphicsPolygonItem* yArrowItem = m_qtGraphicsScene->addPolygon(
yArrow,
yPen,
QBrush(Qt::green)
);
yArrowItem->setZValue(zOrder);
// 原点
QGraphicsEllipseItem* originItem = m_qtGraphicsScene->addEllipse(
-4, -4,
8, 8,
QPen(Qt::blue),
QBrush(Qt::blue)
);
originItem->setZValue(zOrder);
// X 标签
QGraphicsTextItem* xText = m_qtGraphicsScene->addText("X");
xText->setDefaultTextColor(Qt::red);
xText->setPos(length + 5, -15);
xText->setZValue(zOrder);
// Y 标签
QGraphicsTextItem* yText = m_qtGraphicsScene->addText("Y");
yText->setDefaultTextColor(Qt::green);
yText->setPos(5, length + 5);
yText->setZValue(zOrder);
// 原点标签
QGraphicsTextItem* originText = m_qtGraphicsScene->addText("(0, 0)");
originText->setDefaultTextColor(Qt::blue);
originText->setPos(5, 5);
originText->setZValue(zOrder);
}

View File

@ -61,6 +61,16 @@ public:
void unsetMapTool(MapTool* tool); void unsetMapTool(MapTool* tool);
MapTool* mapTool() const; MapTool* mapTool() const;
QGraphicsPixmapItem* pixmapItemHandle();
// 图像显示变换(左右镜像/上下镜像/旋转),状态保存在 AppSettings 中全局生效
void rotateImage90();
void toggleHorizontalMirror();
void toggleVerticalMirror();
// 把当前的镜像/旋转重新应用到已经显示的图像,并按显示模式重新适配视图
void refreshImageTransform();
protected: protected:
QGraphicsScene *m_qtGraphicsScene; QGraphicsScene *m_qtGraphicsScene;
private: private:
@ -79,9 +89,24 @@ private:
double m_CrosshairHalfLen = 10.0; double m_CrosshairHalfLen = 10.0;
QGraphicsLineItem* m_hLine = nullptr; // horizontal line QGraphicsLineItem* m_hLine = nullptr; // horizontal line
QGraphicsLineItem* m_vLine = nullptr; // vertical line QGraphicsLineItem* m_vLine = nullptr; // vertical line
QPointF m_crosshairItemPos; // 十字叉锚点,保存在图像(图元)坐标系
AppSettings::HyperimgDisplayMode m_displayMode; AppSettings::HyperimgDisplayMode m_displayMode;
struct ImageTransformState
{
bool horizontalMirror = true;
bool verticalMirror = true;
int rotation = 90*3; // 0、90、180、270
};
ImageTransformState m_imageTransformState;
void applyImageTransform();
void repositionCrosshair();
void loadSettings();
void addSceneCoordinateSystem();
signals: signals:
void leftMouseButtonPressed(int, int, QVector<double>, QVector<double>); void leftMouseButtonPressed(int, int, QVector<double>, QVector<double>);
}; };

View File

@ -37,21 +37,35 @@ void MapToolSpectral::canvasMousePressEvent(QMouseEvent* e)
if (!canvas()) if (!canvas())
return; return;
const QPointF scenePt = canvas()->mapToScene(e->pos()); //获取图像元素
const int x = static_cast<int>(std::floor(scenePt.x())); QGraphicsPixmapItem* item = canvas()->pixmapItemHandle();
const int y = static_cast<int>(std::floor(scenePt.y())); QPointF scenePos = item->pos();
QPointF scenePos2 = item->scenePos();
if (item==nullptr)
{
return;
}
QPointF scenePt = canvas()->mapToScene(e->pos());
int x_scenePt = static_cast<int>(std::floor(scenePt.x()));
int y_scenePt = static_cast<int>(std::floor(scenePt.y()));
QPointF itemPt = item->mapFromScene(scenePt);
int x_itemPt = static_cast<int>(std::floor(itemPt.x()));
int y_itemPt = static_cast<int>(std::floor(itemPt.y()));
auto* imageLayer = canvas()->imageLayer(); auto* imageLayer = canvas()->imageLayer();
RasterLayer* rl = imageLayer ? imageLayer->layer() : nullptr; RasterLayer* rl = imageLayer ? imageLayer->layer() : nullptr;
if (rl && rl->isValidPixel(x, y)) if (rl && rl->isValidPixel(x_itemPt, y_itemPt))
{ {
canvas()->updateCrosshair(x + 0.5, y + 0.5); canvas()->updateCrosshair(x_scenePt + 0.5, y_scenePt + 0.5);
QVector<double> wavelengths; QVector<double> wavelengths;
QVector<double> spectrum; QVector<double> spectrum;
if (rl->readPixelSpectrum(x, y, wavelengths, spectrum)) if (rl->readPixelSpectrum(x_itemPt, y_itemPt, wavelengths, spectrum))
{ {
emit spectralClicked(x, y, wavelengths, spectrum); emit spectralClicked(x_itemPt, y_itemPt, wavelengths, spectrum);
} }
} }
} }

335
HPPA/MotorConfigDialog.cpp Normal file
View File

@ -0,0 +1,335 @@
#include "MotorConfigDialog.h"
#include <QStyle>
#include <QStyleOptionComboBox>
#include <QStylePainter>
#include <QPaintEvent>
#include <QComboBox>
#include <QFileDialog>
#include <QFormLayout>
#include <QGroupBox>
#include <QHostAddress>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QSpinBox>
#include <QStackedWidget>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
MotorConfigDialog::MotorConfigDialog(const QString& configFilePath, QWidget* parent) : QDialog(parent)
{
ui.setupUi(this);
ui.motorLayout->addStretch();
connect(this->ui.openFileBtn, SIGNAL(clicked()), this, SLOT(onOpenFile()));
connect(this->ui.confirmBtn, SIGNAL(clicked()), this, SLOT(onOk()));
connect(this->ui.cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
loadConfigFile(configFilePath);
}
MotorConfigDialog::~MotorConfigDialog()
{
}
bool MotorConfigDialog::loadConfigFile(const QString& configFilePath)
{
m_configfile.setConfigfilePath(configFilePath.toStdString());
int motorNumber = 0;
bool isValid = true;
QString errorMessage;
if (!m_configfile.isConfigfileExist())
{
isValid = false;
errorMessage = QString::fromLocal8Bit("配置文件不存在:");
}
else if (!m_configfile.parseConfigfile())
{
isValid = false;
errorMessage = QString::fromLocal8Bit("配置文件解析失败:");
}
else if (!m_configfile.getMotorNumber(motorNumber) || motorNumber <= 0)
{
isValid = false;
errorMessage = QString::fromLocal8Bit("配置文件里没有马达信息:");
}
if (!isValid)
{
//载入失败时不能保留上一个文件的界面,避免把配置保存到错误的文件上
clearMotorRows();
ui.configFilePathLineEdit->clear();
ui.confirmBtn->setEnabled(false);
QMessageBox::warning(this, QString::fromLocal8Bit("马达配置"), errorMessage + configFilePath);
return false;
}
m_configFilePath = configFilePath;
ui.configFilePathLineEdit->setText(configFilePath);
ui.confirmBtn->setEnabled(true);
clearMotorRows();
for (int i = 0; i < motorNumber; i++)
{
addMotorRow(i);
}
return true;
}
void MotorConfigDialog::clearMotorRows()
{
m_motorRows.clear();
while (ui.motorLayout->count() > 1)//保留末尾的弹簧
{
QLayoutItem* item = ui.motorLayout->takeAt(0);
if (item->widget() != nullptr)
{
delete item->widget();
}
delete item;
}
}
//不可编辑的QComboBox固定把文字靠左绘制(样式表的text-align和文本对齐角色都不起作用),这里改成居中
class CenteredComboBox : public QComboBox
{
public:
explicit CenteredComboBox(QWidget* parent = nullptr)
: QComboBox(parent)
{
}
protected:
void paintEvent(QPaintEvent* event) override
{
if (isEditable())//可编辑时文字由内部的QLineEdit绘制,对齐方式用setAlignment设置
{
QComboBox::paintEvent(event);
return;
}
QStyleOptionComboBox option;
initStyleOption(&option);
const QString text = option.currentText;
option.currentText.clear();//不画默认的左对齐文字,改由下面居中绘制
QStylePainter painter(this);
painter.setPen(palette().color(QPalette::Text));
painter.drawComplexControl(QStyle::CC_ComboBox, option);
if (!text.isEmpty())
{
QRect textRect = style()->subControlRect(QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxEditField, this);
painter.save();
painter.setClipRect(textRect);
painter.drawText(textRect, Qt::AlignCenter, text);
painter.restore();
}
}
};
//下拉列表(弹出菜单)里每一项的文字居中
static void addCenteredItem(QComboBox* comboBox, const QString& text)
{
comboBox->addItem(text);
comboBox->setItemData(comboBox->count() - 1, Qt::AlignCenter, Qt::TextAlignmentRole);
}
void MotorConfigDialog::addMotorRow(int id)
{
int communicationMethod = 0;//老配置文件没有CommunicationMethod,默认串口
SerialPortConnectionParams serialParams;
TCPConnectionParams tcpParams;
//获取失败时用createVinceConfig里的默认参数
serialParams.SerialPortNumber = "COM7";
serialParams.BaudRate = 9600;
tcpParams.serverIP = "192.168.1.2";
tcpParams.port = 6002;
m_configfile.getCommunicationMethod(id, communicationMethod);
m_configfile.getSerialPortConnectionParams(id, serialParams);
m_configfile.getTcpConnectionParams(id, tcpParams);
if (communicationMethod != 0 && communicationMethod != 1)
{
communicationMethod = 0;
}
QGroupBox* motorGroupBox = new QGroupBox(QString::fromLocal8Bit("马达%1 (motor%2)").arg(id + 1).arg(id + 1), ui.motorContainer);
QFormLayout* groupLayout = new QFormLayout(motorGroupBox);
QLabel* methodLabel = new QLabel(QString::fromLocal8Bit("通信方式"), motorGroupBox);
QComboBox* methodComboBox = new CenteredComboBox(motorGroupBox);
addCenteredItem(methodComboBox, QString::fromLocal8Bit("串口"));
addCenteredItem(methodComboBox, QString::fromLocal8Bit("网络"));
methodComboBox->setItemDelegate(new ComboBoxItemDelegate(methodComboBox));
//串口参数
QWidget* serialWidget = new QWidget(motorGroupBox);
QFormLayout* serialLayout = new QFormLayout(serialWidget);
serialLayout->setContentsMargins(0, 0, 0, 0);
QLabel* serialPortLabel = new QLabel(QString::fromLocal8Bit("串口编号"), serialWidget);
QComboBox* serialPortComboBox = new CenteredComboBox(serialWidget);
serialPortComboBox->setItemDelegate(new ComboBoxItemDelegate(serialPortComboBox));
//serialPortComboBox->setEditable(true);
//查找可用串口,并显示
foreach(const QSerialPortInfo& info, QSerialPortInfo::availablePorts())
{
QSerialPort serial;
serial.setPort(info);
if (serial.open(QIODevice::ReadWrite))
{
addCenteredItem(serialPortComboBox, serial.portName());
serial.close();
}
}
serialPortComboBox->setCurrentText(serialParams.SerialPortNumber);
QLabel* baudRateLabel = new QLabel(QString::fromLocal8Bit("波特率"), serialWidget);
QComboBox* baudRateComboBox = new CenteredComboBox(serialWidget);
baudRateComboBox->setItemDelegate(new ComboBoxItemDelegate(baudRateComboBox));
baudRateComboBox->setEditable(true);
baudRateComboBox->lineEdit()->setAlignment(Qt::AlignCenter);//可编辑下拉框的文字由内部的QLineEdit绘制
addCenteredItem(baudRateComboBox, "9600");
addCenteredItem(baudRateComboBox, "19200");
addCenteredItem(baudRateComboBox, "38400");
addCenteredItem(baudRateComboBox, "57600");
addCenteredItem(baudRateComboBox, "115200");
baudRateComboBox->setCurrentText(QString::number(serialParams.BaudRate));
serialLayout->addRow(serialPortLabel, serialPortComboBox);
serialLayout->addRow(baudRateLabel, baudRateComboBox);
//网络参数
QWidget* tcpWidget = new QWidget(motorGroupBox);
QFormLayout* tcpLayout = new QFormLayout(tcpWidget);
tcpLayout->setContentsMargins(0, 0, 0, 0);
QLabel* serverIPLabel = new QLabel(QString::fromLocal8Bit("服务器IP"), tcpWidget);
QLineEdit* serverIPLineEdit = new QLineEdit(tcpParams.serverIP, tcpWidget);
serverIPLineEdit->setAlignment(Qt::AlignCenter);
QLabel* portLabel = new QLabel(QString::fromLocal8Bit("端口"), tcpWidget);
QSpinBox* portSpinBox = new QSpinBox(tcpWidget);
portSpinBox->setAlignment(Qt::AlignCenter);
portSpinBox->setRange(1, 65535);
portSpinBox->setValue(tcpParams.port);
tcpLayout->addRow(serverIPLabel, serverIPLineEdit);
tcpLayout->addRow(portLabel, portSpinBox);
//
QStackedWidget* paramsStack = new QStackedWidget(motorGroupBox);
paramsStack->addWidget(serialWidget);
paramsStack->addWidget(tcpWidget);
groupLayout->addRow(methodLabel, methodComboBox);
groupLayout->addRow(paramsStack);
methodComboBox->setCurrentIndex(communicationMethod);
paramsStack->setCurrentIndex(communicationMethod);
connect(methodComboBox, SIGNAL(currentIndexChanged(int)), paramsStack, SLOT(setCurrentIndex(int)));
ui.motorLayout->insertWidget(ui.motorLayout->count() - 1, motorGroupBox);
MotorConnectionRow row;
row.methodComboBox = methodComboBox;
row.serialPortComboBox = serialPortComboBox;
row.baudRateComboBox = baudRateComboBox;
row.serverIPLineEdit = serverIPLineEdit;
row.portSpinBox = portSpinBox;
m_motorRows.push_back(row);
}
bool MotorConfigDialog::saveConfigFile()
{
for (int i = 0; i < m_motorRows.size(); i++)
{
const MotorConnectionRow& row = m_motorRows[i];
int communicationMethod = row.methodComboBox->currentIndex();
SerialPortConnectionParams serialParams;
serialParams.SerialPortNumber = row.serialPortComboBox->currentText().trimmed();
bool isBaudRateValid = false;
serialParams.BaudRate = row.baudRateComboBox->currentText().toInt(&isBaudRateValid);
TCPConnectionParams tcpParams;
tcpParams.serverIP = row.serverIPLineEdit->text().trimmed();
tcpParams.port = row.portSpinBox->value();
if (communicationMethod == 0)//串口
{
if (serialParams.SerialPortNumber.isEmpty() || !isBaudRateValid || serialParams.BaudRate <= 0)
{
QMessageBox::warning(this, QString::fromLocal8Bit("马达配置"),
QString::fromLocal8Bit("马达%1的串口参数不正确!").arg(i + 1));
return false;
}
}
else//网络
{
QHostAddress serverIP(tcpParams.serverIP);
if (serverIP.isNull())
{
QMessageBox::warning(this, QString::fromLocal8Bit("马达配置"),
QString::fromLocal8Bit("马达%1的服务器IP不正确!").arg(i + 1));
return false;
}
}
if (!m_configfile.setConnectionParams(i, communicationMethod, serialParams, tcpParams))
{
QMessageBox::warning(this, QString::fromLocal8Bit("马达配置"),
QString::fromLocal8Bit("马达%1的配置写入失败!").arg(i + 1));
return false;
}
}
if (!m_configfile.writeConfig2File())
{
QMessageBox::warning(this, QString::fromLocal8Bit("马达配置"),
QString::fromLocal8Bit("配置文件写入失败:") + m_configFilePath);
return false;
}
return true;
}
void MotorConfigDialog::onOpenFile()
{
QString configFilePath = QFileDialog::getOpenFileName(this,
QString::fromLocal8Bit("选择马达配置文件"),
m_configFilePath,
QString::fromLocal8Bit("配置文件 (*.cfg);;所有文件 (*.*)"));
if (configFilePath.isEmpty())
{
return;
}
loadConfigFile(configFilePath);
}
void MotorConfigDialog::onOk()
{
if (!saveConfigFile())
{
return;
}
QMessageBox::information(this, QString::fromLocal8Bit("马达配置"),
QString::fromLocal8Bit("配置已保存,重新连接马达后生效。"));
accept();
}

66
HPPA/MotorConfigDialog.h Normal file
View File

@ -0,0 +1,66 @@
#pragma once
#include <QtWidgets/qdialog.h>
#include <QVector>
#include <QStyledItemDelegate>
#include "ui_MotorConfigDialog.h"
#include "MotorConfigFile.h"
class QComboBox;
class QLineEdit;
class QSpinBox;
class QStackedWidget;
class ComboBoxItemDelegate : public QStyledItemDelegate
{
public:
explicit ComboBoxItemDelegate(QObject* parent = nullptr)
: QStyledItemDelegate(parent)
{
}
QSize sizeHint(const QStyleOptionViewItem& option,
const QModelIndex& index) const override
{
QSize size = QStyledItemDelegate::sizeHint(option, index);
size.setHeight(25);
return size;
}
};
class MotorConfigDialog :public QDialog
{
Q_OBJECT
public:
MotorConfigDialog(const QString& configFilePath, QWidget* parent = Q_NULLPTR);
~MotorConfigDialog();
private:
//每个马达对应的界面控件
struct MotorConnectionRow
{
QComboBox* methodComboBox;
QComboBox* serialPortComboBox;
QComboBox* baudRateComboBox;
QLineEdit* serverIPLineEdit;
QSpinBox* portSpinBox;
};
bool loadConfigFile(const QString& configFilePath);
void clearMotorRows();
void addMotorRow(int id);
bool saveConfigFile();
Ui::MotorConfigDialog ui;
ConfigfileMultiAxisController m_configfile;
QString m_configFilePath;
QVector<MotorConnectionRow> m_motorRows;
public Q_SLOTS:
void onOpenFile();
void onOk();
};

258
HPPA/MotorConfigDialog.ui Normal file
View File

@ -0,0 +1,258 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MotorConfigDialog</class>
<widget class="QDialog" name="MotorConfigDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>560</width>
<height>398</height>
</rect>
</property>
<property name="windowTitle">
<string>马达配置</string>
</property>
<property name="styleSheet">
<string notr="true">QWidget
{
background: #040125;
/*border-radius: 8px 8px 8px 8px;*/
/*border: 1px solid #2f6bff;*/
}
QLineEdit {
background-color: #142D7F;
color: #e6eeff;
border: 1px solid #2f6bff;
border-radius: 6px;
padding: 4px 8px;
font-size: 13px;
}
QLineEdit:hover {
border: 1px solid #409eff;
}
QLabel {
color: rgb(255, 255, 255);
}
QPushButton
{
/*width: 172px;
height: 56px;*/
font: 10pt &quot;新宋体&quot;;
background-color: qlineargradient(
spread:pad,
x1:0.5, y1:0, x2:0.5, y2:1,
stop:0 #283D86,
stop:1 #0F1A40
);
color: white;
border: none;
padding: 8px 8px;
border-radius: 4px;
}
QPushButton:hover
{
background-color: qlineargradient(
spread:pad,
x1:0, y1:0, x2:1, y2:0,
stop:0 #3A4875,
stop:1 #5F6B91
);
}
/* 按下时的效果 */
QPushButton:pressed
{
background-color: qlineargradient(
spread:pad,
x1:0, y1:0, x2:1, y2:0,
stop:0 #1A254F,
stop:1 #3A466B
);
/* 可选:添加下压效果 */
padding-top: 9px;
padding-bottom: 7px;
}
QGroupBox
{
border: 12px solid transparent;
/*border-top: 12px solid transparent;
border-right: 0px solid transparent;
border-bottom: 0px solid transparent;
border-left: 0px solid transparent;*/
color: #ACCDFF;
}
QComboBox {
background-color: #142D7F;
color: #e6eeff;
border: 1px solid #2f6bff;
border-radius: 6px;
padding: 4px 8px;
font-size: 13px;
}
QComboBox:hover {
border: 1px solid #409eff;
}
/* 下拉列表整体(弹出框) */
QComboBox QAbstractItemView {
color: white;
background-color: #142D7F;
border: 1px solid #2f6bff;
border-radius: 6px;
outline: none; /* 去掉选中项虚线框 */
selection-background-color: #2f6bff;
selection-color: #ffffff;
}
/* 下拉列表的每一项 */
QComboBox QAbstractItemView::item {
height: 40px; /* 项高 */
min-width: 30px;
padding: 10px 0 10px 8px; /* ← 关键,用 padding 撑高 */
color: #e6eeff;
background-color: #142D7F;
}
/* 鼠标悬停的项 */
QComboBox QAbstractItemView::item:hover {
background-color: #2f6bff;
color: #ffffff;
}
/* 被选中的项 */
QComboBox QAbstractItemView::item:selected {
background-color: #2f6bff;
color: #ffffff;
}
QSpinBox {
background-color: #142D7F;
color: #e6eeff;
border: 1px solid #2f6bff;
border-radius: 6px;
padding: 4px 8px;
font-size: 13px;
}
QSpinBox:hover {
border: 1px solid #409eff;
}</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="QGroupBox" name="fileGroupBox">
<property name="title">
<string>配置文件</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLineEdit" name="configFilePathLineEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="openFileBtn">
<property name="text">
<string>打开文件...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QScrollArea" name="motorsScrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="motorContainer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>548</width>
<height>272</height>
</rect>
</property>
<layout class="QVBoxLayout" name="motorLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</widget>
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="buttonLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="confirmBtn">
<property name="text">
<string>保存</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="cancelBtn">
<property name="text">
<string>取消</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -1,4 +1,5 @@
#include "OneMotorControl.h" #include "OneMotorControl.h"
#include "MotorConfigDialog.h"
OneMotorControl::OneMotorControl(QWidget* parent) : QDialog(parent) OneMotorControl::OneMotorControl(QWidget* parent) : QDialog(parent)
{ {
@ -12,6 +13,7 @@ OneMotorControl::OneMotorControl(QWidget* parent) : QDialog(parent)
connect(this->ui.left_btn, SIGNAL(released()), this, SLOT(onxMotorStop())); connect(this->ui.left_btn, SIGNAL(released()), this, SLOT(onxMotorStop()));
connect(this->ui.move2loc_pushButton, SIGNAL(pressed()), this, SLOT(onxMove2Loc())); connect(this->ui.move2loc_pushButton, SIGNAL(pressed()), this, SLOT(onxMove2Loc()));
connect(this->ui.config_pushButton, &QPushButton::clicked, this, &OneMotorControl::editMotorConfigFile);
connect(this->ui.zero_start_btn, SIGNAL(released()), this, SLOT(zeroStart())); connect(this->ui.zero_start_btn, SIGNAL(released()), this, SLOT(zeroStart()));
@ -49,6 +51,31 @@ void OneMotorControl::loadSettings()
ui.reverseMove_radioButton->setChecked(AppSettings::instance().isReverseMove()); ui.reverseMove_radioButton->setChecked(AppSettings::instance().isReverseMove());
} }
QString OneMotorControl::motorConfigFilePath()
{
FileOperation fileOperation;
string directory = fileOperation.getDirectoryOfExe();
return QString::fromStdString(directory) + "\\oneMotorConfigFile.cfg";
}
void OneMotorControl::editMotorConfigFile()
{
if (getMotorsConnectionStatus())
{
QMessageBox msgBox;
msgBox.setText(QString::fromLocal8Bit("马达已连接,修改的配置在重新连接马达后生效。\n采集过程中程序会回写该配置文件,可能会覆盖本次修改,是否继续?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
if (msgBox.exec() != QMessageBox::Yes)
{
return;
}
}
MotorConfigDialog motorConfigDialog(motorConfigFilePath(), this);
motorConfigDialog.exec();
}
void OneMotorControl::onConnectMotor() void OneMotorControl::onConnectMotor()
{ {
connectMotor(true); connectMotor(true);
@ -91,11 +118,7 @@ void OneMotorControl::connectMotor(bool isNotification)
try try
{ {
FileOperation* fileOperation = new FileOperation(); m_multiAxisController = new IrisMultiMotorController(motorConfigFilePath());
string directory = fileOperation->getDirectoryOfExe();
QString configFilePath = QString::fromStdString(directory) + "\\oneMotorConfigFile.cfg";
m_multiAxisController = new IrisMultiMotorController(configFilePath);
} }
catch (std::exception const& e) catch (std::exception const& e)
{ {
@ -386,6 +409,7 @@ OneMotorControl_LiftingPlatform::OneMotorControl_LiftingPlatform(QWidget* parent
connect(this->ui.left_btn, SIGNAL(released()), this, SLOT(onxMotorStop())); connect(this->ui.left_btn, SIGNAL(released()), this, SLOT(onxMotorStop()));
connect(this->ui.move2loc_pushButton, SIGNAL(pressed()), this, SLOT(onxMove2Loc())); connect(this->ui.move2loc_pushButton, SIGNAL(pressed()), this, SLOT(onxMove2Loc()));
connect(this->ui.config_pushButton, &QPushButton::clicked, this, &OneMotorControl_LiftingPlatform::editMotorConfigFile);
connect(this->ui.zero_start_btn, SIGNAL(released()), this, SLOT(zeroStart())); connect(this->ui.zero_start_btn, SIGNAL(released()), this, SLOT(zeroStart()));
@ -418,6 +442,31 @@ void OneMotorControl_LiftingPlatform::loadSettings()
ui.manualMovementSpeed_lineEdit->setText(QString::number(AppSettings::instance().manualMovementSpeed())); ui.manualMovementSpeed_lineEdit->setText(QString::number(AppSettings::instance().manualMovementSpeed()));
} }
QString OneMotorControl_LiftingPlatform::motorConfigFilePath()
{
FileOperation fileOperation;
string directory = fileOperation.getDirectoryOfExe();
return QString::fromStdString(directory) + "\\oneMotorConfigFile_LiftingPlatform.cfg";
}
void OneMotorControl_LiftingPlatform::editMotorConfigFile()
{
if (getMotorsConnectionStatus())
{
QMessageBox msgBox;
msgBox.setText(QString::fromLocal8Bit("马达已连接,修改的配置在重新连接马达后生效。\n采集过程中程序会回写该配置文件,可能会覆盖本次修改,是否继续?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
if (msgBox.exec() != QMessageBox::Yes)
{
return;
}
}
MotorConfigDialog motorConfigDialog(motorConfigFilePath(), this);
motorConfigDialog.exec();
}
void OneMotorControl_LiftingPlatform::onConnectMotor() void OneMotorControl_LiftingPlatform::onConnectMotor()
{ {
connectMotor(true); connectMotor(true);
@ -455,11 +504,7 @@ void OneMotorControl_LiftingPlatform::connectMotor(bool isNotification)
try try
{ {
FileOperation* fileOperation = new FileOperation(); m_multiAxisController = new IrisMultiMotorController(motorConfigFilePath());
string directory = fileOperation->getDirectoryOfExe();
QString configFilePath = QString::fromStdString(directory) + "\\oneMotorConfigFile_LiftingPlatform.cfg";
m_multiAxisController = new IrisMultiMotorController(configFilePath);
} }
catch (std::exception const& e) catch (std::exception const& e)
{ {

View File

@ -53,6 +53,9 @@ public Q_SLOTS:
void onSequenceComplete_motorBack2Origin(int state); void onSequenceComplete_motorBack2Origin(int state);
void onSequenceComplete_gonggashan_autoexpose(int state); void onSequenceComplete_gonggashan_autoexpose(int state);
private Q_SLOTS:
void editMotorConfigFile();
signals: signals:
void moveSignal(int, double, int); void moveSignal(int, double, int);
void move2LocSignal(int, double, double, int); void move2LocSignal(int, double, double, int);
@ -94,6 +97,7 @@ private:
QPointer<OneMotorMultiPosCoordinator> m_coordinator_gonggashan_autoexpose; QPointer<OneMotorMultiPosCoordinator> m_coordinator_gonggashan_autoexpose;
void loadSettings(); void loadSettings();
QString motorConfigFilePath();
}; };
class OneMotorControl_LiftingPlatform : public QDialog, public MotorWindowBase class OneMotorControl_LiftingPlatform : public QDialog, public MotorWindowBase
@ -126,6 +130,9 @@ public Q_SLOTS:
void onBack2Origin(double pos); void onBack2Origin(double pos);
private Q_SLOTS:
void editMotorConfigFile();
signals: signals:
void moveSignal(int, double, int); void moveSignal(int, double, int);
void move2LocSignal(int, double, double, int); void move2LocSignal(int, double, double, int);
@ -155,4 +162,6 @@ private:
bool m_xMotorConnectionStatus = false; bool m_xMotorConnectionStatus = false;
void loadSettings(); void loadSettings();
QString motorConfigFilePath();
}; };

View File

@ -1,5 +1,7 @@
#include "TwoMotorControl.h" #include "TwoMotorControl.h"
#include "MotorConfigDialog.h"
TwoMotorControl::TwoMotorControl(QWidget* parent) : QDialog(parent) TwoMotorControl::TwoMotorControl(QWidget* parent) : QDialog(parent)
{ {
ui.setupUi(this); ui.setupUi(this);
@ -12,6 +14,7 @@ TwoMotorControl::TwoMotorControl(QWidget* parent) : QDialog(parent)
//headerView->setHidden(true);//去除左边默认自带序列号 //headerView->setHidden(true);//去除左边默认自带序列号
connect(this->ui.connect_btn, SIGNAL(pressed()), this, SLOT(onConnectMotor())); connect(this->ui.connect_btn, SIGNAL(pressed()), this, SLOT(onConnectMotor()));
connect(this->ui.motorConfig_btn, SIGNAL(clicked()), this, SLOT(onMotorConfig()));
connect(ui.addRecordLine_btn, SIGNAL(clicked()), this, SLOT(onAddRecordLine_btn())); connect(ui.addRecordLine_btn, SIGNAL(clicked()), this, SLOT(onAddRecordLine_btn()));
connect(ui.removeRecordLine_btn, SIGNAL(clicked()), this, SLOT(onRemoveRecordLine_btn())); connect(ui.removeRecordLine_btn, SIGNAL(clicked()), this, SLOT(onRemoveRecordLine_btn()));
@ -369,6 +372,31 @@ void TwoMotorControl::onConnectMotor()
connectMotor(true); connectMotor(true);
} }
QString TwoMotorControl::motorConfigFilePath()
{
FileOperation fileOperation;
string directory = fileOperation.getDirectoryOfExe();
return QString::fromStdString(directory) + "\\twoMotorConfigFile.cfg";
}
void TwoMotorControl::onMotorConfig()
{
if (getMotorsConnectionStatus())
{
QMessageBox msgBox;
msgBox.setText(QString::fromLocal8Bit("马达已连接,修改的配置在重新连接马达后生效。\n采集过程中程序会回写该配置文件,可能会覆盖本次修改,是否继续?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
if (msgBox.exec() != QMessageBox::Yes)
{
return;
}
}
MotorConfigDialog motorConfigDialog(motorConfigFilePath(), this);
motorConfigDialog.exec();
}
void TwoMotorControl::connectMotor(bool isNotification) void TwoMotorControl::connectMotor(bool isNotification)
{ {
if (getMotorsConnectionStatus()) if (getMotorsConnectionStatus())
@ -401,11 +429,7 @@ void TwoMotorControl::connectMotor(bool isNotification)
try try
{ {
FileOperation* fileOperation = new FileOperation(); m_multiAxisController = new IrisMultiMotorController(motorConfigFilePath());
string directory = fileOperation->getDirectoryOfExe();
QString configFilePath = QString::fromStdString(directory) + "\\twoMotorConfigFile.cfg";
m_multiAxisController = new IrisMultiMotorController(configFilePath);
} }
catch (std::exception const& e) catch (std::exception const& e)
{ {

View File

@ -45,6 +45,8 @@ private:
ImagerOperationBase* m_Imager; ImagerOperationBase* m_Imager;
bool getState(); bool getState();
QString motorConfigFilePath();
bool isWritePosFile = false; bool isWritePosFile = false;
QString m_posFileName; QString m_posFileName;
FILE* m_posFileHandle; FILE* m_posFileHandle;
@ -54,6 +56,7 @@ private:
public Q_SLOTS: public Q_SLOTS:
void onConnectMotor(); void onConnectMotor();
void onMotorConfig();
void displayRealTimeLoc(std::vector<double> loc); void displayRealTimeLoc(std::vector<double> loc);
void display_motors_connectivity(std::vector<int> connectivity); void display_motors_connectivity(std::vector<int> connectivity);

View File

@ -288,7 +288,7 @@ QPushButton:pressed
}</string> }</string>
</property> </property>
<property name="text"> <property name="text">
<string>版本:3.1.4</string> <string>版本:3.1.5</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -57,6 +57,8 @@ focusWindow::focusWindow(QWidget *parent, ImagerOperationBase* imager)
ui.stackedWidget_connetcParm->setCurrentIndex(checked ? 0 : 1); ui.stackedWidget_connetcParm->setCurrentIndex(checked ? 0 : 1);
}); });
connect(this->ui.config_pushButton, &QPushButton::clicked, this, &focusWindow::editMotorConfigFile);
//查找可用串口,并显示 //查找可用串口,并显示
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{ {
@ -129,6 +131,31 @@ focusWindow::~focusWindow()
m_MotionCaptureCoordinatorThread.wait(); m_MotionCaptureCoordinatorThread.wait();
} }
QString focusWindow::motorConfigFilePath()
{
FileOperation fileOperation;
string directory = fileOperation.getDirectoryOfExe();
return QString::fromStdString(directory) + "\\oneMotorConfigFile_focus.cfg";
}
void focusWindow::editMotorConfigFile()
{
if (getMotorsConnectionStatus())
{
QMessageBox msgBox;
msgBox.setText(QString::fromLocal8Bit("马达已连接,修改的配置在重新连接马达后生效。\n采集过程中程序会回写该配置文件,可能会覆盖本次修改,是否继续?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
if (msgBox.exec() != QMessageBox::Yes)
{
return;
}
}
MotorConfigDialog motorConfigDialog(motorConfigFilePath(), this);
motorConfigDialog.exec();
}
void focusWindow::onExit() void focusWindow::onExit()
{ {
this->close(); this->close();
@ -310,11 +337,7 @@ void focusWindow::connectMotor(bool isNotification)//需要修改这个函数
try try
{ {
FileOperation* fileOperation = new FileOperation(); m_multiAxisController = new IrisMultiMotorController(motorConfigFilePath());
string directory = fileOperation->getDirectoryOfExe();
QString configFilePath = QString::fromStdString(directory) + "\\oneMotorConfigFile_focus.cfg";
m_multiAxisController = new IrisMultiMotorController(configFilePath);
} }
catch (std::exception const& e) catch (std::exception const& e)
{ {

View File

@ -34,6 +34,8 @@
#include <Eigen/Dense> #include <Eigen/Dense>
#include <cmath> #include <cmath>
#include "MotorConfigDialog.h"
// 数据记录结构体 // 数据记录结构体
struct PositionData { struct PositionData {
double targetPosition; // 目标位置 double targetPosition; // 目标位置
@ -156,6 +158,8 @@ private:
bool m_isDisplaysAutofocusResultViaPopup = true; bool m_isDisplaysAutofocusResultViaPopup = true;
QString motorConfigFilePath();
public Q_SLOTS: public Q_SLOTS:
void onConnectMotor(); void onConnectMotor();
void onMove2MotorLogicZero(); void onMove2MotorLogicZero();
@ -179,6 +183,9 @@ public Q_SLOTS:
void display_motors_connectivity(std::vector<int> connectivity); void display_motors_connectivity(std::vector<int> connectivity);
private Q_SLOTS:
void editMotorConfigFile();
signals: signals:
void StartManualFocusSignal(int);//1:开始调焦;0:停止调焦; void StartManualFocusSignal(int);//1:开始调焦;0:停止调焦;

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>678</width> <width>532</width>
<height>480</height> <height>469</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -84,7 +84,7 @@ QLineEdit:focus {
background-color: #23345c; background-color: #23345c;
}</string> }</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_4"> <layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="1"> <item row="0" column="1">
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
@ -116,151 +116,43 @@ QLineEdit:focus {
<property name="spacing"> <property name="spacing">
<number>10</number> <number>10</number>
</property> </property>
<item row="1" column="1"> <item row="6" column="3">
<widget class="QLineEdit" name="scanSpeed_lineEdit"> <widget class="QWidget" name="widget_2" native="true">
<property name="sizePolicy"> <layout class="QGridLayout" name="gridLayout_2">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <item row="0" column="0">
<horstretch>0</horstretch> <widget class="QRadioButton" name="reverseMove_radioButton">
<verstretch>0</verstretch> <property name="styleSheet">
</sizepolicy> <string notr="true"/>
</property> </property>
<property name="minimumSize"> <property name="text">
<size> <string>反转</string>
<width>88</width> </property>
<height>30</height> </widget>
</size> </item>
</property> <item row="0" column="1">
<property name="maximumSize"> <widget class="QLabel" name="motor_state_label">
<size> <property name="maximumSize">
<width>16777215</width> <size>
<height>16777215</height> <width>8</width>
</size> <height>8</height>
</property> </size>
<property name="styleSheet"> </property>
<string notr="true"/> <property name="sizeIncrement">
</property> <size>
<property name="text"> <width>8</width>
<string>0.1</string> <height>8</height>
</property> </size>
<property name="alignment"> </property>
<set>Qt::AlignCenter</set> <property name="styleSheet">
</property> <string notr="true">background-color: red;
</widget> border-radius: 4px;</string>
</item> </property>
<item row="4" column="2"> <property name="text">
<widget class="QPushButton" name="move2loc_pushButton"> <string/>
<property name="sizePolicy"> </property>
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> </widget>
<horstretch>0</horstretch> </item>
<verstretch>0</verstretch> </layout>
</sizepolicy>
</property>
<property name="text">
<string>移动至</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="rangeMeasurement_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>量程测量</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="zero_start_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>归零</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="left_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>←0</string>
</property>
</widget>
</item>
<item row="5" column="2">
<widget class="QPushButton" name="right_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>→</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="move2loc_lineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>88</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>扫描速度</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="connect_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>连接</string>
</property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="6" column="1">
@ -275,7 +167,7 @@ QLineEdit:focus {
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>实时位置:</string> <string>位置:</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>
@ -342,6 +234,22 @@ QLineEdit:focus {
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>返回速度</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QLineEdit" name="return_speed_lineEdit"> <widget class="QLineEdit" name="return_speed_lineEdit">
<property name="sizePolicy"> <property name="sizePolicy">
@ -364,8 +272,43 @@ QLineEdit:focus {
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="4" column="1">
<widget class="QLabel" name="label_3"> <widget class="QLineEdit" name="move2loc_lineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>88</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="zero_start_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>归零</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding"> <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
@ -373,52 +316,143 @@ QLineEdit:focus {
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>返回速度</string> <string>扫描速度</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="2"> <item row="1" column="3">
<widget class="QWidget" name="widget_2" native="true"> <widget class="QPushButton" name="connect_btn">
<layout class="QGridLayout" name="gridLayout_2"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>连接</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="rangeMeasurement_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>量程测量</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="scanSpeed_lineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>88</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>0.1</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QPushButton" name="move2loc_pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>移动至</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QWidget" name="widget_3" native="true">
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="horizontalSpacing">
<number>6</number>
</property>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QRadioButton" name="reverseMove_radioButton"> <widget class="QPushButton" name="left_btn">
<property name="styleSheet"> <property name="sizePolicy">
<string notr="true"/> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>反转</string> <string>←0</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QLabel" name="motor_state_label"> <widget class="QPushButton" name="right_btn">
<property name="maximumSize"> <property name="sizePolicy">
<size> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<width>8</width> <horstretch>0</horstretch>
<height>8</height> <verstretch>0</verstretch>
</size> </sizepolicy>
</property>
<property name="sizeIncrement">
<size>
<width>8</width>
<height>8</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: red;
border-radius: 4px;</string>
</property> </property>
<property name="text"> <property name="text">
<string/> <string>→</string>
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="5" column="3">
<widget class="QPushButton" name="config_pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>配置</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item row="1" column="2"> <item row="1" column="2">

View File

@ -297,6 +297,19 @@ QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QPushButton" name="motorConfig_btn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>配置</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>