add,计划采集3:
实现部分计划采集功能
This commit is contained in:
@ -575,6 +575,10 @@ HPPA::HPPA(QWidget* parent)
|
|||||||
|
|
||||||
initMapTools();
|
initMapTools();
|
||||||
|
|
||||||
|
//定时采集
|
||||||
|
connect(this->ui.mActionTimedDataCollection, SIGNAL(triggered()), this, SLOT(onTimedDataCollection()));
|
||||||
|
mTimedDataCollectionWindow = new TimedDataCollection(m_tmc);
|
||||||
|
|
||||||
QString strPath = QCoreApplication::applicationDirPath() + "/UILayout.ini";
|
QString strPath = QCoreApplication::applicationDirPath() + "/UILayout.ini";
|
||||||
QFile file(strPath);
|
QFile file(strPath);
|
||||||
if (file.open(QIODevice::ReadOnly))
|
if (file.open(QIODevice::ReadOnly))
|
||||||
@ -588,6 +592,23 @@ HPPA::HPPA(QWidget* parent)
|
|||||||
this->showMaximized();
|
this->showMaximized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HPPA::onTimedDataCollection()
|
||||||
|
{
|
||||||
|
QAction* checkedScenario = m_ScenarioActionGroup->checkedAction();
|
||||||
|
QString checkedScenarioName = checkedScenario->objectName();
|
||||||
|
if (checkedScenarioName == "mAction3DPlantPhenotypeScenario")//计划采集
|
||||||
|
{
|
||||||
|
mTimedDataCollectionWindow->show();
|
||||||
|
//mTimedDataCollectionWindow->exec();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (checkedScenarioName == "mActionPlantPhenotypeScenario")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HPPA::initMenubarToolbar()
|
void HPPA::initMenubarToolbar()
|
||||||
{
|
{
|
||||||
//自定义菜单栏和工具栏
|
//自定义菜单栏和工具栏
|
||||||
@ -1523,22 +1544,6 @@ bool HPPA::showResultMessageBox(QString title, QString msg)
|
|||||||
|
|
||||||
void HPPA::onStartRecordStep1()
|
void HPPA::onStartRecordStep1()
|
||||||
{
|
{
|
||||||
QAction* checkedScenario = m_ScenarioActionGroup->checkedAction();
|
|
||||||
QString checkedScenarioName = checkedScenario->objectName();
|
|
||||||
if (checkedScenarioName == "mAction3DPlantPhenotypeScenario")//计划采集
|
|
||||||
{
|
|
||||||
TimedDataCollection* tmp = new TimedDataCollection();
|
|
||||||
/*m_ic->setWindowFlags(Qt::Widget);*/
|
|
||||||
tmp->show();
|
|
||||||
//tmp->exec();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (checkedScenarioName == "mActionPlantPhenotypeScenario")
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//判断移动平台
|
//判断移动平台
|
||||||
QAction* checked = moveplatformActionGroup->checkedAction();
|
QAction* checked = moveplatformActionGroup->checkedAction();
|
||||||
if (!checked)
|
if (!checked)
|
||||||
|
|||||||
@ -318,6 +318,8 @@ private:
|
|||||||
bool showResultMessageBox(QString title, QString msg);
|
bool showResultMessageBox(QString title, QString msg);
|
||||||
void disconnectImagerAndCleanup();
|
void disconnectImagerAndCleanup();
|
||||||
|
|
||||||
|
TimedDataCollection* mTimedDataCollectionWindow;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QString filePath);
|
void onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber, QString filePath);
|
||||||
void focusPlotSpectralImg(int state);
|
void focusPlotSpectralImg(int state);
|
||||||
@ -395,6 +397,8 @@ public Q_SLOTS:
|
|||||||
|
|
||||||
void onMapToolPanTriggered();
|
void onMapToolPanTriggered();
|
||||||
void onMapToolSpectralTriggered();
|
void onMapToolSpectralTriggered();
|
||||||
|
|
||||||
|
void onTimedDataCollection();
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent* event) override;
|
void closeEvent(QCloseEvent* event) override;
|
||||||
|
|
||||||
|
|||||||
@ -105,6 +105,7 @@ color:white;
|
|||||||
<addaction name="action_start_recording"/>
|
<addaction name="action_start_recording"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionOpenDirectory"/>
|
<addaction name="actionOpenDirectory"/>
|
||||||
|
<addaction name="mActionTimedDataCollection"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuhelp">
|
<widget class="QMenu" name="menuhelp">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -743,6 +744,11 @@ QPushButton:pressed
|
|||||||
<string>3D植物表型</string>
|
<string>3D植物表型</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="mActionTimedDataCollection">
|
||||||
|
<property name="text">
|
||||||
|
<string>定时采集</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
|||||||
@ -254,7 +254,7 @@
|
|||||||
<QtMoc Include="rgbCameraWindow.h" />
|
<QtMoc Include="rgbCameraWindow.h" />
|
||||||
<QtMoc Include="SingleLensReflexCameraWindow.h" />
|
<QtMoc Include="SingleLensReflexCameraWindow.h" />
|
||||||
<QtMoc Include="TimedDataCollection.h" />
|
<QtMoc Include="TimedDataCollection.h" />
|
||||||
<ClInclude Include="TimedDataCollectionDataStructures.h" />
|
<QtMoc Include="TimedDataCollectionDataStructures.h" />
|
||||||
<ClInclude Include="utility_tc.h" />
|
<ClInclude Include="utility_tc.h" />
|
||||||
<QtMoc Include="aboutWindow.h" />
|
<QtMoc Include="aboutWindow.h" />
|
||||||
<ClInclude Include="hppaConfigFile.h" />
|
<ClInclude Include="hppaConfigFile.h" />
|
||||||
|
|||||||
@ -384,6 +384,9 @@
|
|||||||
<QtMoc Include="TimedDataCollection.h">
|
<QtMoc Include="TimedDataCollection.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</QtMoc>
|
</QtMoc>
|
||||||
|
<QtMoc Include="TimedDataCollectionDataStructures.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</QtMoc>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="imageProcessor.h">
|
<ClInclude Include="imageProcessor.h">
|
||||||
@ -440,9 +443,6 @@
|
|||||||
<ClInclude Include="MotorWindowBase.h">
|
<ClInclude Include="MotorWindowBase.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="TimedDataCollectionDataStructures.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<QtUic Include="FocusDialog.ui">
|
<QtUic Include="FocusDialog.ui">
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
#include "TimedDataCollection.h"
|
#include "TimedDataCollection.h"
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include "TwoMotorControl.h"
|
||||||
|
|
||||||
TimedDataCollection::TimedDataCollection(QWidget* parent)
|
TimedDataCollection::TimedDataCollection(TwoMotorControl* motorControl, QWidget* parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
|
, m_motorControl(nullptr)
|
||||||
|
, m_scheduler(nullptr)
|
||||||
{
|
{
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
|
|
||||||
@ -12,21 +15,52 @@ TimedDataCollection::TimedDataCollection(QWidget* parent)
|
|||||||
ui.treeWidget->setDropIndicatorShown(true); // 显示插入位置指示线
|
ui.treeWidget->setDropIndicatorShown(true); // 显示插入位置指示线
|
||||||
ui.treeWidget->setDragDropMode(QAbstractItemView::InternalMove); // 内部移动
|
ui.treeWidget->setDragDropMode(QAbstractItemView::InternalMove); // 内部移动
|
||||||
|
|
||||||
|
// 初始化调度器
|
||||||
|
m_scheduler = new TaskScheduler(this);
|
||||||
|
|
||||||
|
// 连接调度器信号
|
||||||
|
connect(m_scheduler, &TaskScheduler::taskStarted, this, &TimedDataCollection::taskStarted);
|
||||||
|
connect(m_scheduler, &TaskScheduler::taskFinished, this, &TimedDataCollection::taskFinished);
|
||||||
|
connect(m_scheduler, &TaskScheduler::subTaskStarted, this, &TimedDataCollection::subTaskStarted);
|
||||||
|
connect(m_scheduler, &TaskScheduler::subTaskFinished, this, &TimedDataCollection::subTaskFinished);
|
||||||
|
connect(m_scheduler, &TaskScheduler::motorPositionUpdated, this, &TimedDataCollection::motorPositionUpdated);
|
||||||
|
connect(m_scheduler, &TaskScheduler::errorOccurred, this, &TimedDataCollection::errorOccurred);
|
||||||
|
|
||||||
//writeRead();
|
//writeRead();
|
||||||
readTimedTaskFromFile("D:/0tmp/3Dtest/task.json");
|
readTimedTaskFromFile("D:/0tmp/3Dtest/task.json");
|
||||||
|
|
||||||
connect(ui.run_btn, SIGNAL(clicked()), this, SLOT(run()));
|
// 加载任务到调度器
|
||||||
|
m_scheduler->loadTasks(m_loadedTasks);
|
||||||
|
|
||||||
connect(ui.run_btn, &QPushButton::clicked, this, &TimedDataCollection::run);
|
connect(ui.run_btn, &QPushButton::clicked, this, &TimedDataCollection::startScheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimedDataCollection::~TimedDataCollection()
|
TimedDataCollection::~TimedDataCollection()
|
||||||
{
|
{
|
||||||
|
if (m_scheduler) {
|
||||||
|
m_scheduler->stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimedDataCollection::run()
|
void TimedDataCollection::startScheduler()
|
||||||
{
|
{
|
||||||
|
if (m_scheduler) {
|
||||||
|
m_scheduler->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimedDataCollection::stopScheduler()
|
||||||
|
{
|
||||||
|
if (m_scheduler) {
|
||||||
|
m_scheduler->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimedDataCollection::setMotorControl(TwoMotorControl* motorControl)
|
||||||
|
{
|
||||||
|
if (m_scheduler) {
|
||||||
|
m_scheduler->setMotorControl(motorControl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
|
void TimedDataCollection::readTimedTaskFromFile(const QString& filePath)
|
||||||
|
|||||||
@ -8,23 +8,39 @@
|
|||||||
#include "ui_TimedDataCollection_ui.h"
|
#include "ui_TimedDataCollection_ui.h"
|
||||||
#include "TimedDataCollectionDataStructures.h"
|
#include "TimedDataCollectionDataStructures.h"
|
||||||
|
|
||||||
|
class TwoMotorControl;
|
||||||
|
|
||||||
class TimedDataCollection : public QDialog
|
class TimedDataCollection : public QDialog
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TimedDataCollection(QWidget* parent = nullptr);
|
TimedDataCollection(TwoMotorControl* motorControl, QWidget* parent = nullptr);
|
||||||
~TimedDataCollection();
|
~TimedDataCollection();
|
||||||
|
|
||||||
void readTimedTaskFromFile(const QString& filePath);
|
void readTimedTaskFromFile(const QString& filePath);
|
||||||
|
|
||||||
|
// 设置马达控制器供调度器使用
|
||||||
|
void setMotorControl(TwoMotorControl* motorControl);
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void run();
|
void startScheduler();
|
||||||
|
void stopScheduler();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void taskStarted(int taskId);
|
||||||
|
void taskFinished(int taskId, bool success);
|
||||||
|
void subTaskStarted(int taskId, int subTaskIndex);
|
||||||
|
void subTaskFinished(int taskId, int subTaskIndex);
|
||||||
|
void motorPositionUpdated(double x, double y);
|
||||||
|
void errorOccurred(const QString& error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::TimedDataCollection_ui ui;
|
Ui::TimedDataCollection_ui ui;
|
||||||
|
TwoMotorControl* m_motorControl;
|
||||||
|
|
||||||
void writeRead();
|
void writeRead();
|
||||||
|
|
||||||
QVector<TimedTask> m_loadedTasks;
|
QVector<TimedTask> m_loadedTasks;
|
||||||
|
TaskScheduler* m_scheduler;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
#include "TimedDataCollectionDataStructures.h"
|
#include "TimedDataCollectionDataStructures.h"
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
@ -194,3 +194,337 @@ bool TimedDataCollectionDataStructuresReaderWriter::jsonToTimedTask(const QJsonO
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== TaskExecutor 实现 ====================
|
||||||
|
|
||||||
|
TaskExecutor::TaskExecutor(TwoMotorControl* motorControl, QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_motorControl(motorControl)
|
||||||
|
, m_currentSubTaskIndex(0)
|
||||||
|
, m_isRunning(false)
|
||||||
|
{
|
||||||
|
if (m_motorControl) {
|
||||||
|
connect(m_motorControl, &TwoMotorControl::broadcastLocationSignal,
|
||||||
|
this, &TaskExecutor::onMotorLocationUpdate);
|
||||||
|
//connect(m_motorControl, &TwoMotorControl::sequenceComplete,
|
||||||
|
// this, &TaskExecutor::onSequenceComplete);
|
||||||
|
//connect(m_motorControl, &TwoMotorControl::errorOccurred,
|
||||||
|
// this, &TaskExecutor::onError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskExecutor::~TaskExecutor()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskExecutor::execute(const TimedTask& task)
|
||||||
|
{
|
||||||
|
if (m_isRunning) {
|
||||||
|
qWarning() << "TaskExecutor: Already running, ignoring execute request";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_task = task;
|
||||||
|
m_currentSubTaskIndex = 0;
|
||||||
|
m_isRunning = true;
|
||||||
|
|
||||||
|
qDebug() << "TaskExecutor: Starting task" << task.id;
|
||||||
|
|
||||||
|
// 开始执行第一个子任务
|
||||||
|
executeNextSubTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskExecutor::stop()
|
||||||
|
{
|
||||||
|
if (!m_isRunning) return;
|
||||||
|
|
||||||
|
qDebug() << "TaskExecutor: Stopping task" << m_task.id;
|
||||||
|
|
||||||
|
if (m_motorControl) {
|
||||||
|
m_motorControl->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_isRunning = false;
|
||||||
|
emit finished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskExecutor::onSequenceComplete(int status)
|
||||||
|
{
|
||||||
|
if (!m_isRunning) return;
|
||||||
|
|
||||||
|
qDebug() << "TaskExecutor: Sequence complete, status:" << status;
|
||||||
|
|
||||||
|
// 更新当前子任务状态
|
||||||
|
if (m_currentSubTaskIndex < m_task.subTasks.size()) {
|
||||||
|
SubTask& subTask = m_task.subTasks[m_currentSubTaskIndex];
|
||||||
|
subTask.status = (status == 0) ? TaskStatus::Finished : TaskStatus::Waiting;
|
||||||
|
|
||||||
|
emit subTaskFinished(m_currentSubTaskIndex, subTask.type, (status == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否还有更多子任务
|
||||||
|
m_currentSubTaskIndex++;
|
||||||
|
if (m_currentSubTaskIndex < m_task.subTasks.size()) {
|
||||||
|
// 执行下一个子任务
|
||||||
|
QTimer::singleShot(100, this, &TaskExecutor::executeNextSubTask);
|
||||||
|
} else {
|
||||||
|
// 所有子任务完成
|
||||||
|
m_isRunning = false;
|
||||||
|
qDebug() << "TaskExecutor: All subtasks completed";
|
||||||
|
emit finished(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskExecutor::onMotorLocationUpdate(std::vector<double> loc)
|
||||||
|
{
|
||||||
|
if (loc.size() >= 2) {
|
||||||
|
emit motorPositionUpdated(loc[0], loc[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskExecutor::onError(const QString& error)
|
||||||
|
{
|
||||||
|
if (!m_isRunning) return;
|
||||||
|
|
||||||
|
qWarning() << "TaskExecutor: Error occurred:" << error;
|
||||||
|
m_isRunning = false;
|
||||||
|
emit errorOccurred(error);
|
||||||
|
emit finished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskExecutor::executeNextSubTask()
|
||||||
|
{
|
||||||
|
if (!m_isRunning || m_currentSubTaskIndex >= m_task.subTasks.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubTask& subTask = m_task.subTasks[m_currentSubTaskIndex];
|
||||||
|
subTask.status = TaskStatus::Running;
|
||||||
|
subTask.startTime = QDateTime::currentDateTime();
|
||||||
|
|
||||||
|
qDebug() << "TaskExecutor: Starting subtask" << m_currentSubTaskIndex
|
||||||
|
<< "type:" << static_cast<int>(subTask.type);
|
||||||
|
|
||||||
|
emit subTaskStarted(m_currentSubTaskIndex, subTask.type);
|
||||||
|
|
||||||
|
//根据任务类型切换相机类型,还需要考虑相关信号和槽
|
||||||
|
|
||||||
|
// 如果有路径线文件,加载路径线并启动马达
|
||||||
|
if (!subTask.pathLineFilePath.isEmpty()) {
|
||||||
|
loadPathLinesFromFile(subTask.pathLineFilePath);
|
||||||
|
} else {
|
||||||
|
qDebug() << "TaskExecutor: No path line file for subtask";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskExecutor::loadPathLinesFromFile(const QString& filePath)
|
||||||
|
{
|
||||||
|
// 从 .RecordLine3 文件加载路径线
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
qWarning() << "TaskExecutor: Failed to open path line file:" << filePath;
|
||||||
|
emit errorOccurred("Failed to open path line file: " + filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double number;
|
||||||
|
file.read(reinterpret_cast<char*>(&number), sizeof(double));
|
||||||
|
|
||||||
|
QVector<PathLine> pathLines;
|
||||||
|
for (int i = 0; i < static_cast<int>(number) / 6; ++i) {
|
||||||
|
PathLine line;
|
||||||
|
for (int j = 0; j < 6; ++j) {
|
||||||
|
double value;
|
||||||
|
file.read(reinterpret_cast<char*>(&value), sizeof(double));
|
||||||
|
switch (j) {
|
||||||
|
case 0: line.targetYPosition = value; break;
|
||||||
|
case 1: line.speedTargetYPosition = value; break;
|
||||||
|
case 2: line.targetXMinPosition = value; break;
|
||||||
|
case 3: line.speedTargetXMinPosition = value; break;
|
||||||
|
case 4: line.targetXMaxPosition = value; break;
|
||||||
|
case 5: line.speedTargetXMaxPosition = value; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pathLines.append(line);
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
qDebug() << "TaskExecutor: Loaded" << pathLines.size() << "path lines from" << filePath;
|
||||||
|
|
||||||
|
// 通知马达控制器开始执行
|
||||||
|
if (m_motorControl) {
|
||||||
|
emit m_motorControl->start(pathLines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== TaskScheduler 实现 ====================
|
||||||
|
|
||||||
|
TaskScheduler::TaskScheduler(QObject* parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_timer(nullptr)
|
||||||
|
, m_motorControl(nullptr)
|
||||||
|
, m_currentExecutor(nullptr)
|
||||||
|
, m_currentTaskId(-1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskScheduler::~TaskScheduler()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::setMotorControl(TwoMotorControl* motorControl)
|
||||||
|
{
|
||||||
|
m_motorControl = motorControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::loadTasks(const QVector<TimedTask>& tasks)
|
||||||
|
{
|
||||||
|
m_tasks = tasks;
|
||||||
|
qDebug() << "TaskScheduler: Loaded" << tasks.size() << "tasks";
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::start()
|
||||||
|
{
|
||||||
|
if (m_timer) {
|
||||||
|
qDebug() << "TaskScheduler: Already running";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "TaskScheduler: Starting";
|
||||||
|
|
||||||
|
m_timer = new QTimer(this);
|
||||||
|
connect(m_timer, &QTimer::timeout, this, &TaskScheduler::checkTasks);
|
||||||
|
m_timer->start(1000); // 每秒检查一次
|
||||||
|
|
||||||
|
emit schedulerStateChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::stop()
|
||||||
|
{
|
||||||
|
if (m_timer) {
|
||||||
|
m_timer->stop();
|
||||||
|
delete m_timer;
|
||||||
|
m_timer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_currentExecutor) {
|
||||||
|
m_currentExecutor->stop();
|
||||||
|
m_currentExecutor->deleteLater();
|
||||||
|
m_currentExecutor = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "TaskScheduler: Stopped";
|
||||||
|
emit schedulerStateChanged(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::checkTasks()
|
||||||
|
{
|
||||||
|
if (!m_motorControl) return;
|
||||||
|
|
||||||
|
QDateTime now = QDateTime::currentDateTime();
|
||||||
|
|
||||||
|
for (auto& task : m_tasks) {
|
||||||
|
if (task.status != TaskStatus::Waiting) continue;
|
||||||
|
if (task.scheduledTime > now) continue;
|
||||||
|
|
||||||
|
// 到达计划时间,启动任务
|
||||||
|
executeTask(task);
|
||||||
|
break; // 一次只执行一个任务
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::onTaskFinished(bool success)
|
||||||
|
{
|
||||||
|
if (m_currentTaskId > 0) {
|
||||||
|
TaskStatus status = success ? TaskStatus::Finished : TaskStatus::Waiting;
|
||||||
|
updateTaskStatus(m_currentTaskId, status);
|
||||||
|
emit taskFinished(m_currentTaskId, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理执行器
|
||||||
|
if (m_currentExecutor) {
|
||||||
|
m_currentExecutor->deleteLater();
|
||||||
|
m_currentExecutor = nullptr;
|
||||||
|
}
|
||||||
|
m_currentTaskId = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::onSubTaskStarted(int subTaskIndex, SubTaskType type)
|
||||||
|
{
|
||||||
|
if (m_currentTaskId > 0) {
|
||||||
|
emit subTaskStarted(m_currentTaskId, subTaskIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::onSubTaskFinished(int subTaskIndex, SubTaskType type, bool success)
|
||||||
|
{
|
||||||
|
if (m_currentTaskId > 0) {
|
||||||
|
emit subTaskFinished(m_currentTaskId, subTaskIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::onExecutorError(const QString& error)
|
||||||
|
{
|
||||||
|
emitError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::onExecutorMotorPositionUpdated(double x, double y)
|
||||||
|
{
|
||||||
|
emit motorPositionUpdated(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::executeTask(TimedTask& task)
|
||||||
|
{
|
||||||
|
if (!m_motorControl) {
|
||||||
|
emitError("Motor control not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "TaskScheduler: Executing task" << task.id;
|
||||||
|
|
||||||
|
updateTaskStatus(task.id, TaskStatus::Running);
|
||||||
|
m_currentTaskId = task.id;
|
||||||
|
|
||||||
|
emit taskStarted(task.id);
|
||||||
|
|
||||||
|
// 创建任务执行器
|
||||||
|
m_currentExecutor = new TaskExecutor(m_motorControl, this);
|
||||||
|
|
||||||
|
// 连接信号
|
||||||
|
connect(m_currentExecutor, &TaskExecutor::finished,
|
||||||
|
this, &TaskScheduler::onTaskFinished);
|
||||||
|
connect(m_currentExecutor, &TaskExecutor::subTaskStarted,
|
||||||
|
this, &TaskScheduler::onSubTaskStarted);
|
||||||
|
connect(m_currentExecutor, &TaskExecutor::subTaskFinished,
|
||||||
|
this, &TaskScheduler::onSubTaskFinished);
|
||||||
|
connect(m_currentExecutor, &TaskExecutor::errorOccurred,
|
||||||
|
this, &TaskScheduler::onExecutorError);
|
||||||
|
connect(m_currentExecutor, &TaskExecutor::motorPositionUpdated,
|
||||||
|
this, &TaskScheduler::onExecutorMotorPositionUpdated);
|
||||||
|
|
||||||
|
// 开始执行
|
||||||
|
m_currentExecutor->execute(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::updateTaskStatus(int taskId, TaskStatus status)
|
||||||
|
{
|
||||||
|
for (auto& task : m_tasks) {
|
||||||
|
if (task.id == taskId) {
|
||||||
|
task.status = status;
|
||||||
|
if (status == TaskStatus::Running) {
|
||||||
|
task.startTime = QDateTime::currentDateTime();
|
||||||
|
} else if (status == TaskStatus::Finished) {
|
||||||
|
task.endTime = QDateTime::currentDateTime();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TaskScheduler::emitError(const QString& error)
|
||||||
|
{
|
||||||
|
qWarning() << "TaskScheduler: Error:" << error;
|
||||||
|
emit errorOccurred(error);
|
||||||
|
}
|
||||||
|
|||||||
@ -4,6 +4,10 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "TwoMotorControl.h"
|
||||||
|
#include "CaptureCoordinator.h"
|
||||||
|
|
||||||
// ==================== 枚举定义 ====================
|
// ==================== 枚举定义 ====================
|
||||||
|
|
||||||
@ -102,3 +106,111 @@ private:
|
|||||||
static QString subTaskTypeToString(SubTaskType type);
|
static QString subTaskTypeToString(SubTaskType type);
|
||||||
static SubTaskType stringToSubTaskType(const QString& str);
|
static SubTaskType stringToSubTaskType(const QString& str);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ==================== 前向声明 ====================
|
||||||
|
|
||||||
|
class TwoMotorControl;
|
||||||
|
|
||||||
|
// ==================== 任务执行器 ====================
|
||||||
|
|
||||||
|
class TaskExecutor : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TaskExecutor(TwoMotorControl* motorControl, QObject* parent = nullptr);
|
||||||
|
~TaskExecutor();
|
||||||
|
|
||||||
|
// 执行任务
|
||||||
|
void execute(const TimedTask& task);
|
||||||
|
|
||||||
|
// 获取当前执行的子任务索引
|
||||||
|
int currentSubTaskIndex() const { return m_currentSubTaskIndex; }
|
||||||
|
|
||||||
|
// 获取正在执行的任务
|
||||||
|
const TimedTask& currentTask() const { return m_task; }
|
||||||
|
|
||||||
|
// 是否正在执行
|
||||||
|
bool isRunning() const { return m_isRunning; }
|
||||||
|
|
||||||
|
// 停止执行
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished(bool success); // 任务完成
|
||||||
|
void subTaskStarted(int subTaskIndex, SubTaskType type); // 子任务开始
|
||||||
|
void subTaskFinished(int subTaskIndex, SubTaskType type, bool success); // 子任务完成
|
||||||
|
void motorPositionUpdated(double x, double y); // 马达位置更新
|
||||||
|
void errorOccurred(const QString& error); // 错误发生
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onSequenceComplete(int status);
|
||||||
|
void onMotorLocationUpdate(std::vector<double> loc);
|
||||||
|
void onError(const QString& error);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void executeNextSubTask();
|
||||||
|
void loadPathLinesFromFile(const QString& filePath);
|
||||||
|
|
||||||
|
TwoMotorControl* m_motorControl;
|
||||||
|
TimedTask m_task;
|
||||||
|
int m_currentSubTaskIndex;
|
||||||
|
bool m_isRunning;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ==================== 任务调度器 ====================
|
||||||
|
|
||||||
|
class TaskScheduler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TaskScheduler(QObject* parent = nullptr);
|
||||||
|
~TaskScheduler();
|
||||||
|
|
||||||
|
// 设置马达控制器
|
||||||
|
void setMotorControl(TwoMotorControl* motorControl);
|
||||||
|
|
||||||
|
// 加载任务列表
|
||||||
|
void loadTasks(const QVector<TimedTask>& tasks);
|
||||||
|
|
||||||
|
// 获取任务列表
|
||||||
|
QVector<TimedTask> tasks() const { return m_tasks; }
|
||||||
|
|
||||||
|
// 开始调度
|
||||||
|
void start();
|
||||||
|
|
||||||
|
// 停止调度
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
// 是否正在运行
|
||||||
|
bool isRunning() const { return m_timer != nullptr && m_timer->isActive(); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void taskStarted(int taskId); // 任务开始
|
||||||
|
void taskFinished(int taskId, bool success); // 任务完成
|
||||||
|
void subTaskStarted(int taskId, int subTaskIndex); // 子任务开始
|
||||||
|
void subTaskFinished(int taskId, int subTaskIndex); // 子任务完成
|
||||||
|
void motorPositionUpdated(double x, double y); // 马达位置更新
|
||||||
|
void errorOccurred(const QString& error); // 错误发生
|
||||||
|
void schedulerStateChanged(bool running); // 调度器状态变化
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void checkTasks(); // 检查任务是否该启动
|
||||||
|
void onTaskFinished(bool success);
|
||||||
|
void onSubTaskStarted(int subTaskIndex, SubTaskType type);
|
||||||
|
void onSubTaskFinished(int subTaskIndex, SubTaskType type, bool success);
|
||||||
|
void onExecutorError(const QString& error);
|
||||||
|
void onExecutorMotorPositionUpdated(double x, double y);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void executeTask(TimedTask& task);
|
||||||
|
void updateTaskStatus(int taskId, TaskStatus status);
|
||||||
|
void emitError(const QString& error);
|
||||||
|
|
||||||
|
QTimer* m_timer;
|
||||||
|
QVector<TimedTask> m_tasks;
|
||||||
|
TwoMotorControl* m_motorControl;
|
||||||
|
TaskExecutor* m_currentExecutor;
|
||||||
|
int m_currentTaskId;
|
||||||
|
};
|
||||||
|
|||||||
@ -6,314 +6,273 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>970</width>
|
<width>1160</width>
|
||||||
<height>456</height>
|
<height>576</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Dialog</string>
|
<string>Dialog</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QTreeWidget" name="treeWidget">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<property name="geometry">
|
<item row="0" column="0" colspan="3">
|
||||||
<rect>
|
<widget class="QWidget" name="widget" native="true">
|
||||||
<x>9</x>
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<y>9</y>
|
<item row="0" column="0">
|
||||||
<width>491</width>
|
<widget class="QTreeWidget" name="treeWidget">
|
||||||
<height>281</height>
|
<property name="allColumnsShowFocus">
|
||||||
</rect>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="allColumnsShowFocus">
|
<attribute name="headerVisible">
|
||||||
<bool>false</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</attribute>
|
||||||
<attribute name="headerVisible">
|
<column>
|
||||||
<bool>true</bool>
|
<property name="text">
|
||||||
</attribute>
|
<string>任务</string>
|
||||||
<column>
|
</property>
|
||||||
<property name="text">
|
</column>
|
||||||
<string>任务</string>
|
<column>
|
||||||
</property>
|
<property name="text">
|
||||||
</column>
|
<string>计划时间</string>
|
||||||
<column>
|
</property>
|
||||||
<property name="text">
|
</column>
|
||||||
<string>计划时间</string>
|
<column>
|
||||||
</property>
|
<property name="text">
|
||||||
</column>
|
<string>开始时间</string>
|
||||||
<column>
|
</property>
|
||||||
<property name="text">
|
</column>
|
||||||
<string>开始时间</string>
|
<column>
|
||||||
</property>
|
<property name="text">
|
||||||
</column>
|
<string>结束时间</string>
|
||||||
<column>
|
</property>
|
||||||
<property name="text">
|
</column>
|
||||||
<string>结束时间</string>
|
<column>
|
||||||
</property>
|
<property name="text">
|
||||||
</column>
|
<string>耗时</string>
|
||||||
<column>
|
</property>
|
||||||
<property name="text">
|
</column>
|
||||||
<string>耗时</string>
|
<column>
|
||||||
</property>
|
<property name="text">
|
||||||
</column>
|
<string>状态</string>
|
||||||
<column>
|
</property>
|
||||||
<property name="text">
|
</column>
|
||||||
<string>状态</string>
|
<item>
|
||||||
</property>
|
<property name="text">
|
||||||
</column>
|
<string>1</string>
|
||||||
<item>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>1</string>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<item>
|
||||||
<string/>
|
<property name="text">
|
||||||
</property>
|
<string>a</string>
|
||||||
<item>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>a</string>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
</item>
|
||||||
<string/>
|
<item>
|
||||||
</property>
|
<property name="text">
|
||||||
</item>
|
<string>b</string>
|
||||||
<item>
|
</property>
|
||||||
<property name="text">
|
</item>
|
||||||
<string>b</string>
|
</item>
|
||||||
</property>
|
<item>
|
||||||
</item>
|
<property name="text">
|
||||||
|
<string>2</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>a</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>b</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>3</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>a</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>b</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>4</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>a</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>b</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>5</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>a</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>b</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QStackedWidget" name="stackedWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="page"/>
|
||||||
|
<widget class="QWidget" name="page_2"/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="1" column="0">
|
||||||
<property name="text">
|
<widget class="QPushButton" name="addToptask_btn">
|
||||||
<string>2</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>a</string>
|
<string>添加总计划任务</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</widget>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>b</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="2" column="0">
|
||||||
<property name="text">
|
<widget class="QPushButton" name="delToptask_btn">
|
||||||
<string>3</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>a</string>
|
<string>删除总计划任务</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</widget>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>b</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="3" column="0">
|
||||||
<property name="text">
|
<widget class="QPushButton" name="addSubtask_btn">
|
||||||
<string>4</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>a</string>
|
<string>添加子任务</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</widget>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>b</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="3" column="1">
|
||||||
<property name="text">
|
<widget class="QComboBox" name="comboBox"/>
|
||||||
<string>5</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>a</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>b</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
<item row="4" column="0">
|
||||||
<widget class="QPushButton" name="addToptask_btn">
|
<widget class="QPushButton" name="delSubtask_btn">
|
||||||
<property name="geometry">
|
<property name="text">
|
||||||
<rect>
|
<string>删除子任务</string>
|
||||||
<x>40</x>
|
</property>
|
||||||
<y>310</y>
|
</widget>
|
||||||
<width>101</width>
|
</item>
|
||||||
<height>23</height>
|
<item row="4" column="2">
|
||||||
</rect>
|
<widget class="QPushButton" name="run_btn">
|
||||||
</property>
|
<property name="text">
|
||||||
<property name="text">
|
<string>运行</string>
|
||||||
<string>添加总计划任务</string>
|
</property>
|
||||||
</property>
|
</widget>
|
||||||
</widget>
|
</item>
|
||||||
<widget class="QPushButton" name="addSubtask_btn">
|
</layout>
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>40</x>
|
|
||||||
<y>370</y>
|
|
||||||
<width>101</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>添加子任务</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QComboBox" name="comboBox">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>170</x>
|
|
||||||
<y>370</y>
|
|
||||||
<width>69</width>
|
|
||||||
<height>22</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QPushButton" name="delSubtask_btn">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>40</x>
|
|
||||||
<y>410</y>
|
|
||||||
<width>101</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>删除子任务</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QPushButton" name="delToptask_btn">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>40</x>
|
|
||||||
<y>340</y>
|
|
||||||
<width>101</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>删除总计划任务</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QStackedWidget" name="stackedWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>520</x>
|
|
||||||
<y>20</y>
|
|
||||||
<width>381</width>
|
|
||||||
<height>261</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="currentIndex">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="page"/>
|
|
||||||
<widget class="QWidget" name="page_2"/>
|
|
||||||
</widget>
|
|
||||||
<widget class="QPushButton" name="run_btn">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>850</x>
|
|
||||||
<y>420</y>
|
|
||||||
<width>101</width>
|
|
||||||
<height>23</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>运行</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|||||||
Reference in New Issue
Block a user